SB100 / GGn Seeding Group Highlighter

// ==UserScript==
// @namespace    https://openuserjs.org/users/SB100
// @name         GGn Seeding Group Highlighter
// @description  Highlights a torrent group on the torrents.php page if you are seeding at least one torrent in the group
// @updateURL    https://openuserjs.org/meta/SB100/GGn_Seeding_Group_Highlighter.meta.js
// @version      1.0.1
// @author       SB100
// @copyright    2021, SB100 (https://openuserjs.org/users/SB100)
// @license      MIT
// @include      https://gazellegames.net/torrents.php*
// @exclude      https://gazellegames.net/torrents.php*id=*
// ==/UserScript==

// ==OpenUserJS==
// @author SB100
// ==/OpenUserJS==

/* jshint esversion: 6 */

/**
 * =============================
 * ADVANCED OPTIONS
 * =============================
 */

// What color to highlight the group text if we have something seeding in the group
const SETTING_HIGHLIGHT_COLOR = '#d9e473';

/**
 * =============================
 * END ADVANCED OPTIONS
 * DO NOT MODIFY BELOW THIS LINE
 * =============================
 */

/**
 * Accepts a row and table, and highlights the row in that table if we're seeing something in the row's group
 */
function highlightGroupIfSeedingInChild(groupTr, tableElem) {
  // find the group id. If we can't, we can't do anything more
  const groupIdMatches = groupTr.className.match(/group_(\d+)/)
  const groupId = groupIdMatches ? groupIdMatches[1] : null;
  if (!groupId) {
    return;
  }

  // find if we're seeding something in the group
  const shouldHighlight = Array.from(tableElem.querySelectorAll(`.groupid_${groupId}`)).some(row => {
    return row.querySelector('[title="Seeding"]') !== null;
  });

  if (!shouldHighlight) {
    return;
  }

  // find the anchor link to highlight and change the title for
  const link = groupTr.querySelector('[title="View Torrent"]');
  if (!link) {
    return;
  }

  link.classList.add('sgh__seeding');
  link.title = 'View Torrent (Currently Seeding)'
}

/**
 * Creates the style which will highlight the group that we have items seeding in
 */
function createStyleTag() {
  const css = `.sgh__seeding {
        color: ${SETTING_HIGHLIGHT_COLOR};
    }`;

  const style = document.createElement('style');
  style.type = 'text/css';
  style.appendChild(document.createTextNode(css));

  document.head.appendChild(style);
}

(function () {
  'use strict';

  // check we have observers available to us
  if (!MutationObserver) return;

  // create our css styles
  createStyleTag();

  // observer config - only interested in tree modifications
  const config = {
    childList: true,
    subtree: true
  };

  // Check modified nodes and run the subtitle function if we find a valid match
  const callback = function (mutationsList, observer) {
    mutationsList.forEach(mutation => {
      if (mutation.target.matches('table.torrent_table.grouping') && mutation.addedNodes[0].matches('tr.group:not(.hidden)')) {
        highlightGroupIfSeedingInChild(mutation.addedNodes[0], mutation.target);
      }
    });
  }

  // create an observer instance with the callback
  const observer = new MutationObserver(callback);

  // Start observing the target node for mutations
  observer.observe(document, config);

  // and run for anything that was already on the page
  Array.from(document.querySelectorAll('tr.group:not(.hidden)')).forEach(groupTr =>
    highlightGroupIfSeedingInChild(groupTr, document.getElementById('torrent_table'))
  );
})();