webketje / Paywall Destroyer

// ==UserScript==
// @name         Paywall Destroyer
// @namespace    https://openuserjs.org/users/webketje
// @version      0.1
// @description  Client-side paywall remover. Uses a simple heuristic. Tested on washingtonpost.com, nytimes.com, and knack.be
// @author       webketje
// @license      LGPL-3.0-or-later
// @copyright    2021, webketje (https://openuserjs.org/users/webketje)
// @run-at       document-idle
// @icon         https://ps.w.org/simple-paywall/assets/icon-128x128.jpg
// @downloadURL  https://openuserjs.org/install/webketje/Paywall_Destroyer.min.user.js
// @updateURL    https://openuserjs.org/meta/webketje/Paywall_Destroyer.meta.js
// @supportURL   https://openuserjs.org/scripts/webketje/Soundcloud_Downloader_Clean/issue/new
// @include      *
// @grant        none
// @noframes
// ==/UserScript==

(function () {
  'use strict';

  var csspatch = 'overflow: auto !important; height: auto !important; position: static !important;';

  function patchTree(node) {
    node.style.cssText += csspatch;
    if (node.parentNode) {
      patchTree(node.parentNode);
    }
  }

  function findContentNodes() {
    var byTag = Array.prototype.slice.call(document.getElementsByTagName('article'));
    var byId = ['article', 'main-content', 'main'].map(function (keyword) {
      return document.querySelector('[id*="' + keyword + '"]');
    }).filter(function (element) {
      return !!element;
    });
    return byTag.concat(byId);
  }

  function paywalldestroyer() {
    var targets = [];
    document.body.style.cssText += csspatch;
    document.documentElement.style.cssText += csspatch;

    findContentNodes()
      .forEach(patchTree);

    if (document.querySelector('[id*="paywall"]')) targets = targets.concat([].slice.call(document.querySelectorAll('[id*="paywall"]')));
    if (document.querySelector('[id*="gateway"]')) targets = targets.concat([].slice.call(document.querySelectorAll('[id*="gateway"]')));

    targets.forEach(function (target) {
      if (target && target.parentNode)
        target.parentNode.removeChild(target);
    });
  }

  setInterval(paywalldestroyer, 1000);
})();