Greasy Fork

Rock Paper Shotgun [RPS] & Eurogamer embed fix

Enable embedded third party content on RPS & Eurogamer despite having rejected cookies

// ==UserScript==
// @name         Rock Paper Shotgun [RPS] & Eurogamer embed fix
// @version      10
// @description  Enable embedded third party content on RPS & Eurogamer despite having rejected cookies
// @author       Tim Smith
// @license      GPL-3.0 License
// @namespace    https://greasyfork.org/users/945293
// @match        *://www.rockpapershotgun.com/*
// @match        *://www.eurogamer.net/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=rockpapershotgun.com
// ==/UserScript==

(function() {

class EmbedFixer {
	sourcesByDataName = [
		['src', [
			['iframe', 'embed.acast.com'],
			['iframe', 'bandcamp.com'],
			['iframe', 'efmfeedback.com'],
			['iframe', 'docs.google.com'],
			['iframe', 'gfycat.com'],
			['iframe', 'giphy.com'],
			['iframe', 'libsyn.com'],
			['iframe', 'megaphone.fm'],
			['iframe', 'redditmedia.com'],
			['iframe', 'soundcloud.com'],
			['iframe', 'spotify.com'],
			['iframe', 'streamable.com'],
			['iframe', 'twitch.tv'],
			['iframe', 'youtube']
		]],
		['cookiesSrc', [
			['script', 'primis.tech']
		]]
	]
	scriptSources = [
		'apester.com',
		'instagram.com',
		'twitter.com'
	]
	mutationObserverOptions = {
		childList: true,
		subtree: true
	}

	constructor() {
		this.cachedDashStyles = new Map();
		this.selectors = this.sourcesByDataName.map(([dataName, sources]) => [dataName, sources.map(source => this.selector(dataName, ...source)).join()]);
		this.scriptSelector = this.scriptSources.map(domain => this.selector('src', 'script', domain)).join();
		this.addedScripts = new Set();

		const style = document.createElement('style');
		document.head.appendChild(style);
		style.sheet.insertRule('.embed_placeholder {display: none;}');
		this.enable(document.body);

		const liveblogContainer = document.body.querySelector('.liveblog');
		if (liveblogContainer !== null) {
			this.mutationObserver = new MutationObserver(mutationRecords => this.checkMutations(mutationRecords));
			this.mutationObserver.observe(liveblogContainer, this.mutationObserverOptions);
		}
	}

	selector(dataName, nodeName, domain) {
		return `${nodeName}[data-${this.dashStyle(dataName)}*="${domain}"]:not([src])`;
	}

	dashStyle(camelCase) {
		if (!this.cachedDashStyles.has(camelCase))
			this.cachedDashStyles.set(camelCase, camelCase.replaceAll(/[A-Z]/g, letter => `-${letter.toLowerCase()}`));
		return this.cachedDashStyles.get(camelCase);
	}

	enable(ancestor) {
		for (const [dataName, selector] of this.selectors)
			ancestor.querySelectorAll(selector).forEach(element => this.addSrc(element, dataName));
		ancestor.querySelectorAll(this.scriptSelector).forEach(script => this.addScript(script));
	}

	addSrc(element, dataName = 'src') {
		element.src = element.dataset[dataName];
		element.removeAttribute(`data-${this.dashStyle(dataName)}`);
	}

	addScript(inlineScript) {
		if (this.addedScripts.has(inlineScript.dataset.src)) return;
		const headScript = inlineScript.cloneNode();
		this.addSrc(headScript);
		document.head.appendChild(headScript);
		this.addedScripts.add(inlineScript.dataset.src)
	}

	checkMutations(mutationRecords) {
		for (const mutationRecord of mutationRecords)
			for (const addedNode of mutationRecord.addedNodes)
				if (addedNode.nodeType == Node.ELEMENT_NODE)
					this.enable(addedNode);
	}
}

const embedFixer = new EmbedFixer();

})();