Reject cookie banners

Automatically rejects cookies and legitimate interest

Od 21.12.2024.. Pogledajte najnovija verzija.

// ==UserScript==
// @name         Reject cookie banners
// @namespace    http://tampermonkey.net/
// @version      1.3.3.6
// @description  Automatically rejects cookies and legitimate interest
// @author       https://greasyfork.org/en/users/85040-dan-wl-danwl
// @license      MIT
// @match        *://*/*
// @run-at       document-start
// @grant        none
// ==/UserScript==

// MIT License

// Copyright(c) 2024 DanWL

// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// 	in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// 	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// 	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

(function() {
	const rejections = [
		{
			// reject consent and reject legitimate interest
			banner: 'body > .fc-consent-root',
			btn: 'button[aria-label^="Manage"] > p',
			btn_htmlMatch: /^Manage options$/,
			toggles: '.fc-preference-slider input[aria-label^="Consent"]:checked, .fc-preference-slider input[aria-label^="Legitimate interest"]:checked',
			confirm: 'button[aria-label^="Confirm"] p',
			confirm_htmlMatch: /^Confirm choices$/
		},
		{
			// only accept necessary cookies
			banner: 'body > #onetrust-consent-sdk',
			btn: '[aria-label="Cookie banner"] #onetrust-reject-all-handler'
		},
		{
			// click customize and reject all
			banner: 'body > .cmpwrapper',
			btn: 'div#cmpbox > div.cmpboxinner > div.cmpboxbtns > div.cmpmore > a.cmpmorelink.cmptxt_btn_custom',
			toggles: null,
			confirm: 'div#cmpbox > div.cmpboxinner > div.cmpboxbtnscustomchoices > a.cmpboxbtn.cmpboxbtnreject.cmpboxbtnrejectcustomchoices.cmptxt_btn_no'
		},
		{
			// more options, reject all, click legitimate interest then object all, save
			banner: 'body > .qc-cmp2-container',
			btn: '.qc-cmp2-summary-buttons > button[mode="secondary"][size="large"] > span',
			btn_htmlMatch: /^MORE OPTIONS$/,
			toggles: [
				{query: '.qc-cmp2-header-links > button[mode="link"][size="small"]', htmlMatch: /^REJECT ALL$/},
				{query: '.qc-cmp2-footer-links > button[mode="link"][size="small"]', htmlMatch: /^LEGITIMATE INTEREST$/},
				{query: '.qc-cmp2-header-links > button[mode="link"][size="small"]', htmlMatch: /^OBJECT ALL$/}
			],
			confirm: '.qc-cmp2-footer-links + .qc-cmp2-buttons-desktop button[mode="primary"][size="large"]',
			confirm_htmlMatch: /^SAVE & EXIT$/
		},
		{
			// LEARN MORE, Show Preferences, click all checked checkboxes, (save TODO)
			banner: 'body > div:has(div[data-tracking-opt-in-overlay])',
			btn: 'div[data-tracking-opt-in-learn-more]',
			btn_htmlMatch: /^LEARN MORE$/,
			toggles: [
				{query: 'div[class]', htmlMatch: /^\s*Show Preferences\s*<svg\s+/, queryAll: true},
				{query: 'input[id^="switch"][type="checkbox"]:checked + label[for^=switch]', htmlMatch: /^$/, queryAll: true},
			],
			DONT_CLOSE: true
		}
	];

	let dealtWithBanner = false;

	function sleep(ms) {
		// cookie banner not fully loaded when trying to select elements
		// so wait for a bit until it has

		return new Promise((resolve) => {
			setTimeout(() => resolve(), ms);
		})
	}

	function getBanner(cookieNotice) {
		return document.querySelector(cookieNotice.banner);
	}

	async function getBtn(cookieNotice) {
		const banner = getBanner(cookieNotice);

		if (cookieNotice.btn_htmlMatch) {
			const btns = (banner.shadowRoot || banner).querySelectorAll(cookieNotice.btn);

			for (const btn of btns) {
				if (btn.innerHTML.match(cookieNotice.btn_htmlMatch)) {
					return btn;
				}
			}
		}
		else {
			const btn = (banner.shadowRoot || banner).querySelector(cookieNotice.btn);

			if (btn) {
				return btn;
			}
		}

		// if made it down to here then btn does not exist, so wait and try again
		await sleep(10);
		return await getBtn(cookieNotice);
	}

	async function clickToggle(cookieNotice, toggleItemNo) {
		if (toggleItemNo >= cookieNotice.toggles.length) {
			return;
		}

		const toggleItem = cookieNotice.toggles[toggleItemNo];
		let banner = getBanner(cookieNotice);

		if (toggleItem.htmlMatch) {
			if (toggleItem.queryAll) {
				// forcefully wait for the cookie notice to load
				await sleep(2000);
				banner = getBanner(cookieNotice);
			}

			const toggles = (banner.shadowRoot || banner).querySelectorAll(toggleItem.query);

			if (!toggles.length) {
				const prev = toggleItemNo > 0 ? 1 : 0;

				return await clickToggle(cookieNotice, toggleItemNo - prev);
			}

			for (const toggle of toggles) {
				if (toggle.innerHTML.match(toggleItem.htmlMatch)) {
					toggle.click();

					if (!toggleItem.queryAll) {
						break;
					}
				}
			}

			return await clickToggle(cookieNotice, toggleItemNo + 1);
		}
		else {
			const toggle = (banner.shadowRoot || banner).querySelector(toggleItem.query);

			if (toggle) {
				toggle.click();
				return await clickToggle(cookieNotice, toggleItemNo + 1);
			}
		}

		// if made it down to here then toggle does not exist, so wait then try again
		await sleep(10);
		await clickToggle(cookieNotice, toggleItemNo);
	}

	async function getConfirmBtn(cookieNotice) {
		const banner = getBanner(cookieNotice);

		if (cookieNotice.confirm_htmlMatch) {
			const btns = (banner.shadowRoot || banner).querySelectorAll(cookieNotice.confirm);

			for (const btn of btns) {
				if (btn.innerHTML.match(cookieNotice.confirm_htmlMatch)) {
					return btn;
				}
			}
		}
		else {
			const btn = (banner.shadowRoot || banner).querySelector(cookieNotice.confirm);

			if (btn) {
				return btn;
			}
		}

		if (typeof cookieNotice.toggles === 'string') {
			// confirm button not loaded to go back and make sure that all toggles have been disabled
			clickToggle(cookieNotice, 0);
		}

		// if made it down to here then it does not exist, so wait then try again
		await sleep(10);
		return await getConfirmBtn(cookieNotice);
	}

	async function tryRejecting(cookieNotice) {
		if (!getBanner(cookieNotice)) {
			return;
		}

		const btn = await getBtn(cookieNotice);

		const togglesIsString = typeof cookieNotice.toggles == 'string';
		const togglesIsArray = Array.isArray(cookieNotice.toggles);

		if (cookieNotice.toggles === null || togglesIsString || togglesIsArray) {
			btn.click();

			if (togglesIsString) {
				// if toggles arent loaded by the time the confirm button exists, toggles will be disabled

				const banner = getBanner(cookieNotice);

				(banner.shadowRoot || banner).querySelectorAll(cookieNotice.toggles).forEach(function(toggle) {
					toggle.click();
				});
			}
			else if (togglesIsArray) {
				// clicks all toggles in the exact order they appear in
				// for buttons like 'reject all' or 'object all' when they are actually provided

				await clickToggle(cookieNotice, 0);
			}

			if (cookieNotice.DONT_CLOSE) {
				return;
			}

			(await getConfirmBtn(cookieNotice)).click();
		}
		else {
			// some pages would constantly reload because of automatically clearing and rejecting cookies
			// so check if cookies are stored before trying to reject them

			if (document.cookie) {
				// reject cookies
				btn.click();
			}

			if (cookieNotice.DONT_CLOSE) {
				return;
			}

			// make sure there is no persistent banner
			getBanner(cookieNotice).outerHTML = '';
		}

		dealtWithBanner = true;
	}

	function rejectAll() {
		for (let i = 0; i < rejections.length; i++) {
			tryRejecting(rejections[i], true);
		}

		if (dealtWithBanner) {
			return;
		}

		// cookie banner may not have been created yet, try again
		setTimeout(rejectAll, 200);
	}

	rejectAll();
})();