ao3 savior

Hide specified works on AO3

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name          ao3 savior
// @description   Hide specified works on AO3
// @namespace     ao3
// @include       http*://archiveofourown.org/*
// @grant         none
// @version       1.16
// ==/UserScript==



(function () {
  'use strict';

  var STYLE = '\n  html body .ao3-savior-hidden.ao3-savior-hidden {\n    display: none;\n  }\n  \n  .ao3-savior-cut {\n    display: none;\n  }\n  \n  .ao3-savior-cut::after {\n    clear: both;\n    content: \'\';\n    display: block;\n  }\n  \n  .ao3-savior-reason {\n    margin-left: 5px;\n  }\n  \n  .ao3-savior-hide-reasons .ao3-savior-reason {\n    display: none;\n  }\n  \n  .ao3-savior-unhide .ao3-savior-cut {\n    display: block;\n  }\n  \n  .ao3-savior-fold {\n    align-items: center;\n    display: flex;\n    justify-content: flex-start;\n  }\n  \n  .ao3-savior-unhide .ao3-savior-fold {\n    border-bottom: 1px dashed;\n    margin-bottom: 15px;\n    padding-bottom: 5px;\n  }\n  \n  button.ao3-savior-toggle {\n    margin-left: auto;\n  }\n';

  function addStyle() {
    var style = document.createElement('style');
    style.innerHTML = STYLE;
    style.className = 'ao3-savior';

    document.head.appendChild(style);
  }

  var CSS_NAMESPACE = 'ao3-savior';

  var getCut = function getCut(work) {
    var cut = document.createElement('div');

    cut.className = CSS_NAMESPACE + '-cut';
    Array.from(work.childNodes).forEach(function (child) {
      return cut.appendChild(child);
    });

    return cut;
  };

  var getFold = function getFold(reason) {
    var fold = document.createElement('div');
    var note = document.createElement('span');

    fold.className = CSS_NAMESPACE + '-fold';
    note.className = CSS_NAMESPACE + '-note';

    note.innerHTML = 'This work is hidden!';

    fold.appendChild(note);
    fold.append(' ');
    fold.appendChild(getReasonSpan(reason));
    fold.appendChild(getToggleButton());

    return fold;
  };

  var getToggleButton = function getToggleButton() {
    var button = document.createElement('button');
    var unhideClassFragment = ' ' + CSS_NAMESPACE + '-unhide';

    button.innerHTML = 'Unhide';
    button.className = CSS_NAMESPACE + '-toggle';

    button.addEventListener('click', function (event) {
      var work = event.target.closest('.' + CSS_NAMESPACE + '-work');

      if (work.className.indexOf(unhideClassFragment) !== -1) {
        work.className = work.className.replace(unhideClassFragment, '');
        work.querySelector('.' + CSS_NAMESPACE + '-note').innerHTML = 'This work is hidden.';
        event.target.innerHTML = 'Unhide';
      } else {
        work.className += unhideClassFragment;
        work.querySelector('.' + CSS_NAMESPACE + '-note').innerHTML = 'ℹ️ This work was hidden.';
        event.target.innerHTML = 'Hide';
      }
    });

    return button;
  };

  var getReasonSpan = function getReasonSpan(reason) {
    var span = document.createElement('span');
    var tag = reason.tag,
        author = reason.author,
        title = reason.title,
        summary = reason.summary;

    var text = void 0;

    if (tag) {
      text = 'tags include <strong>' + tag + '</strong>';
    } else if (author) {
      text = 'authors include <strong>' + author + '</strong>';
    } else if (title) {
      text = 'title is <strong>' + title + '</strong>';
    } else if (summary) {
      text = 'summary includes <strong>' + summary + '</strong>';
    }

    if (text) {
      span.innerHTML = '(Reason: ' + text + '.)';
    }

    span.className = CSS_NAMESPACE + '-reason';

    return span;
  };

  function blockWork(work, reason, config) {
    if (!reason) return;

    var showReasons = config.showReasons,
        showPlaceholders = config.showPlaceholders;


    if (showPlaceholders) {
      var fold = getFold(reason);
      var cut = getCut(work);

      work.className += ' ' + CSS_NAMESPACE + '-work';
      work.innerHTML = '';
      work.appendChild(fold);
      work.appendChild(cut);

      if (!showReasons) {
        work.className += ' ' + CSS_NAMESPACE + '-hide-reasons';
      }
    } else {
      work.className += ' ' + CSS_NAMESPACE + '-hidden';
    }
  }

  function matchTermsWithWildCard(term0, pattern0) {
    var term = term0.toLowerCase();
    var pattern = pattern0.toLowerCase();

    if (term === pattern) return true;
    if (pattern.indexOf('*') === -1) return false;

    var lastMatchedIndex = pattern.split('*').filter(Boolean).reduce(function (prevIndex, chunk) {
      var matchedIndex = term.indexOf(chunk);
      return prevIndex >= 0 && prevIndex <= matchedIndex ? matchedIndex : -1;
    }, 0);

    return lastMatchedIndex >= 0;
  }

  var isItemWhitelisted = function isItemWhitelisted(items, whitelist) {
    var whitelistLookup = whitelist.reduce(function (lookup, item) {
      lookup[item] = true;
      return lookup;
    }, {});

    return items.some(function (item) {
      return !!whitelistLookup[item];
    });
  };

  var findBlacklistedItem = function findBlacklistedItem(list, blacklist, comparator) {
    var matchingEntry = void 0;

    list.some(function (item) {
      blacklist.some(function (entry) {
        var matched = comparator(item, entry);

        if (matched) matchingEntry = entry;

        return matched;
      });
    });

    return matchingEntry;
  };

  var equals = function equals(a, b) {
    return a === b;
  };
  var contains = function contains(a, b) {
    return a.indexOf(b) !== -1;
  };

  function getBlockReason(_ref, _ref2) {
    var _ref$authors = _ref.authors,
        authors = _ref$authors === undefined ? [] : _ref$authors,
        _ref$title = _ref.title,
        title = _ref$title === undefined ? '' : _ref$title,
        _ref$tags = _ref.tags,
        tags = _ref$tags === undefined ? [] : _ref$tags,
        _ref$summary = _ref.summary,
        summary = _ref$summary === undefined ? '' : _ref$summary;
    var _ref2$authorBlacklist = _ref2.authorBlacklist,
        authorBlacklist = _ref2$authorBlacklist === undefined ? [] : _ref2$authorBlacklist,
        _ref2$titleBlacklist = _ref2.titleBlacklist,
        titleBlacklist = _ref2$titleBlacklist === undefined ? [] : _ref2$titleBlacklist,
        _ref2$tagBlacklist = _ref2.tagBlacklist,
        tagBlacklist = _ref2$tagBlacklist === undefined ? [] : _ref2$tagBlacklist,
        _ref2$authorWhitelist = _ref2.authorWhitelist,
        authorWhitelist = _ref2$authorWhitelist === undefined ? [] : _ref2$authorWhitelist,
        _ref2$tagWhitelist = _ref2.tagWhitelist,
        tagWhitelist = _ref2$tagWhitelist === undefined ? [] : _ref2$tagWhitelist,
        _ref2$summaryBlacklis = _ref2.summaryBlacklist,
        summaryBlacklist = _ref2$summaryBlacklis === undefined ? [] : _ref2$summaryBlacklis;


    if (isItemWhitelisted(tags, tagWhitelist)) {
      return null;
    }

    if (isItemWhitelisted(authors, authorWhitelist)) {
      return null;
    }

    var blockedTag = findBlacklistedItem(tags, tagBlacklist, matchTermsWithWildCard);
    if (blockedTag) {
      return { tag: blockedTag };
    }

    var author = findBlacklistedItem(authors, authorBlacklist, equals);
    if (author) {
      return { author: author };
    }

    var blockedTitle = findBlacklistedItem([title], titleBlacklist, matchTermsWithWildCard);
    if (blockedTitle) {
      return { title: blockedTitle };
    }

    var summaryTerm = findBlacklistedItem([summary], summaryBlacklist, contains);
    if (summaryTerm) {
      return { summary: summaryTerm };
    }

    return null;
  }

  function isDebug(location) {
    return location.hostname === 'localhost' || /\ba3sv-debug\b/.test(location.search);
  }

  var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

  var getText = function getText(element) {
    return element.textContent.replace(/^\s*|\s*$/g, '');
  };
  var selectTextsIn = function selectTextsIn(root, selector) {
    return Array.from(root.querySelectorAll(selector)).map(getText);
  };

  function selectFromWork(container) {
    return _extends({}, selectFromBlurb(container), {
      title: selectTextsIn(container, '.title')[0],
      summary: selectTextsIn(container, '.summary .userstuff')[0]
    });
  }

  function selectFromBlurb(blurb) {
    return {
      authors: selectTextsIn(blurb, 'a[rel=author]'),
      tags: [].concat(selectTextsIn(blurb, 'a.tag'), selectTextsIn(blurb, '.required-tags .text')),
      title: selectTextsIn(blurb, '.header .heading a:first-child')[0],
      summary: selectTextsIn(blurb, 'blockquote.summary')[0]
    };
  }

  setTimeout(function () {
    var debugMode = isDebug(window.location);
    var config = window.ao3SaviorConfig;
    var workContainer = document.querySelector('#main.works-show') || document.querySelector('#main.chapters-show');
    var blocked = 0;
    var total = 0;

    if (debugMode) {
      console.groupCollapsed('AO3 SAVIOR');

      if (!config) {
        console.warn('Exiting due to missing config.');
        return;
      }
    }

    addStyle();

    Array.from(document.querySelectorAll('li.blurb')).forEach(function (blurb) {
      var blockables = selectFromBlurb(blurb);
      var reason = getBlockReason(blockables, config);

      total++;

      if (reason) {
        blockWork(blurb, reason, config);
        blocked++;

        if (debugMode) {
          console.groupCollapsed('- blocked ' + blurb.id);
          console.log(blurb, reason);
          console.groupEnd();
        }
      } else if (debugMode) {
        console.groupCollapsed('  skipped ' + blurb.id);
        console.log(blurb);
        console.groupEnd();
      }
    });

    if (config.alertOnVisit && workContainer && document.referrer.indexOf('//archiveofourown.org') === -1) {

      var blockables = selectFromWork(workContainer);
      var reason = getBlockReason(blockables, config);

      if (reason) {
        blocked++;
        blockWork(workContainer, reason, config);
      }
    }

    if (debugMode) {
      console.log('Blocked ' + blocked + ' out of ' + total + ' works');
      console.groupEnd();
    }
  }, 10);

}());