Denocle / DN.se remove paywall

// ==UserScript==
// @name            DN.se remove paywall
// @namespace       dn-remove-paywall
// @description     Removes the annoying free articles per week limit
// @icon            https://raw.githubusercontent.com/Denocle/DN.se-paywall-remover/master/assets/icon48.png
// @icon64          https://raw.githubusercontent.com/Denocle/DN.se-paywall-remover/master/assets/icon64.png
// @include         *dn.se*
// @grant           none
// @version         0.7.2
// @license         GPL-3.0+; http://www.gnu.org/licenses/gpl-3.0.txt
// @updateURL       https://openuserjs.org/meta/Denocle/DN.se_remove_paywall.meta.js
// @downloadURL     https://openuserjs.org/src/scripts/Denocle/DN.se_remove_paywall.user.js
// ==/UserScript==

const elBody = document.body;
const intMaxTries = 3;
const objObserverConfig = {
	attributes: true,
	childList: true,
	characterData: true,
	subtree: true
};

let boolArticleBodyPaywallRemoved = false;
let boolPremiumContentPaywallRemoved = false;
let boolGenericPaywallRemoved = false;
let boolPopupPaywallRemoved = false;

// Stolen from: http://greasemonkey.win-start.de/patterns/add-css.html
function addGlobalStyle(css) {

	var elHead;
	var elStyle;

	elHead = document.getElementsByTagName('head')[0];

	if (!elHead) {
		return;
	}

	elStyle = document.createElement('style');
	elStyle.type = 'text/css';
	elStyle.innerHTML = css;

	elHead.appendChild(elStyle);

}

// Run these at once, and only one time each is necessary.
// These CSS styles will "un-hide" the lead paragraph of articles.
addGlobalStyle('.article__body--mask .article__lead { max-height: 1000px !important; }');
addGlobalStyle('.article__body--mask .article__lead:after { display: none; }');
addGlobalStyle('.article__body--mask .article__lead { overflow: inherit; max-height: inherit; position: inherit; }');

/**
 * removeArticleBodyPaywall
 *
 * This function will look for and remove elements
 * that are blocking the article body.
 *
 * @return {void}
 */
function removeArticleBodyPaywall() {

	let arrPaywallContainers = document.getElementsByClassName('paywall--active');

	// If we found the container we know that their script for hiding the article has executed
	if (typeof arrPaywallContainers == 'object' && arrPaywallContainers !== null && arrPaywallContainers.length > 0) {

		let elPaywallContainer = arrPaywallContainers[0];
		// Remove the container
		elPaywallContainer.remove();

		let arrPaywallMask = document.getElementsByClassName('paywall-mask');
		if (arrPaywallMask.length > 0) {
			// Remove the mask
			arrPaywallMask[0].remove();
		}

		let arrPaywallContent = document.getElementsByClassName('paywall-content');
		if (arrPaywallContent.length > 0) {

			// Change the CSS so that the article becomes visible
			arrPaywallContent[0].style.height = 'auto';
			arrPaywallContent[0].style.overflow = 'visible';
		}

		boolArticleBodyPaywallRemoved = true;
	}

}

/**
 * removePremiumContentPaywall
 *
 * This function looks removes the CSS styling of
 * "display: none;" on article bodys.
 *
 * @return {void}
 */
function removePremiumContentPaywall() {

	let arrPremiumContent = document.getElementsByClassName('article__premium-content');

	if (arrPremiumContent.length > 0) {
		for (let i = 0; i < arrPremiumContent.length; i++) {
			arrPremiumContent[i].style.display = 'block';
			boolPremiumContentPaywallRemoved = true;
		}
	}

}

/**
 * removeGenericPaywall
 *
 * This function removes any element with
 * the class of "paywall".
 *
 * @return {void}
 */
function removeGenericPaywall() {

	let arrPayWalls = document.getElementsByClassName('paywall');

	if (arrPayWalls.length > 0) {
		for (let i = 0; i < arrPayWalls.length; i++) {
			arrPayWalls[i].remove();
			boolGenericPaywallRemoved = true;
		}
	}

}

/**
 * removePopupPaywall
 *
 * This function removes the modal/popup that
 * appears a while after an article loads.
 *
 * @return {void}
 */
function removePopupPaywall() {

	var elPayWallOverlay = document.getElementById('pwOverlay');

	if (typeof elPayWallOverlay == 'object' && elPayWallOverlay !== null) {
		elPayWallOverlay.remove();
		console.log('Removed popup');
		boolPopupPaywallRemoved = true;
	}

}

// Setup an generic observer for all DOM change events
const objBodyObserver = new MutationObserver(arrMutations => {

	if (!boolArticleBodyPaywallRemoved) {
		removeArticleBodyPaywall();
	}

	if (!boolPremiumContentPaywallRemoved) {
		removePremiumContentPaywall();
	}

	if (!boolGenericPaywallRemoved) {
		removeGenericPaywall();
	}

	if (!boolPopupPaywallRemoved) {
		removePopupPaywall();
	}

});

// Attach the observer to the body element
objBodyObserver.observe(elBody, objObserverConfig);