<commit_before>/* global chrome, sources, util */

var MAX_WATCHED = 150; // Max watched videos to keep in storage.
var MAX_KNOWN = 200;   // Max videos in memory to "know" about, to notify.
var MAX_VIDEOS = 50;   // Max videos to display for each group.
var QUEUE_WAIT = 2500; // How long to wait to play queued up videos.

var options = {
  sources: { youtube: true, twitch: false },
  interval: 15,
  use_same_tab: true,
  ignore: [],
  show_ignored_tab: false,
  show_notifications: false,
  play_sound: '',
  show_watched: false,
  show_ungrouped: false,
  merge: [],
};


var allVideos;
var watchedVideos;
var knownVideos = new util.sizedMap(MAX_KNOWN);
var ignoredVideos;
var ignoreRules = [];
var groups = [];
var queueTabs = {};
var queueUrlMap = {};

function checkForUpdates() {
  var keys = Object.keys(sources);
  var totalCalls = 0;
  var callsDone = 0;
  var results = [];

  keys.forEach(function(source) {
    if (!options.sources[source]) { return; }
    totalCalls++;
    sources[source](function(items) {
      results = results.concat(items);
      if (++callsDone === totalCalls) {
        allVideos = results;
        allVideos.sort(function(a, b) { return b.timestamp - a.timestamp; });
        updateVideos();
      }
    });
  });
}

function mergeMatch(source, username, video) {
  return video.source === source && video.user.name === username;
}

function updateVideos() {
  ignoredVideos = [];
  var results = allVideos.slice();

  // See if any videos can be merged.
  options.merge.forEach(function(rule) {
    results
      .filter(mergeMatch.bind(null, rule.source1, rule.username1))
      .forEach(function(video1) {
        if (video1.otherSource) { return; }
        for (var i = results.length - 1; i >= 0; i--) {
          var video2 = results[i];
          if (!mergeMatch(rule.source2, rule.username2, video2)) { continue; }
          if (util.isSameVideo(video1, video2)) {
            results.splice(i, 1);
            for (var key in video2) {
              if (!video1[key]) {
                video1[key] = video2[key];
              }
            }
            video1.otherSource = { source: video2.source, url: video2.url };
          }
        }
      });
  });

  results = results
    .filter(function(video) {
      if (watchedVideos.has(video.url)) {
        if (options.show_watched) {
          video.watched = true;
        } else {
          return false;
        }
      }
      var ignoreIt = matchRules(ignoreRules, video);
      if (ignoreIt) { ignoredVideos.push(video); }
      return !ignoreIt;
    });<commit_msg>share watched status across merged videos<commit_after>/* global chrome, sources, util */

var MAX_WATCHED = 150; // Max watched videos to keep in storage.
var MAX_KNOWN = 200;   // Max videos in memory to "know" about, to notify.
var MAX_VIDEOS = 50;   // Max videos to display for each group.
var QUEUE_WAIT = 2500; // How long to wait to play queued up videos.

var options = {
  sources: { youtube: true, twitch: false },
  interval: 15,
  use_same_tab: true,
  ignore: [],
  show_ignored_tab: false,
  show_notifications: false,
  play_sound: '',
  show_watched: false,
  show_ungrouped: false,
  merge: [],
};


var allVideos;
var watchedVideos;
var knownVideos = new util.sizedMap(MAX_KNOWN);
var ignoredVideos;
var ignoreRules = [];
var groups = [];
var queueTabs = {};
var queueUrlMap = {};

function checkForUpdates() {
  var keys = Object.keys(sources);
  var totalCalls = 0;
  var callsDone = 0;
  var results = [];

  keys.forEach(function(source) {
    if (!options.sources[source]) { return; }
    totalCalls++;
    sources[source](function(items) {
      results = results.concat(items);
      if (++callsDone === totalCalls) {
        allVideos = results;
        allVideos.sort(function(a, b) { return b.timestamp - a.timestamp; });
        updateVideos();
      }
    });
  });
}

function mergeMatch(source, username, video) {
  return video.source === source && video.user.name === username;
}

function updateVideos() {
  ignoredVideos = [];

  var results = allVideos
    .filter(function(video) {
      delete video.otherSource;
      if (watchedVideos.has(video.url)) {
        if (options.show_watched) {
          video.watched = true;
        } else {
          return false;
        }
      }
      var ignoreIt = matchRules(ignoreRules, video);
      if (ignoreIt) { ignoredVideos.push(video); }
      return !ignoreIt;
    });

  // See if any videos can be merged.
  options.merge.forEach(function(rule) {
    results
      .filter(mergeMatch.bind(null, rule.source1, rule.username1))
      .forEach(function(video1) {
        if (video1.otherSource) { return; }
        for (var i = results.length - 1; i >= 0; i--) {
          var video2 = results[i];
          if (!mergeMatch(rule.source2, rule.username2, video2)) { continue; }
          if (util.isSameVideo(video1, video2)) {
            results.splice(i, 1);

            // Merge everything from other source to preferred source.
            // If one is watched, they both will be.
            for (var key in video2) {
              if (!video1[key]) { video1[key] = video2[key]; }
            }
            video1.otherSource = { source: video2.source, url: video2.url };
          }
        }
      });
  });
{'fraction_non_alphanumeric': 0.1321969696969697, 'fraction_numerical': 0.013636363636363636, 'mean_word_length': 2.5300802139037435, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1745605', 'n_tokens_mistral': 1734, 'n_tokens_neox': 1653, 'n_words': 437}