From 143c5d2a34e99d3f01d13e71384a1fd55907d6d6 Mon Sep 17 00:00:00 2001
From: Hadi <112569860+anotherhadi@users.noreply.github.com>
Date: Sat, 25 Apr 2026 14:56:21 +0200
Subject: [PATCH] Edit qutebrowser userscripts & overlay
Signed-off-by: Hadi <112569860+anotherhadi@users.noreply.github.com>
---
flake.nix | 15 +-
.../greasemonkey/dont-track-me-google.user.js | 826 ------------
.../i-dont-care-about-cookies.user.js | 984 --------------
.../return-youtube-dislike.user.js | 704 ----------
.../greasemonkey/sponsorblock-lite.user.js | 1146 -----------------
.../greasemonkey/startpage-no-ads.user.js | 18 -
.../tracking-token-stripper.user.js | 191 ---
home/programs/qutebrowser/userscripts.nix | 78 +-
8 files changed, 73 insertions(+), 3889 deletions(-)
delete mode 100644 home/programs/qutebrowser/greasemonkey/dont-track-me-google.user.js
delete mode 100644 home/programs/qutebrowser/greasemonkey/i-dont-care-about-cookies.user.js
delete mode 100644 home/programs/qutebrowser/greasemonkey/return-youtube-dislike.user.js
delete mode 100644 home/programs/qutebrowser/greasemonkey/sponsorblock-lite.user.js
delete mode 100644 home/programs/qutebrowser/greasemonkey/startpage-no-ads.user.js
delete mode 100644 home/programs/qutebrowser/greasemonkey/tracking-token-stripper.user.js
diff --git a/flake.nix b/flake.nix
index 66eb94e..9cc414a 100644
--- a/flake.nix
+++ b/flake.nix
@@ -52,7 +52,20 @@
nixpkgs.lib.nixosSystem {
modules = [
{
- nixpkgs.overlays = [];
+ nixpkgs.overlays = [
+ (final: prev: {
+ # FIXME: Workaround: Mesa crash with AMD GPU + Wayland + Qt 6.11.0
+ qutebrowser = prev.symlinkJoin {
+ name = "qutebrowser";
+ paths = [prev.qutebrowser];
+ buildInputs = [prev.makeWrapper];
+ postBuild = ''
+ wrapProgram $out/bin/qutebrowser \
+ --set LIBGL_ALWAYS_SOFTWARE 1
+ '';
+ };
+ })
+ ];
_module.args = {
inherit inputs;
};
diff --git a/home/programs/qutebrowser/greasemonkey/dont-track-me-google.user.js b/home/programs/qutebrowser/greasemonkey/dont-track-me-google.user.js
deleted file mode 100644
index 0b1ede4..0000000
--- a/home/programs/qutebrowser/greasemonkey/dont-track-me-google.user.js
+++ /dev/null
@@ -1,826 +0,0 @@
-// ==UserScript==
-// @name Don't track me Google
-// @namespace Rob W
-// @description Removes the annoying link-conversion at Google Search/maps/...
-// @version 4.28
-// @icon https://raw.githubusercontent.com/Rob--W/dont-track-me-google/master/icon48.png
-// @supportURL https://github.com/Rob--W/dont-track-me-google/issues
-// @license MIT
-// @run-at document-start
-// @match *://*.google.com/*
-// @match *://*.google.ad/*
-// @match *://*.google.ae/*
-// @match *://*.google.com.af/*
-// @match *://*.google.com.ag/*
-// @match *://*.google.com.ai/*
-// @match *://*.google.al/*
-// @match *://*.google.am/*
-// @match *://*.google.co.ao/*
-// @match *://*.google.com.ar/*
-// @match *://*.google.as/*
-// @match *://*.google.at/*
-// @match *://*.google.com.au/*
-// @match *://*.google.az/*
-// @match *://*.google.ba/*
-// @match *://*.google.com.bd/*
-// @match *://*.google.be/*
-// @match *://*.google.bf/*
-// @match *://*.google.bg/*
-// @match *://*.google.com.bh/*
-// @match *://*.google.bi/*
-// @match *://*.google.bj/*
-// @match *://*.google.com.bn/*
-// @match *://*.google.com.bo/*
-// @match *://*.google.com.br/*
-// @match *://*.google.bs/*
-// @match *://*.google.bt/*
-// @match *://*.google.co.bw/*
-// @match *://*.google.by/*
-// @match *://*.google.com.bz/*
-// @match *://*.google.ca/*
-// @match *://*.google.cd/*
-// @match *://*.google.cf/*
-// @match *://*.google.cg/*
-// @match *://*.google.ch/*
-// @match *://*.google.ci/*
-// @match *://*.google.co.ck/*
-// @match *://*.google.cl/*
-// @match *://*.google.cm/*
-// @match *://*.google.cn/*
-// @match *://*.google.com.co/*
-// @match *://*.google.co.cr/*
-// @match *://*.google.com.cu/*
-// @match *://*.google.cv/*
-// @match *://*.google.com.cy/*
-// @match *://*.google.cz/*
-// @match *://*.google.de/*
-// @match *://*.google.dj/*
-// @match *://*.google.dk/*
-// @match *://*.google.dm/*
-// @match *://*.google.com.do/*
-// @match *://*.google.dz/*
-// @match *://*.google.com.ec/*
-// @match *://*.google.ee/*
-// @match *://*.google.com.eg/*
-// @match *://*.google.es/*
-// @match *://*.google.com.et/*
-// @match *://*.google.fi/*
-// @match *://*.google.com.fj/*
-// @match *://*.google.fm/*
-// @match *://*.google.fr/*
-// @match *://*.google.ga/*
-// @match *://*.google.ge/*
-// @match *://*.google.gg/*
-// @match *://*.google.com.gh/*
-// @match *://*.google.com.gi/*
-// @match *://*.google.gl/*
-// @match *://*.google.gm/*
-// @match *://*.google.gp/*
-// @match *://*.google.gr/*
-// @match *://*.google.com.gt/*
-// @match *://*.google.gy/*
-// @match *://*.google.com.hk/*
-// @match *://*.google.hn/*
-// @match *://*.google.hr/*
-// @match *://*.google.ht/*
-// @match *://*.google.hu/*
-// @match *://*.google.co.id/*
-// @match *://*.google.ie/*
-// @match *://*.google.co.il/*
-// @match *://*.google.im/*
-// @match *://*.google.co.in/*
-// @match *://*.google.iq/*
-// @match *://*.google.is/*
-// @match *://*.google.it/*
-// @match *://*.google.je/*
-// @match *://*.google.com.jm/*
-// @match *://*.google.jo/*
-// @match *://*.google.co.jp/*
-// @match *://*.google.co.ke/*
-// @match *://*.google.com.kh/*
-// @match *://*.google.ki/*
-// @match *://*.google.kg/*
-// @match *://*.google.co.kr/*
-// @match *://*.google.com.kw/*
-// @match *://*.google.kz/*
-// @match *://*.google.la/*
-// @match *://*.google.com.lb/*
-// @match *://*.google.li/*
-// @match *://*.google.lk/*
-// @match *://*.google.co.ls/*
-// @match *://*.google.lt/*
-// @match *://*.google.lu/*
-// @match *://*.google.lv/*
-// @match *://*.google.com.ly/*
-// @match *://*.google.co.ma/*
-// @match *://*.google.md/*
-// @match *://*.google.me/*
-// @match *://*.google.mg/*
-// @match *://*.google.mk/*
-// @match *://*.google.ml/*
-// @match *://*.google.com.mm/*
-// @match *://*.google.mn/*
-// @match *://*.google.ms/*
-// @match *://*.google.com.mt/*
-// @match *://*.google.mu/*
-// @match *://*.google.mv/*
-// @match *://*.google.mw/*
-// @match *://*.google.com.mx/*
-// @match *://*.google.com.my/*
-// @match *://*.google.co.mz/*
-// @match *://*.google.com.na/*
-// @match *://*.google.com.nf/*
-// @match *://*.google.com.ng/*
-// @match *://*.google.com.ni/*
-// @match *://*.google.ne/*
-// @match *://*.google.nl/*
-// @match *://*.google.no/*
-// @match *://*.google.com.np/*
-// @match *://*.google.nr/*
-// @match *://*.google.nu/*
-// @match *://*.google.co.nz/*
-// @match *://*.google.com.om/*
-// @match *://*.google.com.pa/*
-// @match *://*.google.com.pe/*
-// @match *://*.google.com.pg/*
-// @match *://*.google.com.ph/*
-// @match *://*.google.com.pk/*
-// @match *://*.google.pl/*
-// @match *://*.google.pn/*
-// @match *://*.google.com.pr/*
-// @match *://*.google.ps/*
-// @match *://*.google.pt/*
-// @match *://*.google.com.py/*
-// @match *://*.google.com.qa/*
-// @match *://*.google.ro/*
-// @match *://*.google.ru/*
-// @match *://*.google.rw/*
-// @match *://*.google.com.sa/*
-// @match *://*.google.com.sb/*
-// @match *://*.google.sc/*
-// @match *://*.google.se/*
-// @match *://*.google.com.sg/*
-// @match *://*.google.sh/*
-// @match *://*.google.si/*
-// @match *://*.google.sk/*
-// @match *://*.google.com.sl/*
-// @match *://*.google.sn/*
-// @match *://*.google.so/*
-// @match *://*.google.sm/*
-// @match *://*.google.sr/*
-// @match *://*.google.st/*
-// @match *://*.google.com.sv/*
-// @match *://*.google.td/*
-// @match *://*.google.tg/*
-// @match *://*.google.co.th/*
-// @match *://*.google.com.tj/*
-// @match *://*.google.tk/*
-// @match *://*.google.tl/*
-// @match *://*.google.tm/*
-// @match *://*.google.tn/*
-// @match *://*.google.to/*
-// @match *://*.google.com.tr/*
-// @match *://*.google.tt/*
-// @match *://*.google.com.tw/*
-// @match *://*.google.co.tz/*
-// @match *://*.google.com.ua/*
-// @match *://*.google.co.ug/*
-// @match *://*.google.co.uk/*
-// @match *://*.google.com.uy/*
-// @match *://*.google.co.uz/*
-// @match *://*.google.com.vc/*
-// @match *://*.google.co.ve/*
-// @match *://*.google.vg/*
-// @match *://*.google.co.vi/*
-// @match *://*.google.com.vn/*
-// @match *://*.google.vu/*
-// @match *://*.google.ws/*
-// @match *://*.google.rs/*
-// @match *://*.google.co.za/*
-// @match *://*.google.co.zm/*
-// @match *://*.google.co.zw/*
-// @match *://*.google.cat/*
-// @match *://*.google.ng/*
-// @downloadURL https://update.greasyfork.org/scripts/428243/Don%27t%20track%20me%20Google.user.js
-// @updateURL https://update.greasyfork.org/scripts/428243/Don%27t%20track%20me%20Google.meta.js
-// ==/UserScript==
-
-document.addEventListener('mousedown', handlePointerPress, true);
-document.addEventListener('touchstart', handlePointerPress, true);
-document.addEventListener('click', handleClick, true);
-var scriptCspNonce;
-var needsCspNonce = typeof browser !== 'undefined'; // Firefox.
-var preferenceObservers = [];
-setupAggresiveUglyLinkPreventer();
-
-var forceNoReferrer = true;
-var noping = true;
-if (typeof chrome == 'object' && chrome.storage) {
- (chrome.storage.sync || chrome.storage.local).get({
- forceNoReferrer: true,
- // From version 4.7 until 4.11, the preference was the literal value of
- // the referrer policy.
- referrerPolicy: 'no-referrer',
- noping: true,
- }, function(items) {
- if (items) {
- // Migration code (to be removed in the future).
- if (items.referrerPolicy === '') {
- // User explicitly allowed referrers to be sent, respect that.
- items.forceNoReferrer = false;
- }
- forceNoReferrer = items.forceNoReferrer;
- noping = items.noping;
- callPreferenceObservers();
- }
- });
- chrome.storage.onChanged.addListener(function(changes) {
- if (changes.forceNoReferrer) {
- forceNoReferrer = changes.forceNoReferrer.newValue;
- }
- if (changes.noping) {
- noping = changes.noping.newValue;
- }
- callPreferenceObservers();
- });
-}
-
-function callImmediatelyAndOnPreferenceUpdate(callback) {
- callback();
- preferenceObservers.push(callback);
-}
-function callPreferenceObservers() {
- // This method is usually once, and occasionally more than once if the user
- // changes a preference. For simplicity we don't check whether a pref was
- // changed before calling a callback - these are cheap anyway.
- preferenceObservers.forEach(function(callback) {
- callback();
- });
-}
-
-function getReferrerPolicy() {
- return forceNoReferrer ? 'origin' : '';
-}
-
-function updateReferrerPolicy(a) {
- if (a.referrerPolicy === 'no-referrer') {
- // "no-referrer" is more privacy-friendly than "origin".
- return;
- }
- var referrerPolicy = getReferrerPolicy();
- if (referrerPolicy) {
- a.referrerPolicy = referrerPolicy;
- }
-}
-
-function handlePointerPress(e) {
- var a = e.target;
- while (a && !a.href) {
- a = a.parentElement;
- }
- if (!a) {
- return;
- }
- var inlineMousedown = a.getAttribute('onmousedown');
- // return rwt(....); // E.g Google search results.
- // return google.rwt(...); // E.g. sponsored search results
- // return google.arwt(this); // E.g. sponsored search results (dec 2016).
- if (inlineMousedown && /\ba?rwt\(/.test(inlineMousedown)) {
- a.removeAttribute('onmousedown');
- // Just in case:
- a.removeAttribute('ping');
- // In Chrome, removing onmousedown during event dispatch does not
- // prevent the inline listener from running... So we have to cancel
- // event propagation just in case.
- e.stopImmediatePropagation();
- }
- if (noping) {
- a.removeAttribute('ping');
- }
- var realLink = getRealLinkFromGoogleUrl(a);
- if (realLink) {
- a.href = realLink;
- // Sometimes, two fixups are needed, on old mobile user agents:
- // /url?q=https://googleweblight.com/fp?u=... -> ...
- realLink = getRealLinkFromGoogleUrl(a);
- if (realLink) {
- a.href = realLink;
- }
- }
- updateReferrerPolicy(a);
-
- if (e.eventPhase === Event.CAPTURING_PHASE) {
- // Our event listener runs first, to sanitize the link.
- // But the page may have an event handler that modifies the link again.
- // We can append a listener to the bubbling phase of the (current)
- // event dispatch to fix the link up again, provided that the page did
- // not call stopPropagation() or stopImmediatePropagation().
- var eventOptions = { capture: false, once: true };
- a.addEventListener(e.type, handlePointerPress, eventOptions);
- document.addEventListener(e.type, handlePointerPress, eventOptions);
- }
-}
-
-// This is specifically designed for catching clicks in Gmail.
-// Gmail binds a click handler to a
and cancels the event after opening
-// a window with an ugly URL. It uses a blank window + meta refresh in Firefox,
-// which is too crazy to patch. So we just make sure that the browser's default
-// click handler is activated (=open link in new tab).
-// The entry point for this crazy stuff is shown in my comment at
-// https://github.com/Rob--W/dont-track-me-google/issues/2
-function handleClick(e) {
- if (e.button !== 0) {
- return;
- }
- var a = e.target;
- while (a && !a.href) {
- a = a.parentElement;
- }
- if (!a) {
- return;
- }
- if (a.dataset && a.dataset.url) {
- var realLink = getSanitizedIntentUrl(a.dataset.url);
- if (realLink) {
- a.dataset.url = realLink;
- }
- }
- if (!location.hostname.startsWith('mail.')) {
- // This hack was designed for Gmail, but broke other Google sites:
- // - https://github.com/Rob--W/dont-track-me-google/issues/6
- // - https://github.com/Rob--W/dont-track-me-google/issues/19
- // So let's disable it for every domain except Gmail.
- return;
- }
- // TODO: Consider using a.baseURI instead of location in case Gmail ever
- // starts using
?
- if (a.origin === location.origin) {
- // Same-origin link.
- // E.g. an in-page navigation at Google Docs (#...)
- // or an attachment at Gmail (https://mail.google.com/mail/u/0?ui=2&...)
- return;
- }
- if (a.protocol !== 'http:' &&
- a.protocol !== 'https:' &&
- a.protocol !== 'ftp:') {
- // Be conservative and don't block too much. E.g. Gmail has special
- // handling for mailto:-URLs, and using stopPropagation now would
- // cause mailto:-links to be opened by the platform's default mailto
- // handler instead of Gmail's handler (=open in new window).
- return;
- }
- if (a.target === '_blank') {
- e.stopPropagation();
- updateReferrerPolicy(a);
- }
-}
-
-/**
- * @param {URL|HTMLHyperlinkElementUtils} a
- * @returns {String} the real URL if the given link is a Google redirect URL.
- */
-function getRealLinkFromGoogleUrl(a) {
- if (a.protocol !== 'https:' && a.protocol !== 'http:') {
- return;
- }
- var url;
- if ((a.hostname === location.hostname || a.hostname === 'www.google.com') &&
- (a.pathname === '/url' || a.pathname === '/local_url' ||
- a.pathname === '/searchurl/rr.html' ||
- a.pathname === '/linkredirect')) {
- // Google Maps / Dito (/local_url?q=
)
- // Mobile (/url?q=)
- // Google Meet's chat (/linkredirect?authuser=0&dest=)
- url = /[?&](?:q|url|dest)=((?:https?|ftp)[%:][^&]+)/.exec(a.search);
- if (url) {
- return decodeURIComponent(url[1]);
- }
- // Help pages, e.g. safe browsing (/url?...&q=%2Fsupport%2Fanswer...)
- url = /[?&](?:q|url)=((?:%2[Ff]|\/)[^&]+)/.exec(a.search);
- if (url) {
- return a.origin + decodeURIComponent(url[1]);
- }
- // Redirect pages for Android intents (/searchurl/rr.html#...&url=...)
- // rr.html only supports http(s). So restrict to http(s) only.
- url = /[#&]url=(https?[:%][^&]+)/.exec(a.hash);
- if (url) {
- return decodeURIComponent(url[1]);
- }
- }
- // Google Search with old mobile UA (e.g. Firefox 41).
- if (a.hostname === 'googleweblight.com' && a.pathname === '/fp') {
- url = /[?&]u=((?:https?|ftp)[%:][^&]+)/.exec(a.search);
- if (url) {
- return decodeURIComponent(url[1]);
- }
- }
-}
-
-/**
- * @param {string} intentUrl
- * @returns {string|undefined} The sanitized intent:-URL if it was an intent URL
- * with embedded tracking link.
- */
-function getSanitizedIntentUrl(intentUrl) {
- if (!intentUrl.startsWith('intent:')) {
- return;
- }
- // https://developer.chrome.com/multidevice/android/intents#syntax
- var BROWSER_FALLBACK_URL = ';S.browser_fallback_url=';
- var indexStart = intentUrl.indexOf(BROWSER_FALLBACK_URL);
- if (indexStart === -1) {
- return;
- }
- indexStart += BROWSER_FALLBACK_URL.length;
- var indexEnd = intentUrl.indexOf(';', indexStart);
- indexEnd = indexEnd === -1 ? intentUrl.length : indexEnd;
-
- var url = decodeURIComponent(intentUrl.substring(indexStart, indexEnd));
- var realUrl = getRealLinkFromGoogleUrl(newURL(url));
- if (!realUrl) {
- return;
- }
- return intentUrl.substring(0, indexStart) +
- encodeURIComponent(realUrl) +
- intentUrl.substring(indexEnd);
-}
-
-/**
- * Intercept the .href setter in the page so that the page can never change the
- * URL to a tracking URL. Just intercepting mousedown/touchstart is not enough
- * because e.g. on Google Maps, the page rewrites the URL in the contextmenu
- * event at the bubbling event stage and then stops the event propagation. So
- * there is no event-driven way to fix the URL. The DOMAttrModified event could
- * be used, but the event is deprecated, so not a viable long-term solution.
- */
-function setupAggresiveUglyLinkPreventer() {
- // This content script runs as document_start, so we can have some assurance
- // that the methods in the page are reliable.
- var s = document.createElement('script');
- if (getScriptCspNonce()) {
- s.setAttribute('nonce', scriptCspNonce);
- } else if (document.readyState !== 'complete' && needsCspNonce) {
- // In Firefox, a page's CSP is enforced for content scripts, so we need
- // to wait for the document to be loaded (we may be at document_start)
- // and find a fitting CSP nonce.
- findScriptCspNonce(setupAggresiveUglyLinkPreventer);
- return;
- }
- s.textContent = '(' + function(getRealLinkFromGoogleUrl) {
- var proto = HTMLAnchorElement.prototype;
- // The link target can be changed in many ways, but let's only consider
- // the .href attribute since it's probably the only used setter.
- var hrefProp = Object.getOwnPropertyDescriptor(proto, 'href');
- var hrefGet = Function.prototype.call.bind(hrefProp.get);
- var hrefSet = Function.prototype.call.bind(hrefProp.set);
-
- Object.defineProperty(proto, 'href', {
- configurable: true,
- enumerable: true,
- get() {
- return hrefGet(this);
- },
- set(v) {
- hrefSet(this, v);
- try {
- v = getRealLinkFromGoogleUrl(this);
- if (v) {
- hrefSet(this, v);
- }
- } catch (e) {
- // Not expected to happen, but don't break the setter if for
- // some reason the (hostile) page broke the link APIs.
- }
- updateReferrerPolicy(this);
- },
- });
- function replaceAMethod(methodName, methodFunc) {
- // Overwrite the methods without triggering setters, because that
- // may inadvertently overwrite the prototype, as observed in
- // https://github.com/Rob--W/dont-track-me-google/issues/52#issuecomment-1596207655
- Object.defineProperty(proto, methodName, {
- configurable: true,
- // All methods that we are overriding are not part of
- // HTMLAnchorElement.prototype, but inherit.
- enumerable: false,
- writable: true,
- value: methodFunc,
- });
- }
-
- // proto inherits Element.prototype.setAttribute:
- var setAttribute = Function.prototype.call.bind(proto.setAttribute);
- replaceAMethod('setAttribute', function(name, value) {
- // Attribute names are not case-sensitive, but weird capitalizations
- // are unlikely, so only check all-lowercase and all-uppercase.
- if (name === 'href' || name === 'HREF') {
- this.href = value;
- } else {
- setAttribute(this, name, value);
- }
- });
-
- // proto inherits EventTarget.prototype.dispatchEvent:
- var aDispatchEvent = Function.prototype.apply.bind(proto.dispatchEvent);
- replaceAMethod('dispatchEvent', function() {
- updateReferrerPolicy(this);
- return aDispatchEvent(this, arguments);
- });
-
- // proto inherits HTMLElement.prototype.click:
- var aClick = Function.prototype.apply.bind(proto.click);
- replaceAMethod('click', function() {
- updateReferrerPolicy(this);
- return aClick(this, arguments);
- });
-
- var rpProp = Object.getOwnPropertyDescriptor(proto, 'referrerPolicy');
- var rpGet = Function.prototype.call.bind(rpProp.get);
- var rpSet = Function.prototype.call.bind(rpProp.set);
-
- var currentScript = document.currentScript;
- var getReferrerPolicy = Object.getOwnPropertyDescriptor(
- HTMLScriptElement.prototype,
- 'referrerPolicy'
- ).get.bind(currentScript);
-
- function updateReferrerPolicy(a) {
- try {
- if (rpGet(a) === 'no-referrer') {
- // "no-referrer" is more privacy-friendly than "origin".
- return;
- }
- var referrerPolicy = getReferrerPolicy();
- if (referrerPolicy) {
- rpSet(a, referrerPolicy);
- }
- } catch (e) {
- // Not expected to happen, but don't break callers if it happens
- // anyway.
- }
- }
- currentScript.dataset.jsEnabled = 1;
- } + ')(' + getRealLinkFromGoogleUrl + ');';
- callImmediatelyAndOnPreferenceUpdate(function forceNoReferrerChanged() {
- // Send the desired referrerPolicy value to the injected script.
- s.referrerPolicy = getReferrerPolicy();
- });
- (document.head || document.documentElement).appendChild(s);
- s.remove();
- if (!s.dataset.jsEnabled) {
- cleanLinksWhenJsIsDisabled();
- if (!needsCspNonce) {
- needsCspNonce = true;
- // This is not Firefox, but the script was blocked. Perhaps a CSP
- // nonce is needed anyway.
- findScriptCspNonce(function() {
- if (scriptCspNonce) {
- setupAggresiveUglyLinkPreventer();
- }
- });
- }
- } else {
- // Scripts enabled (not blocked by CSP), run other inline scripts.
- blockTrackingBeacons();
- overwriteWindowOpen();
-
- if (location.hostname === 'docs.google.com') {
- // Google Docs have simple non-JS interfaces where the ugly links
- // are hard-coded in the HTML. Remove them (#51).
- // https://docs.google.com/document/d/.../mobilebasic
- // https://docs.google.com/spreadsheets/d/.../htmlview
- cleanLinksWhenJsIsDisabled();
- }
- }
-}
-
-// Block sendBeacon requests with destination /gen_204, because Google
-// asynchronously sends beacon requests in response to mouse events on links:
-// https://github.com/Rob--W/dont-track-me-google/issues/20
-//
-// This implementation also blocks other forms of tracking via gen_204 as a side
-// effect. That is not fully intentional, but given the lack of obvious ways to
-// discern such link-tracking events from others, I will block all of them.
-function blockTrackingBeacons() {
- var s = document.createElement('script');
- if (getScriptCspNonce()) {
- s.setAttribute('nonce', scriptCspNonce);
- }
- s.textContent = '(' + function() {
- var navProto = window.Navigator.prototype;
- var navProtoSendBeacon = navProto.sendBeacon;
- if (!navProtoSendBeacon) {
- return;
- }
- var sendBeacon = Function.prototype.apply.bind(navProtoSendBeacon);
-
- // Blocks the following:
- // gen_204
- // /gen_204
- // https://www.google.com/gen_204
- var isTrackingUrl = RegExp.prototype.test.bind(
- /^(?:(?:https?:\/\/[^\/]+)?\/)?gen_204(?:[?#]|$)/);
-
- navProto.sendBeacon = function(url, data) {
- if (isTrackingUrl(url) && isNoPingEnabled()) {
- // Lie that the data has been transmitted to avoid fallbacks.
- return true;
- }
- return sendBeacon(this, arguments);
- };
-
- var currentScript = document.currentScript;
- var getElementId = Object.getOwnPropertyDescriptor(
- Element.prototype,
- 'id'
- ).get.bind(currentScript);
- function isNoPingEnabled() {
- try {
- return getElementId() !== '_dtmg_do_not_touch_ping';
- } catch (e) {
- return true;
- }
- }
- } + ')();';
- callImmediatelyAndOnPreferenceUpdate(function nopingChanged() {
- // Send the noping value to the injected script. The "id" property is
- // mirrored and can have an arbitrary (string) value, so we use that:
- s.id = noping ? '' : '_dtmg_do_not_touch_ping';
- });
- (document.head || document.documentElement).appendChild(s);
- s.remove();
-}
-
-// Google sometimes uses window.open() to open ugly links.
-// https://github.com/Rob--W/dont-track-me-google/issues/18
-// https://github.com/Rob--W/dont-track-me-google/issues/41
-function overwriteWindowOpen() {
- var s = document.createElement('script');
- if (getScriptCspNonce()) {
- s.setAttribute('nonce', scriptCspNonce);
- }
- s.textContent = '(' + function() {
- var open = window.open;
- window.open = function(url, windowName, windowFeatures) {
- var isBlankUrl = !url || url === "about:blank";
- try {
- if (!isBlankUrl) {
- var a = document.createElement('a');
- // Triggers getRealLinkFromGoogleUrl via the href setter in
- // setupAggresiveUglyLinkPreventer.
- a.href = url;
- url = a.href;
- // The origin check exists to avoid adding "noreferrer" to
- // same-origin popups. That implies noopener and causes
- // https://github.com/Rob--W/dont-track-me-google/issues/43
- // And allow any Google domain to support auth popups:
- // https://github.com/Rob--W/dont-track-me-google/issues/45
- // And don't bother editing the list if it already contains
- // "opener" (it would be disabled by "noreferrer").
- if (a.referrerPolicy && a.origin !== location.origin &&
- !/\.google\.([a-z]+)$/.test(a.hostname) &&
- !/\bopener|noreferrer/.test(windowFeatures)) {
- if (windowFeatures) {
- windowFeatures += ',';
- } else {
- windowFeatures = '';
- }
- windowFeatures += 'noreferrer';
- }
- }
- } catch (e) {
- // Not expected to happen, but don't break callers if it does.
- }
- var win = open(url, windowName, windowFeatures);
- try {
- if (isBlankUrl && win) {
- // In Google Docs, sometimes a blank document is opened,
- // and document.write is used to insert a redirector.
- // https://github.com/Rob--W/dont-track-me-google/issues/41
- var doc = win.document;
- var docWrite = win.Function.prototype.call.bind(doc.write);
- doc.write = function(markup) {
- try {
- markup = fixupDocMarkup(markup);
- } catch (e) {
- // Not expected, but don't break callers otherwise.
- }
- return docWrite(this, markup);
- };
- }
- } catch (e) {
- // Not expected to happen, but don't break callers if it does.
- }
- return win;
- };
- function fixupDocMarkup(html) {
- html = html || '';
- html += '';
- return html.replace(
- /]*http-equiv=(["']?)refresh\1[^>]*>/i,
- function(m) {
- var doc = new DOMParser().parseFromString(m, 'text/html');
- var meta = doc.querySelector('meta[http-equiv=refresh]');
- return meta && fixupMetaUrl(meta) || m;
- });
- }
- function fixupMetaUrl(meta) {
- var parts = /^(\d*;\s*url=)(.+)$/i.exec(meta.content);
- if (!parts) {
- return;
- }
- var metaPrefix = parts[1];
- var url = parts[2];
- var a = document.createElement('a');
- // Triggers getRealLinkFromGoogleUrl via the href setter in
- // setupAggresiveUglyLinkPreventer.
- a.href = url;
- url = a.href;
- meta.content = metaPrefix + url;
-
- var html = meta.outerHTML;
- if (a.referrerPolicy) {
- // Google appears to already append the no-referrer
- // meta tag, but add one just in case it doesn't.
- html = '' + html;
- }
- return html;
- }
- } + ')();';
- (document.head || document.documentElement).appendChild(s);
- s.remove();
-}
-
-function cleanLinksWhenJsIsDisabled() {
- // When JavaScript is disabled, Google sets the "href" attribute's value to
- // an ugly URL. Although the link is rewritten on click, we still need to
- // rewrite the link even earlier because otherwise the ugly URL is shown in
- // the tooltip upon hover.
-
- if (document.readyState == 'complete') {
- cleanAllLinks();
- return;
- }
-
- // When JS is disabled, the links won't change after the document finishes
- // loading. Until the DOM has finished loading, use the mouseover event to
- // beautify links (the DOMContentLoaded may be delayed on slow networks).
- document.addEventListener('mouseover', handleMouseOver);
- document.addEventListener('DOMContentLoaded', function() {
- document.removeEventListener('mouseover', handleMouseOver);
- cleanAllLinks();
- }, {once: true});
-
- function cleanAllLinks() {
- var as = document.querySelectorAll('a[href]');
- for (var i = 0; i < as.length; ++i) {
- var href = getRealLinkFromGoogleUrl(as[i]);
- if (href) {
- as[i].href = href;
- }
- }
- }
-
- function handleMouseOver(e) {
- var a = e.target;
- var href = a.href && getRealLinkFromGoogleUrl(a);
- if (href) {
- a.href = href;
- }
- }
-}
-
-function getScriptCspNonce() {
- var scripts = document.querySelectorAll('script[nonce]');
- for (var i = 0; i < scripts.length && !scriptCspNonce; ++i) {
- scriptCspNonce = scripts[i].nonce;
- }
- return scriptCspNonce;
-}
-
-function findScriptCspNonce(callback) {
- var timer;
- function checkDOM() {
- if (getScriptCspNonce() || document.readyState === 'complete') {
- document.removeEventListener('DOMContentLoaded', checkDOM, true);
- if (timer) {
- clearTimeout(timer);
- }
- callback();
- return;
- }
- timer = setTimeout(checkDOM, 50);
- }
- document.addEventListener('DOMContentLoaded', checkDOM, true);
- checkDOM();
-}
-
-function newURL(href) {
- try {
- return new URL(href);
- } catch (e) {
- var a = document.createElement('a');
- a.href = href;
- return a;
- }
-}
diff --git a/home/programs/qutebrowser/greasemonkey/i-dont-care-about-cookies.user.js b/home/programs/qutebrowser/greasemonkey/i-dont-care-about-cookies.user.js
deleted file mode 100644
index 025d961..0000000
--- a/home/programs/qutebrowser/greasemonkey/i-dont-care-about-cookies.user.js
+++ /dev/null
@@ -1,984 +0,0 @@
-// ==UserScript==
-// @name I don't care about cookies
-// @name:vi Tôi không quan tâm về cookie
-// @name:zh-CN 我不关心cookie
-// @name:zh-TW 我不關心cookie
-// @name:ja クッキーについては気にしない
-// @name:ru Я не забочусь о куки
-// @namespace http://tampermonkey.net/
-// @version 2025.01.03.2
-// @description Remove cookie warnings from almost all websites! Auto accept cookies and remove annoying cookie popups
-// @description:vi Loại bỏ cảnh báo cookie từ hầu hết các trang web! Tự động chấp nhận cookie và xóa các popup cookie phiền phức
-// @description:zh-CN 自动接受cookie并移除烦人的cookie弹窗
-// @description:zh-TW 自動接受cookie並移除煩人的cookie彈窗
-// @description:ru Автоматическое принятие cookie и удаление надоедливых всплывающих окон
-// @description:ja 自動承認cookieと迷惑なポップアップを削除
-// @author Yuusei
-// @match *://*/*
-// @grant none
-// @icon https://lh3.googleusercontent.com/sCLTYpGX0VcVootQ_XaFQ9saRIhVWu79ngSzY5eTZ5evRpJ_Q27OdvxA4RrOoZXP7Q4enFh-u6VhxObcJLfARw1g=s60
-// @compatible chrome
-// @compatible edge
-// @compatible firefox
-// @compatible safari
-// @run-at document-start
-// @license gpl-3.0-only
-// @downloadURL https://update.greasyfork.org/scripts/522645/I%20don%27t%20care%20about%20cookies.user.js
-// @updateURL https://update.greasyfork.org/scripts/522645/I%20don%27t%20care%20about%20cookies.meta.js
-// ==/UserScript==
-
-(function () {
- 'use strict';
-
- const CONSENT_TEXTS = {
- en: ['accept', 'accept all', 'agree', 'continue', 'got it', 'reject all', 'decline', 'necessary only', 'required only', 'manage', 'customize'],
- vi: ['chấp nhận', 'chấp nhận tất cả', 'đồng ý', 'tiếp tục', 'từ chối tất cả', 'từ chối', 'chỉ cần thiết', 'tùy chỉnh', 'quản lý', 'cho phép', 'đồng ý và tiếp tục', 'tôi đồng ý', 'xác nhận', 'tôi chấp nhận', 'đồng ý tất cả', 'chấp nhận và tiếp tục', 'cho phép tất cả'],
- zh: ['接受', '接受全部', '同意', '继续', '拒绝全部', '拒绝', '仅必要', '管理', '自定义'],
- ru: ['принять', 'принять все', 'согласен', 'продолжить', 'отклонить все', 'отклонить', 'только необходимые', 'настроить', 'управлять'],
- ja: ['承認', '同意', '続ける', 'すべて拒否', '拒否', '必要のみ', 'カスタマイズ', '管理'],
- de: ['akzeptieren', 'einverstanden', 'fortfahren', 'alle ablehnen', 'ablehnen', 'nur notwendige', 'anpassen', 'verwalten'],
- fr: ['accepter', 'accepter tout', 'accepte', 'continuer', 'tout refuser', 'refuser', 'uniquement nécessaire', 'personnaliser', 'gérer'],
- es: ['aceptar', 'acepto todo', 'acepto', 'continuar', 'rechazar todo', 'rechazar', 'solo necesario', 'personalizar', 'gestionar'],
- it: ['accetta', 'accetto tutto', 'accetto', 'continua', 'rifiuta tutto', 'rifiuta', 'solo necessari', 'personalizza', 'gestisci'],
- pl: ['akceptuj', 'akceptuj wszystko', 'zgadzam się', 'kontynuuj', 'odrzuć wszystko', 'odrzuć', 'tylko niezbędne', 'dostosuj', 'zarządzaj'],
- nl: ['accepteren', 'accepteren', 'doorgaan', 'alles weigeren', 'weigeren', 'alleen noodzakelijk', 'aanpassen', 'beheren'],
- ko: ['동의', '모두 동의', '계속하기', '모두 거부', '거부', '필수만', '설정', '관리'],
- th: ['ยอมรับ', 'ยอมรับทั้งหมด', 'ตกลง', 'ปฏิเสธทั้งหมด', 'ปฏิเสธ', 'จำเป็นเท่านั้น', 'ตั้งค่า', 'จัดการ'],
- id: ['setuju', 'setuju semua', 'lanjutkan', 'tolak semua', 'tolak', 'wajib saja', 'pengaturan', 'kelola'],
- ms: ['terima', 'terima semua', 'teruskan', 'tolak semua', 'tolak', 'perlu sahaja', 'tetapan', 'urus'],
- pt: ['aceitar', 'aceitar tudo', 'continuar', 'rejeitar tudo', 'rejeitar', 'necessário', 'configurar', 'gerir'],
- sv: ['godkänn', 'godkänn alla', 'fortsätt', 'neka alla', 'neka', 'nödvändiga', 'inställningar', 'hantera'],
- da: ['accepter', 'accepter alle', 'fortsæt', 'afvis alle', 'afvis', 'nødvendige', 'indstillinger', 'administrer'],
- fi: ['hyväksy', 'hyväksy kaikki', 'jatka', 'hylkää kaikki', 'hylkää', 'välttämätön', 'asetukset', 'hallitse'],
- 'zh-CN': ['接受', '接受全部', '同意', '继续', '我同意', '确定', '确认', '知道了', '好的', '拒绝全部', '拒绝', '仅必要', '设置', '自定义', '管理', '保存设置', '允许', '允许全部', '接受并继续', '同意并继续', '保存并继续'],
- 'zh-TW': ['接受', '接受全部', '同意', '繼續', '我同意', '確定', '確認', '知道了', '好的', '拒絕全部', '拒絕', '僅必要', '設置', '自定義', '管理', '保存設置', '允許', '允許全部', '接受並繼續', '同意並繼續', '保存並繼續'],
- ko: ['동의', '모두 동의', '수락', '계속하기', '확인', '거부', '거부하기', '필수만', '설정', '관리', '저장', '허용', '모두 허용'],
- th: ['ยอมรับ', 'ยอมรับทั้งหมด', 'ตกลง', 'ดำเนินการต่อ', 'ปฏิเสธ', 'ปฏิเสธทั้งหมด', 'จำเป็นเท่านั้น', 'ตั้งค่า', 'จัดการ', 'บันทึก', 'อนุญาต', 'อนุญาตทั้งหมด'],
- id: ['terima', 'terima semua', 'setuju', 'lanjutkan', 'tolak', 'tolak semua', 'wajib saja', 'pengaturan', 'kelola', 'simpan', 'izinkan', 'izinkan semua'],
- ms: ['terima', 'terima semua', 'setuju', 'teruskan', 'tolak', 'tolak semua', 'perlu sahaja', 'tetapan', 'urus', 'simpan', 'benarkan', 'benarkan semua'],
- };
-
- function matchesConsentText(element) {
- const text = element.textContent.toLowerCase();
- const lang = document.documentElement.lang || 'en';
- const texts = CONSENT_TEXTS[lang.split('-')[0]] || CONSENT_TEXTS['en'];
- return texts.some(t => text.includes(t));
- }
-
- // Utility functions
- function _sl(selector, container) {
- return (container || document).querySelector(selector);
- }
-
- function _id(id) {
- return document.getElementById(id);
- }
-
- function _ev(selector, container, full) {
- return document.evaluate((typeof full == 'undefined' ? '//' : '') + selector, container || document, null, XPathResult.ANY_TYPE, null).iterateNext();
- }
-
- function _if(condition, ...selectors) {
- return _sl(condition) ? _chain(...selectors) : false;
- }
-
- function _if_else(condition, if_selectors, else_selectors) {
- if (_sl(condition)) return _chain(...if_selectors);
-
- return _chain(...else_selectors);
- }
-
- function _chain(...selectors) {
- let elements,
- l = selectors.length;
- let flagUnique = false,
- flagOptional = false,
- flagAllMatches = false;
-
- for (let i = currentChainElement; i < l; i++) {
- if (/^FLAG\:/.test(selectors[i])) {
- selectors[i]
- .split(':')[1]
- .split(',')
- .forEach(function (flag) {
- if (flag == 'UNIQUE') flagUnique = true;
- else if (flag == 'OPTIONAL') flagOptional = true;
- else if (flag == 'REQUIRED') flagOptional = false;
- else if (flag == 'ALL-MATCHES') flagAllMatches = true;
- else if (flag == 'SINGLE-MATCH') flagAllMatches = false;
- });
-
- continue;
- }
-
- if (flagUnique) selectors[i] += selectors[i].startsWith('//') ? '[not(contains(@class, "' + classname + '"))]' : ':not(.' + classname + ')';
-
- if (i == l - 1) return selectors[i];
-
- elements = _sl(selectors[i], false, flagAllMatches);
-
- if (!flagAllMatches) elements = elements ? [elements] : [];
-
- if (!elements.length) {
- if (flagOptional) {
- currentChainElement++;
- continue;
- }
-
- return false;
- }
-
- currentChainElement++;
-
- elements.forEach(function (element) {
- if (flagUnique) element.classList.add(classname);
-
- if (element.nodeName == 'OPTION') element.selected = true;
- else element.click();
- });
- }
-
- return false;
- }
-
- function getItem(hostname) {
- switch (hostname) {
- case 'youtube.com':
- case 'www.youtube.com':
- return { strict: true, key: 'CONSENT', value: 'PENDING+999' };
-
- case 'google.com':
- case 'www.google.com':
- return { strict: true, key: 'CONSENT', value: 'YES+' };
-
- case 'twitter.com':
- case 'www.twitter.com':
- return { strict: false, key: 'twtr_cookie_consent', value: '1' };
-
- case 'pepephone.com':
- case 'lyricsbox.com':
- return { strict: true, key: 'cookieconsent', value: '1111' };
-
- case 'kontaktbazar.at':
- case 'hoernews.de':
- return { strict: false, key: 'cookieconsent_status', value: 'dismiss' };
-
- case 'vodafoneziggo.nl':
- return { strict: false, key: 'cookies-accepted', value: 'true' };
- case 'frankfurt.de':
- return { strict: false, key: 'cookieAccepted', value: 'needed---piwik' };
- case 'hackerrank.com':
- return { strict: false, key: 'show_cookie_banner', value: 'false' };
-
- case 'facebook.com':
- case 'www.facebook.com':
- return { strict: true, key: 'datr', value: 'accepted' };
-
- case 'instagram.com':
- case 'www.instagram.com':
- return { strict: true, key: 'ig_did', value: 'accepted' };
-
- case 'linkedin.com':
- case 'www.linkedin.com':
- return { strict: false, key: 'lidc', value: 'accepted' };
-
- case 'reddit.com':
- case 'www.reddit.com':
- return { strict: false, key: 'eu_cookie', value: '{"opted":true}' };
-
- case 'tiktok.com':
- case 'www.tiktok.com':
- return { strict: true, key: 'tt_webid', value: 'accepted' };
-
- case 'netflix.com':
- case 'www.netflix.com':
- return { strict: false, key: 'netflix-cookie-consent', value: 'accepted' };
-
- case 'spotify.com':
- case 'www.spotify.com':
- return { strict: false, key: 'sp_dc', value: 'accepted' };
-
- case 'amazon.com':
- case 'www.amazon.com':
- return { strict: false, key: 'amazon-cookie-consent', value: 'accepted' };
-
- case 'pinterest.com':
- case 'www.pinterest.com':
- return { strict: false, key: '_pinterest_sess', value: 'accepted' };
-
- case 'twitch.tv':
- case 'www.twitch.tv':
- return { strict: false, key: 'twitch_cookie_consent', value: 'accepted' };
-
- case 'github.com':
- case 'www.github.com':
- return { strict: false, key: '_gh_sess', value: 'accepted' };
-
- case 'medium.com':
- case 'www.medium.com':
- return { strict: false, key: 'medium_cookie_consent', value: 'accepted' };
-
- case 'quora.com':
- case 'www.quora.com':
- return { strict: false, key: 'm-b', value: 'accepted' };
-
- case 'stackoverflow.com':
- case 'www.stackoverflow.com':
- return { strict: false, key: 'acct', value: 'accepted' };
-
- case 'microsoft.com':
- case 'www.microsoft.com':
- return { strict: false, key: 'MUID', value: 'accepted' };
-
- case 'apple.com':
- case 'www.apple.com':
- return { strict: false, key: 'geo', value: 'accepted' };
-
- case 'dropbox.com':
- case 'www.dropbox.com':
- return { strict: false, key: 'dbx-consent', value: 'accepted' };
-
- case 'booking.com':
- case 'www.booking.com':
- return { strict: false, key: 'bkng_consent', value: 'accepted' };
-
- case 'vnexpress.net':
- case 'www.vnexpress.net':
- return { strict: false, key: 'vnexpress_cookie_consent', value: 'accepted' };
-
- case 'thanhnien.vn':
- case 'www.thanhnien.vn':
- return { strict: false, key: 'thanhnien_cookie', value: 'accepted' };
-
- case 'tuoitre.vn':
- case 'www.tuoitre.vn':
- return { strict: false, key: 'tuoitre_cookie', value: 'accepted' };
-
- case 'tiki.vn':
- case 'www.tiki.vn':
- return { strict: false, key: 'tiki_cookie', value: 'accepted' };
-
- case 'shopee.vn':
- case 'www.shopee.vn':
- return { strict: false, key: 'shopee_cookie', value: 'accepted' };
-
- case 'lazada.vn':
- case 'www.lazada.vn':
- return { strict: false, key: 'lzd_cookie', value: 'accepted' };
-
- case 'sendo.vn':
- case 'www.sendo.vn':
- return { strict: false, key: 'sendo_cookie', value: 'accepted' };
-
- case 'thegioididong.com':
- case 'www.thegioididong.com':
- return { strict: false, key: 'tgdd_cookie', value: 'accepted' };
-
- case 'fptshop.com.vn':
- case 'www.fptshop.com.vn':
- return { strict: false, key: 'fpt_cookie', value: 'accepted' };
-
- case 'cellphones.com.vn':
- case 'www.cellphones.com.vn':
- return { strict: false, key: 'cps_cookie', value: 'accepted' };
-
- case 'aliexpress.com':
- case 'www.aliexpress.com':
- return { strict: false, key: 'aep_usuc_f', value: 'accepted' };
-
- case 'ebay.com':
- case 'www.ebay.com':
- return { strict: false, key: 'ebay_cookie_consent', value: 'accepted' };
-
- case 'coursera.org':
- case 'www.coursera.org':
- return { strict: false, key: 'coursera_cookie', value: 'accepted' };
-
- case 'udemy.com':
- case 'www.udemy.com':
- return { strict: false, key: 'ud_cookie', value: 'accepted' };
-
- case 'bachhoaxanh.com':
- case 'www.bachhoaxanh.com':
- return { strict: false, key: 'bhx_cookie', value: 'accepted' };
-
- case 'dienmayxanh.com':
- case 'www.dienmayxanh.com':
- return { strict: false, key: 'dmx_cookie', value: 'accepted' };
-
- case 'nguyenkim.com':
- case 'www.nguyenkim.com':
- return { strict: false, key: 'nk_cookie', value: 'accepted' };
-
- case 'dantri.com.vn':
- case 'www.dantri.com.vn':
- return { strict: false, key: 'dantri_cookie', value: 'accepted' };
-
- case 'vietnamnet.vn':
- case 'www.vietnamnet.vn':
- return { strict: false, key: 'vietnamnet_cookie', value: 'accepted' };
-
- case '24h.com.vn':
- case 'www.24h.com.vn':
- return { strict: false, key: '24h_cookie', value: 'accepted' };
-
- case 'vietcombank.com.vn':
- case 'www.vietcombank.com.vn':
- return { strict: false, key: 'vcb_cookie', value: 'accepted' };
-
- case 'techcombank.com.vn':
- case 'www.techcombank.com.vn':
- return { strict: false, key: 'tcb_cookie', value: 'accepted' };
-
- case 'mbbank.com.vn':
- case 'www.mbbank.com.vn':
- return { strict: false, key: 'mb_cookie', value: 'accepted' };
-
- case 'amazon.co.jp':
- case 'www.amazon.co.jp':
- return { strict: false, key: 'amazon_jp_cookie', value: 'accepted' };
-
- case 'rakuten.co.jp':
- case 'www.rakuten.co.jp':
- return { strict: false, key: 'rakuten_jp_cookie', value: 'accepted' };
-
- case 'taobao.com':
- case 'www.taobao.com':
- return { strict: false, key: 'taobao_cookie', value: 'accepted' };
-
- case 'line.me':
- case 'www.line.me':
- return { strict: false, key: 'line_cookie', value: 'accepted' };
-
- case 'weibo.com':
- case 'www.weibo.com':
- return { strict: false, key: 'weibo_cookie', value: 'accepted' };
-
- case 'kakao.com':
- case 'www.kakao.com':
- return { strict: false, key: 'kakao_cookie', value: 'accepted' };
-
- case 'yahoo.co.jp':
- case 'www.yahoo.co.jp':
- return { strict: false, key: 'yahoo_jp_cookie', value: 'accepted' };
-
- case 'naver.com':
- case 'www.naver.com':
- return { strict: false, key: 'naver_cookie', value: 'accepted' };
-
- case 'baidu.com':
- case 'www.baidu.com':
- return { strict: false, key: 'baidu_cookie', value: 'accepted' };
-
- case 'zalando.com':
- case 'www.zalando.com':
- return { strict: false, key: 'zalando_cookie', value: 'accepted' };
-
- case 'asos.com':
- case 'www.asos.com':
- return { strict: false, key: 'asos_cookie', value: 'accepted' };
-
- case 'zara.com':
- case 'www.zara.com':
- return { strict: false, key: 'zara_cookie', value: 'accepted' };
-
- case 'tmall.com':
- case 'www.tmall.com':
- return { strict: false, key: 'tmall_cookie', value: 'accepted' };
-
- case 'jd.com':
- case 'www.jd.com':
- return { strict: false, key: 'jd_cookie', value: 'accepted' };
-
- case 'sina.com.cn':
- case 'www.sina.com.cn':
- return { strict: false, key: 'sina_cookie', value: 'accepted' };
-
- case 'qq.com':
- case 'www.qq.com':
- return { strict: false, key: 'qq_cookie', value: 'accepted' };
-
- case '163.com':
- case 'www.163.com':
- return { strict: false, key: 'netease_cookie', value: 'accepted' };
-
- case 'sohu.com':
- case 'www.sohu.com':
- return { strict: false, key: 'sohu_cookie', value: 'accepted' };
-
- case 'bilibili.com':
- case 'www.bilibili.com':
- return { strict: false, key: 'bilibili_cookie', value: 'accepted' };
- }
-
- const parts = hostname.split('.');
- if (parts.length > 2) {
- parts.shift();
- return getItem(parts.join('.'));
- }
- return false;
- }
-
- function _parent(element) {
- if (element && element.parentNode) return element.parentNode;
- return false;
- }
-
- function _iframe(iframe_selector, selector) {
- var e = _sl(iframe_selector);
- return e ? _sl(selector, e.contentDocument || e.contentWindow.contentDocument) : e;
- }
-
- // Cookie consent handling logic
- let searchPairs = {
- '.vn-cookie-banner': ['.vn-cookie-banner__reject', '.vn-cookie-banner__customize'],
- '.vn-cookie-notice': ['.vn-cookie-notice__reject', '.vn-cookie-notice__settings'],
- '.vn-cookie-consent': ['.vn-cookie-consent__reject', '.vn-cookie-consent__customize'],
- '.vn-cookie-popup': ['.vn-cookie-popup__reject', '.vn-cookie-popup__settings'],
-
- '.shopee-cookie-banner': ['.shopee-cookie-banner__reject', '.shopee-cookie-banner__settings'],
- '.lazada-cookie-notice': ['.lazada-cookie-notice__reject', '.lazada-cookie-notice__settings'],
- '.tiki-cookie-popup': ['.tiki-cookie-popup__reject', '.tiki-cookie-popup__settings'],
- '.sendo-cookie-consent': ['.sendo-cookie-consent__reject', '.sendo-cookie-consent__settings'],
-
- '.vnexpress-cookie': ['.vnexpress-cookie__reject', '.vnexpress-cookie__settings'],
- '.tuoitre-cookie': ['.tuoitre-cookie__reject', '.tuoitre-cookie__settings'],
- '.thanhnien-cookie': ['.thanhnien-cookie__reject', '.thanhnien-cookie__settings'],
- '.dantri-cookie': ['.dantri-cookie__reject', '.dantri-cookie__settings'],
-
- '.tgdd-cookie-notice': ['.tgdd-cookie-notice__reject', '.tgdd-cookie-notice__settings'],
- '.fpt-cookie-popup': ['.fpt-cookie-popup__reject', '.fpt-cookie-popup__settings'],
- '.cps-cookie-consent': ['.cps-cookie-consent__reject', '.cps-cookie-consent__settings'],
-
- '.vcb-cookie-notice': ['.vcb-cookie-notice__reject', '.vcb-cookie-notice__settings'],
- '.tcb-cookie-popup': ['.tcb-cookie-popup__reject', '.tcb-cookie-popup__settings'],
- '.mb-cookie-consent': ['.mb-cookie-consent__reject', '.mb-cookie-consent__settings'],
-
- 'div[class*="consent"]': ['button[class*="reject"]', 'button[class*="decline"]', 'button[class*="settings"]'],
- 'div[class*="notice"]': ['button[class*="reject"]', 'button[class*="decline"]', 'button[class*="settings"]'],
- 'div[class*="popup"]': ['button[class*="reject"]', 'button[class*="decline"]', 'button[class*="settings"]'],
- 'div[class*="banner"]': ['button[class*="reject"]', 'button[class*="decline"]', 'button[class*="settings"]'],
- };
-
- let searchGroups = [
- '.qc-cmp2-summary-buttons button[mode="secondary"],\
- .qc-cmp2-buttons-desktop > button:first-child,\
- #didomi-popup .didomi-button-highlight:not([class*="paywall"]):not([class*="disagree"]),\
- #rgpd_video .rgpd-mask a[data-rgpd-consent],\
- .cli-barmodal-open #wt-cli-privacy-save-btn,\
- .js--modal[style*="block"] .cookie-permission--accept-button,\
- .gdpr-modal-rider .btn-cookieaccept,\
- .js-cookiewall #sel-test-accept-cookies-button,\
- #mpo[style*="block"] .submit.modal-privacy__btn[onclick*="privacyframe.accept"],\
- .lightbox--cookie-consent .btn-cta,\
- .lightbox.cookie-consent .cookie-consent-button-decline,\
- .js-modal-gdpr.is-active .btn[data-level="2"],\
- #CybotCookiebotDialogBodyLevelButtonLevelOptinAllowallSelection,\
- #cookieNotificationModal.in .btn.accept-cookie,\
- .has-ccwindow .cc-compliance .cc-dismiss,\
- .ds2-cookie-disclaimer--slidedown .ds2-cookie-disclaimer-js--submit,\
- #mdlCookieCompliance.in .cookieClose,\
- #cookieModal.in .js-acceptDefaultCookie,\
- .c-cookiebutton .c-cookiebutton__close,\
- #normativa_cookies.in .btn,\
- #cookiewall.in .btn-primary,\
- .outerCookieBar .EuCookieBar__cookieButton,\
- #TOS-POPUP .rhododendron-popup__button--agree,\
- #cookie-wall #accept-cookies,\
- #popup-wrapper .button[href*="/cookies.consent.php"],\
- .reveal.cookies[style*="block"] button[click*="aceptaCookies"],\
- .mnd-cookie-modal[style*="block"] .btn.is--primary,\
- .cookieHandler.cookieHandler--modalOpen #acceptAllCookies,\
- .gdpr-modal--active .btn--primary,\
- #dpi-banner:not(.hidden) #btn-agree-cookie,\
- .gh-banner.gh-banner-active #gh-cookiebanner-close,\
- #mrktpref.notification-bar .btn-success,\
- #PopinGDPRCookie[style*="block"] .jsbd-popin-ok,\
- #modal-rodo.in .btn-primary,\
- .cookie-compliance-modal.in .btn-primary,\
- .cookieconsent.show .btn[data-dm*="accept"],\
- .cookie-wall-modal.in .btn.ja,\
- #modal-consent.in .modal-consent-accept,\
- .rodo #cookies.in .btn-primary,\
- .js-cookie-alert.in .js-cookie-alert-accept,\
- #modal_gdpr_intro_popup.in #gdpr-modal-btn-ok-agree,\
- #consentButtonContainer > button[onclick*="sendAndRedirect"],\
- #eu-consent[style*="block"] .btn.yes,\
- .modal--gdpr.is-open .js-gdpr-consent,\
- #cookiePopupModal.in .cookiepopup-agreed,\
- .polityka-cookie-rodo[style*="block"] .button-zgoda,\
- .ui-dialog.consent-modal[style*="block"] .js-btn-agree,\
- #up-cookie.active .button[onclick*="setCookiePreference"],\
- .RodoModal.in .close,\
- .consent-popup form[action*="cookie-consent"] .consent-popup__button,\
- #consent form[action*="cookie-consent"] .one-btn,\
- #cookiewall-wrapper .button[href*="accept"],\
- #cookieChoiceButtonAccept,\
- .mod-cookie-consent[style*="block"] .btn-all-cookies,\
- .c-layer--consent .layer-button--accept,\
- .button.button-ok[onclick*="acceptAVG"],\
- #meredithGdprConsentFormButton,\
- #advanced-cookie-modal.in .cookie-accept,\
- .show-modal .cookie-settings-manager-container .initial-dialog .js-accept-button,\
- .cookie-settings-manager-container .initial-dialog[style*="block"] .js-accept-button,\
- .gdprLightbox[data-module="gdprLightbox"] ._type_gdpr_agree,\
- .cookie.showa #Row1_Column1_Cell1_CookieSettings_AdvancedSaveAccept,\
- #core-cookie-container[style*="block"] .btn--agree,\
- .cookie-consent-modal._show .action-primary,\
- #dsgvoModal.show #dsvgo-banner__button,\
- .basicLightbox--visible #accept-all-gdpr,\
- #gdpr-modal.in .gdpr-modal__btn--accept,\
- .cookiehint .btn.cookieagree,\
- #cookiealert .modal.in .btn[href*="accept"],\
- #lml-data-consent-accept,\
- #CBCookieMsg.in .btn[onclick*="approveCookies"],\
- #cookiewall-container .button[name="submit"],\
- #cookie_disclaimer.in .cookie_disclaimer_button,\
- .m-cookie.iziModal[style*="block"] .m-cookie__save2.button,\
- kamino-cookie-policy .mat-raised-button,\
- #surbma-gpga-modal[style*="block"] button,\
- #GDPR.overlayBox .menuButton,\
- #cookiebar .cookie-selection-button.accept,\
- .modal.in .btn.close-modal-cookie,\
- #consent-module[style*="block"] #consent-module-text-button,\
- .modal #consentButton,\
- #consent-modal[style*="block"] .lm_modal__modal__content__body__buttons__ok,\
- .cookiesOverlay3Box #cookiesConsentOK,\
- .bemCookieOverlay--activePopup .bemCookieOverlay__btn--save,\
- #root main ~ div [data-gi-selector="reject-all-cookies"] ~ div a,\
- .cookies-management .cookies-deny,\
- .offcanvas.is-open .js-offcanvas-cookie-submit,\
- .force--consent.show--consent #cs_save__btn,\
- .force--consent.show--consent #s-sv-bn,\
- #cookieNoticeModal.vrm-reveal[style*="block"] .vrm-reveal__icon--close',
- '.cookie-banner .cookie-banner__buttons .cookie-banner__button--reject,\
- .cookie-consent-banner .cookie-consent-banner__reject,\
- .cookie-notification .cookie-notification__buttons .cookie-notification__reject,\
- .cookie-policy-banner .cookie-policy-banner__buttons .cookie-policy-banner__reject,\
- .cookie-warning .cookie-warning__buttons .cookie-warning__reject,\
- .cookie-notice .cookie-notice__buttons .cookie-notice__reject,\
- .cookie-alert .cookie-alert__buttons .cookie-alert__reject,\
- .cookie-popup .cookie-popup__buttons .cookie-popup__reject,\
- .cookie-modal .cookie-modal__buttons .cookie-modal__reject,\
- .cookie-dialog .cookie-dialog__buttons .cookie-dialog__reject,\
- .gdpr-banner .gdpr-banner__buttons .gdpr-banner__reject,\
- .gdpr-modal .gdpr-modal__buttons .gdpr-modal__reject,\
- .gdpr-notice .gdpr-notice__buttons .gdpr-notice__reject,\
- .gdpr-popup .gdpr-popup__buttons .gdpr-popup__reject,\
- .gdpr-dialog .gdpr-dialog__buttons .gdpr-dialog__reject,\
- .privacy-banner .privacy-banner__buttons .privacy-banner__reject,\
- .privacy-modal .privacy-modal__buttons .privacy-modal__reject,\
- .privacy-notice .privacy-notice__buttons .privacy-notice__reject,\
- .privacy-popup .privacy-popup__buttons .privacy-popup__reject,\
- .privacy-dialog .privacy-dialog__buttons .privacy-dialog__reject',
-
- '.consent-banner .consent-banner__buttons .consent-banner__reject,\
- .consent-modal .consent-modal__buttons .consent-modal__reject,\
- .consent-notice .consent-notice__buttons .consent-notice__reject,\
- .consent-popup .consent-popup__buttons .consent-popup__reject,\
- .consent-dialog .consent-dialog__buttons .consent-dialog__reject,\
- .tracking-banner .tracking-banner__buttons .tracking-banner__reject,\
- .tracking-modal .tracking-modal__buttons .tracking-modal__reject,\
- .tracking-notice .tracking-notice__buttons .tracking-notice__reject,\
- .tracking-popup .tracking-popup__buttons .tracking-popup__reject,\
- .tracking-dialog .tracking-dialog__buttons .tracking-dialog__reject',
-
- '.cookie-settings-modal .cookie-settings__reject,\
- .cookie-settings-modal .cookie-settings__customize,\
- .cookie-preferences-modal .cookie-preferences__reject,\
- .cookie-preferences-modal .cookie-preferences__customize,\
- .cookie-manager-modal .cookie-manager__reject,\
- .cookie-manager-modal .cookie-manager__customize,\
- .cookie-control-modal .cookie-control__reject,\
- .cookie-control-modal .cookie-control__customize,\
- .cookie-options-modal .cookie-options__reject,\
- .cookie-options-modal .cookie-options__customize',
-
- '.data-privacy-modal .data-privacy__reject,\
- .data-privacy-modal .data-privacy__customize,\
- .data-protection-modal .data-protection__reject,\
- .data-protection-modal .data-protection__customize,\
- .data-consent-modal .data-consent__reject,\
- .data-consent-modal .data-consent__customize,\
- .data-settings-modal .data-settings__reject,\
- .data-settings-modal .data-settings__customize,\
- .data-preferences-modal .data-preferences__reject,\
- .data-preferences-modal .data-preferences__customize',
-
- '.privacy-manager-modal .privacy-manager__reject,\
- .privacy-manager-modal .privacy-manager__customize,\
- .privacy-settings-modal .privacy-settings__reject,\
- .privacy-settings-modal .privacy-settings__customize,\
- .privacy-options-modal .privacy-options__reject,\
- .privacy-options-modal .privacy-options__customize,\
- .privacy-control-modal .privacy-control__reject,\
- .privacy-control-modal .privacy-control__customize,\
- .privacy-preferences-modal .privacy-preferences__reject,\
- .privacy-preferences-modal .privacy-preferences__customize',
-
- '.consent-manager-modal .consent-manager__reject,\
- .consent-manager-modal .consent-manager__customize,\
- .consent-settings-modal .consent-settings__reject,\
- .consent-settings-modal .consent-settings__customize,\
- .consent-options-modal .consent-options__reject,\
- .consent-options-modal .consent-options__customize,\
- .consent-control-modal .consent-control__reject,\
- .consent-control-modal .consent-control__customize,\
- .consent-preferences-modal .consent-preferences__reject,\
- .consent-preferences-modal .consent-preferences__customize',
-
- '.tracking-manager-modal .tracking-manager__reject,\
- .tracking-manager-modal .tracking-manager__customize,\
- .tracking-settings-modal .tracking-settings__reject,\
- .tracking-settings-modal .tracking-settings__customize,\
- .tracking-options-modal .tracking-options__reject,\
- .tracking-options-modal .tracking-options__customize,\
- .tracking-control-modal .tracking-control__reject,\
- .tracking-control-modal .tracking-control__customize,\
- .tracking-preferences-modal .tracking-preferences__reject,\
- .tracking-preferences-modal .tracking-preferences__customize',
-
- '.gdpr-manager-modal .gdpr-manager__reject,\
- .gdpr-manager-modal .gdpr-manager__customize,\
- .gdpr-settings-modal .gdpr-settings__reject,\
- .gdpr-settings-modal .gdpr-settings__customize,\
- .gdpr-options-modal .gdpr-options__reject,\
- .gdpr-options-modal .gdpr-options__customize,\
- .gdpr-control-modal .gdpr-control__reject,\
- .gdpr-control-modal .gdpr-control__customize,\
- .gdpr-preferences-modal .gdpr-preferences__reject,\
- .gdpr-preferences-modal .gdpr-preferences__customize',
-
- 'div[class*="cookie-banner"] button[class*="reject"],\
- div[class*="cookie-banner"] button[class*="decline"],\
- div[class*="cookie-banner"] button[class*="settings"],\
- div[id*="cookie-banner"] button[class*="reject"],\
- div[id*="cookie-banner"] button[class*="decline"],\
- div[id*="cookie-banner"] button[class*="settings"]',
-
- 'div[class*="cookie-consent"] button[class*="reject"],\
- div[class*="cookie-consent"] button[class*="decline"],\
- div[class*="cookie-consent"] button[class*="settings"],\
- div[id*="cookie-consent"] button[class*="reject"],\
- div[id*="cookie-consent"] button[class*="decline"],\
- div[id*="cookie-consent"] button[class*="settings"]',
-
- 'div[class*="cookie-notice"] button[class*="reject"],\
- div[class*="cookie-notice"] button[class*="decline"],\
- div[class*="cookie-notice"] button[class*="settings"],\
- div[id*="cookie-notice"] button[class*="reject"],\
- div[id*="cookie-notice"] button[class*="decline"],\
- div[id*="cookie-notice"] button[class*="settings"]',
-
- '[data-*="cookie"] button[data-*="reject"],\
- [data-*="cookie"] button[data-*="decline"],\
- [data-*="cookie"] button[data-*="settings"],\
- [data-*="gdpr"] button[data-*="reject"],\
- [data-*="gdpr"] button[data-*="decline"],\
- [data-*="gdpr"] button[data-*="settings"]',
-
- 'div[class*="cookie-layer"] button[class*="reject"],\
- div[class*="cookie-layer"] button[class*="decline"],\
- div[class*="cookie-layer"] button[class*="settings"],\
- div[id*="cookie-layer"] button[class*="reject"],\
- div[id*="cookie-layer"] button[class*="decline"],\
- div[id*="cookie-layer"] button[class*="settings"]',
-
- 'div[class*="cookie-section"] button[class*="reject"],\
- div[class*="cookie-section"] button[class*="decline"],\
- div[class*="cookie-section"] button[class*="settings"],\
- div[id*="cookie-section"] button[class*="reject"],\
- div[id*="cookie-section"] button[class*="decline"],\
- div[id*="cookie-section"] button[class*="settings"]',
-
- 'div[class*="cookie-container"] button[class*="reject"],\
- div[class*="cookie-container"] button[class*="decline"],\
- div[class*="cookie-container"] button[class*="settings"],\
- div[id*="cookie-container"] button[class*="reject"],\
- div[id*="cookie-container"] button[class*="decline"],\
- div[id*="cookie-container"] button[class*="settings"]',
-
- '[data-purpose*="cookie"] button[data-purpose*="reject"],\
- [data-purpose*="cookie"] button[data-purpose*="decline"],\
- [data-purpose*="cookie"] button[data-purpose*="settings"],\
- [data-ref*="cookie"] button[data-ref*="reject"],\
- [data-ref*="cookie"] button[data-ref*="decline"],\
- [data-ref*="cookie"] button[data-ref*="settings"]',
-
- '[id*="cookie-manager"] button[id*="reject"],\
- [id*="cookie-manager"] button[id*="decline"],\
- [id*="cookie-manager"] button[id*="settings"],\
- [id*="cookie-control"] button[id*="reject"],\
- [id*="cookie-control"] button[id*="decline"],\
- [id*="cookie-control"] button[id*="settings"]',
-
- 'div[class*="vn-cookie"] button[class*="reject"],\
- div[class*="vn-cookie"] button[class*="decline"],\
- div[class*="vn-cookie"] button[class*="settings"],\
- div[id*="vn-cookie"] button[class*="reject"],\
- div[id*="vn-cookie"] button[class*="decline"],\
- div[id*="vn-cookie"] button[class*="settings"]',
-
- 'div[class*="ecommerce"] button[class*="cookie-reject"],\
- div[class*="ecommerce"] button[class*="cookie-decline"],\
- div[class*="ecommerce"] button[class*="cookie-settings"],\
- div[id*="ecommerce"] button[class*="cookie-reject"],\
- div[id*="ecommerce"] button[class*="cookie-decline"],\
- div[id*="ecommerce"] button[class*="cookie-settings"]',
-
- 'div[class*="news"] button[class*="cookie-reject"],\
- div[class*="news"] button[class*="cookie-decline"],\
- div[class*="news"] button[class*="cookie-settings"],\
- div[id*="news"] button[class*="cookie-reject"],\
- div[id*="news"] button[class*="cookie-decline"],\
- div[id*="news"] button[class*="cookie-settings"]',
-
- 'div[class*="retail"] button[class*="cookie-reject"],\
- div[class*="retail"] button[class*="cookie-decline"],\
- div[class*="retail"] button[class*="cookie-settings"],\
- div[id*="retail"] button[class*="cookie-reject"],\
- div[id*="retail"] button[class*="cookie-decline"],\
- div[id*="retail"] button[class*="cookie-settings"]',
-
- 'div[class*="gdpr"] button[class*="reject"],\
- div[class*="gdpr"] button[class*="decline"],\
- div[class*="gdpr"] button[class*="settings"],\
- div[id*="gdpr"] button[class*="reject"],\
- div[id*="gdpr"] button[class*="decline"],\
- div[id*="gdpr"] button[class*="settings"]',
-
- 'div[class*="privacy"] button[class*="reject"],\
- div[class*="privacy"] button[class*="decline"],\
- div[class*="privacy"] button[class*="settings"],\
- div[id*="privacy"] button[class*="reject"],\
- div[id*="privacy"] button[class*="decline"],\
- div[id*="privacy"] button[class*="settings"]',
-
- 'div[class*="bank"] button[class*="cookie-reject"],\
- div[class*="bank"] button[class*="cookie-decline"],\
- div[class*="bank"] button[class*="cookie-settings"],\
- div[id*="bank"] button[class*="cookie-reject"],\
- div[id*="bank"] button[class*="cookie-decline"],\
- div[id*="bank"] button[class*="cookie-settings"]',
-
- 'div[class*="consent"] button[class*="reject"],\
- div[class*="consent"] button[class*="decline"],\
- div[class*="consent"] button[class*="settings"],\
- div[id*="consent"] button[class*="reject"],\
- div[id*="consent"] button[class*="decline"],\
- div[id*="consent"] button[class*="settings"]',
-
- 'div[class*="notice"] button[class*="reject"],\
- div[class*="notice"] button[class*="decline"],\
- div[class*="notice"] button[class*="settings"],\
- div[id*="notice"] button[class*="reject"],\
- div[id*="notice"] button[class*="decline"],\
- div[id*="notice"] button[class*="settings"]',
-
- 'div[class*="popup"] button[class*="reject"],\
- div[class*="popup"] button[class*="decline"],\
- div[class*="popup"] button[class*="settings"],\
- div[id*="popup"] button[class*="reject"],\
- div[id*="popup"] button[class*="decline"],\
- div[id*="popup"] button[class*="settings"]',
-
- 'div[class*="eu-cookie-banner"] button[class*="reject"],\
- div[class*="eu-cookie-banner"] button[class*="settings"]',
-
- 'div[class*="gdpr-notice"] button[class*="reject"],\
- div[class*="gdpr-notice"] button[class*="settings"]',
-
- 'div[class*="privacy-consent"] button[class*="reject"],\
- div[class*="privacy-consent"] button[class*="settings"]',
-
- 'div[class*="asia"] button[class*="cookie-reject"],\
- div[class*="asia"] button[class*="cookie-decline"],\
- div[class*="asia"] button[class*="cookie-settings"]',
-
- 'div[class*="europe"] button[class*="cookie-reject"],\
- div[class*="europe"] button[class*="cookie-decline"],\
- div[class*="europe"] button[class*="cookie-settings"]',
-
- 'div[class*="global"] button[class*="cookie-reject"],\
- div[class*="global"] button[class*="cookie-decline"],\
- div[class*="global"] button[class*="cookie-settings"]',
-
- 'div[class*="america"] button[class*="cookie-reject"],\
- div[class*="america"] button[class*="cookie-decline"],\
- div[class*="america"] button[class*="cookie-settings"]',
-
- 'div[class*="oceania"] button[class*="cookie-reject"],\
- div[class*="oceania"] button[class*="cookie-decline"],\
- div[class*="oceania"] button[class*="cookie-settings"]',
- ];
-
- let currentChainElement = 0;
- const classname = Math.random()
- .toString(36)
- .replace(/[^a-z]+/g, '');
-
- // Search loop function
- let searchGroupsLength = searchGroups.length,
- searchPairsKeys = Object.keys(searchPairs),
- searchPairsJoinedKeys = searchPairsKeys.join(','),
- timeoutDuration = 300;
-
- function querySelectorAllShadowRoot(selector, root = document) {
- const elements = [];
- const findElements = node => {
- if (node.shadowRoot) {
- node.shadowRoot.querySelectorAll(selector).forEach(el => elements.push(el));
- node.shadowRoot.querySelectorAll('*').forEach(findElements);
- }
- };
- root.querySelectorAll('*').forEach(findElements);
- return elements;
- }
-
- function searchLoop(counter) {
- if (document.cookie.indexOf('cookie_consent') !== -1) {
- return;
- }
-
- const dynamicTimeout = Math.min(timeoutDuration * (counter + 1), 2000);
-
- setTimeout(function () {
- document.querySelectorAll(searchPairsJoinedKeys).forEach(function (box) {
- searchPairsKeys.forEach(function (selector) {
- if (box.matches(selector)) {
- const shadowElements = querySelectorAllShadowRoot(searchPairs[selector].join(','), box);
- shadowElements.forEach(button => {
- if (button.click && !button.classList.contains(classname)) {
- button.classList.add(classname);
-
- if (typeof chrome == 'object' && chrome.runtime) chrome.runtime.sendMessage({ command: 'cookie_warning_dismissed', url: document.location.href });
-
- button.click();
-
- if (selector != '.message-container' && button.getAttribute('href') != '#cookieman-settings')
- setTimeout(function () {
- if (button) button.click();
- }, 500);
-
- timeoutDuration += 500;
- }
- });
- }
- });
- });
-
- document.querySelectorAll(searchGroups[counter % searchGroupsLength]).forEach(function (element) {
- if (element.click && !element.classList.contains(classname)) {
- element.classList.add(classname);
-
- if (typeof chrome == 'object' && chrome.runtime) chrome.runtime.sendMessage({ command: 'cookie_warning_dismissed', url: document.location.href });
-
- element.click();
-
- if (element.getAttribute('aria-pressed') != 'true')
- setTimeout(function () {
- if (element) element.click();
- }, 500);
-
- timeoutDuration += 500;
- }
- });
-
- if (counter < 100 * searchGroupsLength) {
- searchLoop(counter + 1);
- }
- }, dynamicTimeout);
- }
-
- // Embeds handling
- function handleEmbeds() {
- var l = document.location,
- is_audioboom = false,
- is_dailymotion = false,
- is_dailybuzz = false,
- is_playerclipslaliga = false;
-
- switch (l.hostname) {
- case 'embeds.audioboom.com':
- is_audioboom = true;
- break;
-
- case 'dailymotion.com':
- case 'www.dailymotion.com':
- is_dailymotion = l.pathname.indexOf('/embed') === 0;
- break;
-
- case 'geo.dailymotion.com':
- is_dailymotion = l.pathname.indexOf('/player') === 0;
- break;
-
- case 'dailybuzz.nl':
- is_dailybuzz = l.pathname.indexOf('/buzz/embed') === 0;
- break;
-
- case 'playerclipslaliga.tv':
- is_playerclipslaliga = true;
- break;
- }
-
- function searchEmbeds() {
- setTimeout(function () {
- if (is_audioboom) {
- document.querySelectorAll('div[id^="cookie-modal"] .modal[style*="block"] .btn.mrs:not(.' + classname + ')').forEach(function (button) {
- button.className += ' ' + classname;
- button.click();
- });
- } else if (is_dailymotion) {
- document.querySelectorAll('.np_DialogConsent-accept:not(.' + classname + '), .consent_screen-accept:not(.' + classname + ')').forEach(function (button) {
- button.className += ' ' + classname;
- button.click();
- });
- } else if (is_dailybuzz) {
- document.querySelectorAll('#ask-consent #accept:not(.' + classname + ')').forEach(function (button) {
- button.className += ' ' + classname;
- button.click();
- });
- } else if (is_playerclipslaliga) {
- document.querySelectorAll('#cookies button[onclick*="saveCookiesSelection"]:not(.' + classname + ')').forEach(function (button) {
- button.className += ' ' + classname;
- button.click();
- });
- } else {
- return;
- }
-
- searchEmbeds();
- }, 1000);
- }
-
- searchEmbeds();
- }
-
- // Initialize
- var start = setInterval(function () {
- var html = document.querySelector('html');
-
- if (!html || /idc0_350/.test(html.className)) return;
-
- clearInterval(start);
-
- html.className += ' idc0_350';
- searchLoop(0);
- handleEmbeds();
- }, 500);
-
- var hostname = document.location.hostname.replace(/^w{2,3}\d*\./i, ''),
- items = getItem(hostname);
-
- if (items) {
- (items instanceof Array ? items : [items]).forEach(function (item) {
- let value = localStorage.getItem(item.key);
- if (value == null || (item.strict && value != item.value)) {
- localStorage.setItem(item.key, item.value);
- counter++;
- }
- });
-
- if (counter > 0) document.location.reload();
- }
-})();
diff --git a/home/programs/qutebrowser/greasemonkey/return-youtube-dislike.user.js b/home/programs/qutebrowser/greasemonkey/return-youtube-dislike.user.js
deleted file mode 100644
index 50f3eff..0000000
--- a/home/programs/qutebrowser/greasemonkey/return-youtube-dislike.user.js
+++ /dev/null
@@ -1,704 +0,0 @@
-// ==UserScript==
-// @name Return YouTube Dislike
-// @namespace https://www.returnyoutubedislike.com/
-// @homepage https://www.returnyoutubedislike.com/
-// @version 3.1.5
-// @encoding utf-8
-// @description Return of the YouTube Dislike, Based off https://www.returnyoutubedislike.com/
-// @icon https://github.com/Anarios/return-youtube-dislike/raw/main/Icons/Return%20Youtube%20Dislike%20-%20Transparent.png
-// @author Anarios & JRWR
-// @match *://*.youtube.com/*
-// @exclude *://music.youtube.com/*
-// @exclude *://*.music.youtube.com/*
-// @compatible chrome
-// @compatible firefox
-// @compatible opera
-// @compatible safari
-// @compatible edge
-// @grant GM.xmlHttpRequest
-// @connect youtube.com
-// @grant GM_addStyle
-// @run-at document-end
-// @downloadURL https://update.greasyfork.org/scripts/436115/Return%20YouTube%20Dislike.user.js
-// @updateURL https://update.greasyfork.org/scripts/436115/Return%20YouTube%20Dislike.meta.js
-// ==/UserScript==
-
-const extConfig = {
- // BEGIN USER OPTIONS
- // You may change the following variables to allowed values listed in the corresponding brackets (* means default). Keep the style and keywords intact.
- showUpdatePopup: false, // [true, false*] Show a popup tab after extension update (See what's new)
- disableVoteSubmission: false, // [true, false*] Disable like/dislike submission (Stops counting your likes and dislikes)
- disableLogging: true, // [true*, false] Disable Logging API Response in JavaScript Console.
- coloredThumbs: false, // [true, false*] Colorize thumbs (Use custom colors for thumb icons)
- coloredBar: false, // [true, false*] Colorize ratio bar (Use custom colors for ratio bar)
- colorTheme: "classic", // [classic*, accessible, neon] Color theme (red/green, blue/yellow, pink/cyan)
- numberDisplayFormat: "compactShort", // [compactShort*, compactLong, standard] Number format (For non-English locale users, you may be able to improve appearance with a different option. Please file a feature request if your locale is not covered)
- numberDisplayRoundDown: true, // [true*, false] Round down numbers (Show rounded down numbers)
- tooltipPercentageMode: "none", // [none*, dash_like, dash_dislike, both, only_like, only_dislike] Mode of showing percentage in like/dislike bar tooltip.
- numberDisplayReformatLikes: false, // [true, false*] Re-format like numbers (Make likes and dislikes format consistent)
- rateBarEnabled: false, // [true, false*] Enables ratio bar under like/dislike buttons
- // END USER OPTIONS
-};
-
-const LIKED_STATE = "LIKED_STATE";
-const DISLIKED_STATE = "DISLIKED_STATE";
-const NEUTRAL_STATE = "NEUTRAL_STATE";
-let previousState = 3; //1=LIKED, 2=DISLIKED, 3=NEUTRAL
-let likesvalue = 0;
-let dislikesvalue = 0;
-let preNavigateLikeButton = null;
-
-let isMobile = location.hostname == "m.youtube.com";
-let isShorts = () => location.pathname.startsWith("/shorts");
-let mobileDislikes = 0;
-function cLog(text, subtext = "") {
- if (!extConfig.disableLogging) {
- subtext = subtext.trim() === "" ? "" : `(${subtext})`;
- console.log(`[Return YouTube Dislikes] ${text} ${subtext}`);
- }
-}
-
-function isInViewport(element) {
- const rect = element.getBoundingClientRect();
- const height = innerHeight || document.documentElement.clientHeight;
- const width = innerWidth || document.documentElement.clientWidth;
- return (
- // When short (channel) is ignored, the element (like/dislike AND short itself) is
- // hidden with a 0 DOMRect. In this case, consider it outside of Viewport
- !(rect.top == 0 && rect.left == 0 && rect.bottom == 0 && rect.right == 0) &&
- rect.top >= 0 &&
- rect.left >= 0 &&
- rect.bottom <= height &&
- rect.right <= width
- );
-}
-
-function getButtons() {
- if (isShorts()) {
- let elements = document.querySelectorAll(
- isMobile ? "ytm-like-button-renderer" : "#like-button > ytd-like-button-renderer",
- );
- for (let element of elements) {
- if (isInViewport(element)) {
- return element;
- }
- }
- }
- if (isMobile) {
- return (
- document.querySelector(".slim-video-action-bar-actions .segmented-buttons") ??
- document.querySelector(".slim-video-action-bar-actions")
- );
- }
- if (document.getElementById("menu-container")?.offsetParent === null) {
- return (
- document.querySelector("ytd-menu-renderer.ytd-watch-metadata > div") ??
- document.querySelector("ytd-menu-renderer.ytd-video-primary-info-renderer > div")
- );
- } else {
- return document.getElementById("menu-container")?.querySelector("#top-level-buttons-computed");
- }
-}
-
-function getDislikeButton() {
- if (getButtons().children[0].tagName === "YTD-SEGMENTED-LIKE-DISLIKE-BUTTON-RENDERER") {
- if (getButtons().children[0].children[1] === undefined) {
- return document.querySelector("#segmented-dislike-button");
- } else {
- return getButtons().children[0].children[1];
- }
- } else {
- if (getButtons().querySelector("segmented-like-dislike-button-view-model")) {
- const dislikeViewModel = getButtons().querySelector("dislike-button-view-model");
- if (!dislikeViewModel) cLog("Dislike button wasn't added to DOM yet...");
- return dislikeViewModel;
- } else {
- return getButtons().children[1];
- }
- }
-}
-
-function getLikeButton() {
- return getButtons().children[0].tagName === "YTD-SEGMENTED-LIKE-DISLIKE-BUTTON-RENDERER"
- ? document.querySelector("#segmented-like-button") !== null
- ? document.querySelector("#segmented-like-button")
- : getButtons().children[0].children[0]
- : getButtons().querySelector("like-button-view-model") ?? getButtons().children[0];
-}
-
-function getLikeTextContainer() {
- return (
- getLikeButton().querySelector("#text") ??
- getLikeButton().getElementsByTagName("yt-formatted-string")[0] ??
- getLikeButton().querySelector("span[role='text']")
- );
-}
-
-function getDislikeTextContainer() {
- const dislikeButton = getDislikeButton();
- let result =
- dislikeButton?.querySelector("#text") ??
- dislikeButton?.getElementsByTagName("yt-formatted-string")[0] ??
- dislikeButton?.querySelector("span[role='text']");
- if (result === null) {
- let textSpan = document.createElement("span");
- textSpan.id = "text";
- textSpan.style.marginLeft = "6px";
- dislikeButton?.querySelector("button").appendChild(textSpan);
- if (dislikeButton) dislikeButton.querySelector("button").style.width = "auto";
- result = textSpan;
- }
- return result;
-}
-
-function createObserver(options, callback) {
- const observerWrapper = new Object();
- observerWrapper.options = options;
- observerWrapper.observer = new MutationObserver(callback);
- observerWrapper.observe = function (element) {
- this.observer.observe(element, this.options);
- };
- observerWrapper.disconnect = function () {
- this.observer.disconnect();
- };
- return observerWrapper;
-}
-
-let shortsObserver = null;
-
-if (isShorts() && !shortsObserver) {
- cLog("Initializing shorts mutation observer");
- shortsObserver = createObserver(
- {
- attributes: true,
- },
- (mutationList) => {
- mutationList.forEach((mutation) => {
- if (
- mutation.type === "attributes" &&
- mutation.target.nodeName === "TP-YT-PAPER-BUTTON" &&
- mutation.target.id === "button"
- ) {
- cLog("Short thumb button status changed");
- if (mutation.target.getAttribute("aria-pressed") === "true") {
- mutation.target.style.color =
- mutation.target.parentElement.parentElement.id === "like-button"
- ? getColorFromTheme(true)
- : getColorFromTheme(false);
- } else {
- mutation.target.style.color = "unset";
- }
- return;
- }
- cLog("Unexpected mutation observer event: " + mutation.target + mutation.type);
- });
- },
- );
-}
-
-function isVideoLiked() {
- if (isMobile) {
- return getLikeButton().querySelector("button").getAttribute("aria-label") == "true";
- }
- return getLikeButton().classList.contains("style-default-active");
-}
-
-function isVideoDisliked() {
- if (isMobile) {
- return getDislikeButton()?.querySelector("button").getAttribute("aria-label") == "true";
- }
- return getDislikeButton()?.classList.contains("style-default-active");
-}
-
-function isVideoNotLiked() {
- if (isMobile) {
- return !isVideoLiked();
- }
- return getLikeButton().classList.contains("style-text");
-}
-
-function isVideoNotDisliked() {
- if (isMobile) {
- return !isVideoDisliked();
- }
- return getDislikeButton()?.classList.contains("style-text");
-}
-
-function checkForUserAvatarButton() {
- if (isMobile) {
- return;
- }
- if (document.querySelector("#avatar-btn")) {
- return true;
- } else {
- return false;
- }
-}
-
-function getState() {
- if (isVideoLiked()) {
- return LIKED_STATE;
- }
- if (isVideoDisliked()) {
- return DISLIKED_STATE;
- }
- return NEUTRAL_STATE;
-}
-
-function setLikes(likesCount) {
- if (isMobile) {
- getButtons().children[0].querySelector(".button-renderer-text").innerText = likesCount;
- return;
- }
- getLikeTextContainer().innerText = likesCount;
-}
-
-function setDislikes(dislikesCount) {
- if (isMobile) {
- mobileDislikes = dislikesCount;
- return;
- }
-
- const _container = getDislikeTextContainer();
- _container?.removeAttribute("is-empty");
- if (_container?.innerText !== dislikesCount) {
- _container.innerText = dislikesCount;
- }
-}
-
-function getLikeCountFromButton() {
- try {
- if (isShorts()) {
- //Youtube Shorts don't work with this query. It's not necessary; we can skip it and still see the results.
- //It should be possible to fix this function, but it's not critical to showing the dislike count.
- return false;
- }
- let likeButton =
- getLikeButton().querySelector("yt-formatted-string#text") ?? getLikeButton().querySelector("button");
-
- let likesStr = likeButton.getAttribute("aria-label").replace(/\D/g, "");
- return likesStr.length > 0 ? parseInt(likesStr) : false;
- } catch {
- return false;
- }
-}
-
-(typeof GM_addStyle != "undefined"
- ? GM_addStyle
- : (styles) => {
- let styleNode = document.createElement("style");
- styleNode.type = "text/css";
- styleNode.innerText = styles;
- document.head.appendChild(styleNode);
- })(`
- #return-youtube-dislike-bar-container {
- background: var(--yt-spec-icon-disabled);
- border-radius: 2px;
- }
-
- #return-youtube-dislike-bar {
- background: var(--yt-spec-text-primary);
- border-radius: 2px;
- transition: all 0.15s ease-in-out;
- }
-
- .ryd-tooltip {
- position: absolute;
- display: block;
- height: 2px;
- bottom: -10px;
- }
-
- .ryd-tooltip-bar-container {
- width: 100%;
- height: 2px;
- position: absolute;
- padding-top: 6px;
- padding-bottom: 12px;
- top: -6px;
- }
-
- ytd-menu-renderer.ytd-watch-metadata {
- overflow-y: visible !important;
- }
-
- #top-level-buttons-computed {
- position: relative !important;
- }
- `);
-
-function createRateBar(likes, dislikes) {
- if (isMobile || !extConfig.rateBarEnabled) {
- return;
- }
- let rateBar = document.getElementById("return-youtube-dislike-bar-container");
-
- const widthPx = getLikeButton().clientWidth + (getDislikeButton()?.clientWidth ?? 52);
-
- const widthPercent = likes + dislikes > 0 ? (likes / (likes + dislikes)) * 100 : 50;
-
- var likePercentage = parseFloat(widthPercent.toFixed(1));
- const dislikePercentage = (100 - likePercentage).toLocaleString();
- likePercentage = likePercentage.toLocaleString();
-
- var tooltipInnerHTML;
- switch (extConfig.tooltipPercentageMode) {
- case "dash_like":
- tooltipInnerHTML = `${likes.toLocaleString()} / ${dislikes.toLocaleString()} - ${likePercentage}%`;
- break;
- case "dash_dislike":
- tooltipInnerHTML = `${likes.toLocaleString()} / ${dislikes.toLocaleString()} - ${dislikePercentage}%`;
- break;
- case "both":
- tooltipInnerHTML = `${likePercentage}% / ${dislikePercentage}%`;
- break;
- case "only_like":
- tooltipInnerHTML = `${likePercentage}%`;
- break;
- case "only_dislike":
- tooltipInnerHTML = `${dislikePercentage}%`;
- break;
- default:
- tooltipInnerHTML = `${likes.toLocaleString()} / ${dislikes.toLocaleString()}`;
- }
-
- if (!rateBar && !isMobile) {
- let colorLikeStyle = "";
- let colorDislikeStyle = "";
- if (extConfig.coloredBar) {
- colorLikeStyle = "; background-color: " + getColorFromTheme(true);
- colorDislikeStyle = "; background-color: " + getColorFromTheme(false);
- }
-
- getButtons().insertAdjacentHTML(
- "beforeend",
- `
-
-`,
- );
- let descriptionAndActionsElement = document.getElementById("top-row");
- descriptionAndActionsElement.style.borderBottom = "1px solid var(--yt-spec-10-percent-layer)";
- descriptionAndActionsElement.style.paddingBottom = "10px";
- } else {
- document.querySelector(".ryd-tooltip").style.width = widthPx + "px";
- document.getElementById("return-youtube-dislike-bar").style.width = widthPercent + "%";
-
- if (extConfig.coloredBar) {
- document.getElementById("return-youtube-dislike-bar-container").style.backgroundColor = getColorFromTheme(false);
- document.getElementById("return-youtube-dislike-bar").style.backgroundColor = getColorFromTheme(true);
- }
- }
-}
-
-function setState() {
- cLog("Fetching votes...");
- let statsSet = false;
-
- fetch(`https://returnyoutubedislikeapi.com/votes?videoId=${getVideoId()}`).then((response) => {
- response.json().then((json) => {
- if (json && !("traceId" in response) && !statsSet) {
- const { dislikes, likes } = json;
- cLog(`Received count: ${dislikes}`);
- likesvalue = likes;
- dislikesvalue = dislikes;
- setDislikes(numberFormat(dislikes));
- if (extConfig.numberDisplayReformatLikes === true) {
- const nativeLikes = getLikeCountFromButton();
- if (nativeLikes !== false) {
- setLikes(numberFormat(nativeLikes));
- }
- }
- createRateBar(likes, dislikes);
- if (extConfig.coloredThumbs === true) {
- const dislikeButton = getDislikeButton();
- if (isShorts()) {
- // for shorts, leave deactived buttons in default color
- const shortLikeButton = getLikeButton().querySelector("tp-yt-paper-button#button");
- const shortDislikeButton = dislikeButton?.querySelector("tp-yt-paper-button#button");
- if (shortLikeButton.getAttribute("aria-pressed") === "true") {
- shortLikeButton.style.color = getColorFromTheme(true);
- }
- if (shortDislikeButton && shortDislikeButton.getAttribute("aria-pressed") === "true") {
- shortDislikeButton.style.color = getColorFromTheme(false);
- }
- shortsObserver.observe(shortLikeButton);
- shortsObserver.observe(shortDislikeButton);
- } else {
- getLikeButton().style.color = getColorFromTheme(true);
- if (dislikeButton) dislikeButton.style.color = getColorFromTheme(false);
- }
- }
- }
- });
- });
-}
-
-function updateDOMDislikes() {
- setDislikes(numberFormat(dislikesvalue));
- createRateBar(likesvalue, dislikesvalue);
-}
-
-function likeClicked() {
- if (checkForUserAvatarButton() == true) {
- if (previousState == 1) {
- likesvalue--;
- updateDOMDislikes();
- previousState = 3;
- } else if (previousState == 2) {
- likesvalue++;
- dislikesvalue--;
- updateDOMDislikes();
- previousState = 1;
- } else if (previousState == 3) {
- likesvalue++;
- updateDOMDislikes();
- previousState = 1;
- }
- if (extConfig.numberDisplayReformatLikes === true) {
- const nativeLikes = getLikeCountFromButton();
- if (nativeLikes !== false) {
- setLikes(numberFormat(nativeLikes));
- }
- }
- }
-}
-
-function dislikeClicked() {
- if (checkForUserAvatarButton() == true) {
- if (previousState == 3) {
- dislikesvalue++;
- updateDOMDislikes();
- previousState = 2;
- } else if (previousState == 2) {
- dislikesvalue--;
- updateDOMDislikes();
- previousState = 3;
- } else if (previousState == 1) {
- likesvalue--;
- dislikesvalue++;
- updateDOMDislikes();
- previousState = 2;
- if (extConfig.numberDisplayReformatLikes === true) {
- const nativeLikes = getLikeCountFromButton();
- if (nativeLikes !== false) {
- setLikes(numberFormat(nativeLikes));
- }
- }
- }
- }
-}
-
-function setInitialState() {
- setState();
-}
-
-function getVideoId() {
- const urlObject = new URL(window.location.href);
- const pathname = urlObject.pathname;
- if (pathname.startsWith("/clip")) {
- return (document.querySelector("meta[itemprop='videoId']") || document.querySelector("meta[itemprop='identifier']")).content;
- } else {
- if (pathname.startsWith("/shorts")) {
- return pathname.slice(8);
- }
- return urlObject.searchParams.get("v");
- }
-}
-
-function isVideoLoaded() {
- if (isMobile) {
- return document.getElementById("player").getAttribute("loading") == "false";
- }
- const videoId = getVideoId();
-
- return (
- // desktop: spring 2024 UI
- document.querySelector(`ytd-watch-grid[video-id='${videoId}']`) !== null ||
- // desktop: older UI
- document.querySelector(`ytd-watch-flexy[video-id='${videoId}']`) !== null ||
- // mobile: no video-id attribute
- document.querySelector('#player[loading="false"]:not([hidden])') !== null
- );
-}
-
-function roundDown(num) {
- if (num < 1000) return num;
- const int = Math.floor(Math.log10(num) - 2);
- const decimal = int + (int % 3 ? 1 : 0);
- const value = Math.floor(num / 10 ** decimal);
- return value * 10 ** decimal;
-}
-
-function numberFormat(numberState) {
- let numberDisplay;
- if (extConfig.numberDisplayRoundDown === false) {
- numberDisplay = numberState;
- } else {
- numberDisplay = roundDown(numberState);
- }
- return getNumberFormatter(extConfig.numberDisplayFormat).format(numberDisplay);
-}
-
-function getNumberFormatter(optionSelect) {
- let userLocales;
- if (document.documentElement.lang) {
- userLocales = document.documentElement.lang;
- } else if (navigator.language) {
- userLocales = navigator.language;
- } else {
- try {
- userLocales = new URL(
- Array.from(document.querySelectorAll("head > link[rel='search']"))
- ?.find((n) => n?.getAttribute("href")?.includes("?locale="))
- ?.getAttribute("href"),
- )?.searchParams?.get("locale");
- } catch {
- cLog("Cannot find browser locale. Use en as default for number formatting.");
- userLocales = "en";
- }
- }
-
- let formatterNotation;
- let formatterCompactDisplay;
- switch (optionSelect) {
- case "compactLong":
- formatterNotation = "compact";
- formatterCompactDisplay = "long";
- break;
- case "standard":
- formatterNotation = "standard";
- formatterCompactDisplay = "short";
- break;
- case "compactShort":
- default:
- formatterNotation = "compact";
- formatterCompactDisplay = "short";
- }
-
- const formatter = Intl.NumberFormat(userLocales, {
- notation: formatterNotation,
- compactDisplay: formatterCompactDisplay,
- });
- return formatter;
-}
-
-function getColorFromTheme(voteIsLike) {
- let colorString;
- switch (extConfig.colorTheme) {
- case "accessible":
- if (voteIsLike === true) {
- colorString = "dodgerblue";
- } else {
- colorString = "gold";
- }
- break;
- case "neon":
- if (voteIsLike === true) {
- colorString = "aqua";
- } else {
- colorString = "magenta";
- }
- break;
- case "classic":
- default:
- if (voteIsLike === true) {
- colorString = "lime";
- } else {
- colorString = "red";
- }
- }
- return colorString;
-}
-
-let smartimationObserver = null;
-
-function setEventListeners(evt) {
- let jsInitChecktimer;
-
- function checkForJS_Finish() {
- //console.log();
- if (isShorts() || (getButtons()?.offsetParent && isVideoLoaded())) {
- const buttons = getButtons();
- const dislikeButton = getDislikeButton();
-
- if (preNavigateLikeButton !== getLikeButton() && dislikeButton) {
- cLog("Registering button listeners...");
- try {
- getLikeButton().addEventListener("click", likeClicked);
- dislikeButton?.addEventListener("click", dislikeClicked);
- getLikeButton().addEventListener("touchstart", likeClicked);
- dislikeButton?.addEventListener("touchstart", dislikeClicked);
- dislikeButton?.addEventListener("focusin", updateDOMDislikes);
- dislikeButton?.addEventListener("focusout", updateDOMDislikes);
- preNavigateLikeButton = getLikeButton();
-
- if (!smartimationObserver) {
- smartimationObserver = createObserver(
- {
- attributes: true,
- subtree: true,
- childList: true,
- },
- updateDOMDislikes,
- );
- smartimationObserver.container = null;
- }
-
- const smartimationContainer = buttons.querySelector("yt-smartimation");
- if (smartimationContainer && smartimationObserver.container != smartimationContainer) {
- cLog("Initializing smartimation mutation observer");
- smartimationObserver.disconnect();
- smartimationObserver.observe(smartimationContainer);
- smartimationObserver.container = smartimationContainer;
- }
- } catch {
- return;
- } //Don't spam errors into the console
- }
- if (dislikeButton) {
- setInitialState();
- clearInterval(jsInitChecktimer);
- }
- }
- }
-
- cLog("Setting up...");
- jsInitChecktimer = setInterval(checkForJS_Finish, 111);
-}
-
-(function () {
- "use strict";
- window.addEventListener("yt-navigate-finish", setEventListeners, true);
- setEventListeners();
-})();
-if (isMobile) {
- let originalPush = history.pushState;
- history.pushState = function (...args) {
- window.returnDislikeButtonlistenersSet = false;
- setEventListeners(args[2]);
- return originalPush.apply(history, args);
- };
- setInterval(() => {
- const dislikeButton = getDislikeButton();
- if (dislikeButton?.querySelector(".button-renderer-text") === null) {
- getDislikeTextContainer().innerText = mobileDislikes;
- } else {
- if (dislikeButton) dislikeButton.querySelector(".button-renderer-text").innerText = mobileDislikes;
- }
- }, 1000);
-}
diff --git a/home/programs/qutebrowser/greasemonkey/sponsorblock-lite.user.js b/home/programs/qutebrowser/greasemonkey/sponsorblock-lite.user.js
deleted file mode 100644
index 765097d..0000000
--- a/home/programs/qutebrowser/greasemonkey/sponsorblock-lite.user.js
+++ /dev/null
@@ -1,1146 +0,0 @@
-// ==UserScript==
-// @name SponsorBlock Lite
-// @name:en SponsorBlock Lite - Auto-skip sponsor segments on YouTube and Bilibili
-// @name:zh-CN SponsorBlock Lite - 自动跳过 YouTube/Bilibili 赞助内容
-// @name:zh-TW SponsorBlock Lite - 自動跳過 YouTube/Bilibili 贊助內容
-// @name:ja SponsorBlock Lite - YouTube/Bilibili スポンサー自動スキップ
-// @name:ko SponsorBlock Lite - YouTube/Bilibili 스폰서 자동 건너뛰기
-// @name:de SponsorBlock Lite - YouTube/Bilibili Sponsoren überspringen
-// @name:fr SponsorBlock Lite - Ignorer les sponsors YouTube/Bilibili
-// @name:es SponsorBlock Lite - Saltar patrocinadores YouTube/Bilibili
-// @name:it SponsorBlock Lite - Salta sponsor YouTube/Bilibili
-// @namespace https://github.com/hxueh
-// @version 1.1.1
-// @description Auto-skip sponsor segments on YouTube and Bilibili using SponsorBlock API
-// @description:en Auto-skip sponsor segments on YouTube and Bilibili using SponsorBlock API
-// @description:zh-CN 基于 SponsorBlock API 自动跳过 YouTube 和 Bilibili 视频中的赞助片段
-// @description:zh-TW 基於 SponsorBlock API 自動跳過 YouTube 和 Bilibili 影片中的贊助片段
-// @description:ja SponsorBlock API を使用して YouTube と Bilibili 動画のスポンサーセグメントを自動的にスキップします
-// @description:ko SponsorBlock API를 사용하여 YouTube 및 Bilibili 동영상의 스폰서 구간을 자동으로 건너뜁니다
-// @description:de Überspringen Sie Sponsorensegmente in YouTube- und Bilibili-Videos automatisch mit der SponsorBlock-API
-// @description:fr Ignorez automatiquement les segments sponsorisés dans les vidéos YouTube et Bilibili via l'API SponsorBlock
-// @description:es Salte automáticamente los segmentos de patrocinadores en videos de YouTube y Bilibili usando la API de SponsorBlock
-// @description:it Salta automaticamente i segmenti degli sponsor nei video di YouTube e Bilibili utilizzando l'API SponsorBlock
-// @author hxueh
-// @match https://www.youtube.com/*
-// @match https://music.youtube.com/*
-// @match https://m.youtube.com/*
-// @match https://*.bilibili.com/video/*
-// @icon https://sponsor.ajay.app/LogoSponsorBlock256px.png
-// @grant GM_xmlhttpRequest
-// @grant GM_addStyle
-// @connect sponsor.ajay.app
-// @connect bsbsb.top
-// @run-at document-idle
-// @license LGPL-3.0-or-later
-// @downloadURL https://update.greasyfork.org/scripts/560869/SponsorBlock%20Lite.user.js
-// @updateURL https://update.greasyfork.org/scripts/560869/SponsorBlock%20Lite.meta.js
-// ==/UserScript==
-
-(function () {
- "use strict";
-
- // ==================== CONSTANTS ====================
-
- // Platform detection (must be first for other constants to use)
- const IS_BILIBILI = window.location.hostname.includes("bilibili.com");
-
- const API_BASE_YOUTUBE = "https://sponsor.ajay.app";
- const API_BASE_BILIBILI = "https://bsbsb.top";
- const API_BASE = IS_BILIBILI ? API_BASE_BILIBILI : API_BASE_YOUTUBE;
- const CATEGORIES = [
- "sponsor",
- "selfpromo",
- "exclusive_access",
- "interaction",
- "outro",
- "music_offtopic",
- ];
- const ACTION_TYPES = ["skip", "full"];
- const SKIP_BUFFER = 0.003;
-
- // Colors for all categories (used in preview bar and category pill)
- const CATEGORY_COLORS = {
- sponsor: "#00d400",
- selfpromo: "#ffff00",
- exclusive_access: "#008a5c",
- interaction: "#cc00ff",
- outro: "#0202ed",
- music_offtopic: "#ff9900",
- };
-
- const CATEGORY_LABELS = {
- exclusive_access: "Exclusive Access",
- music_offtopic: "Music: Non-Music",
- };
-
- // ==================== STATE ====================
-
- let currentVideoID = null;
- let segments = [];
- let skippableSegments = [];
- let skipScheduleTimer = null;
- let video = null;
- let lastSkippedUUID = null;
- let currentSegmentIndex = 0;
- let videoChangeDebounce = null;
- let previewBarContainer = null;
- let videoDuration = 0;
- let lastUrl = location.href;
- let urlPollInterval = null;
- let videoObserver = null;
- let rafSkipId = null; // For requestAnimationFrame-based skipping
- let lastVideoSrc = null; // Track video element replacement
-
- // Platform detection
- const IS_MUSIC_YOUTUBE = window.location.hostname === "music.youtube.com";
- const IS_MOBILE_YOUTUBE = window.location.hostname === "m.youtube.com";
-
- // Vinegar detection - now a function that's called when needed
- let IS_VINEGAR = false;
-
- function updateVinegarDetection() {
- const hasVideo = document.querySelector("video") !== null;
- const hasYouTubePlayer = document.querySelector("#movie_player, ytm-player, #player") !== null;
- const hasYouTubeProgressBar = document.querySelector(".ytp-progress-bar, .progress-bar-line") !== null;
- // Vinegar: video exists but no YouTube player components
- const detected = hasVideo && !hasYouTubePlayer && !hasYouTubeProgressBar;
-
- if (detected && !IS_VINEGAR) {
- IS_VINEGAR = true;
- log("Vinegar/native video mode detected");
- }
-
- return IS_VINEGAR;
- }
-
- // ==================== CSS INJECTION ====================
-
- function injectStyles() {
- const css = `
- /* Desktop YouTube styles */
- #sb-lite-previewbar {
- position: absolute;
- width: 100%;
- height: 100%;
- padding: 0;
- margin: 0;
- overflow: visible;
- pointer-events: none;
- z-index: 42;
- list-style: none;
- transform: scaleY(0.6);
- transition: transform 0.1s cubic-bezier(0, 0, 0.2, 1);
- }
-
- /* Expand on hover (desktop) */
- .ytp-progress-bar:hover #sb-lite-previewbar {
- transform: scaleY(1);
- }
-
- /* Fullscreen mode (desktop) */
- .ytp-big-mode #sb-lite-previewbar {
- transform: scaleY(0.625);
- }
-
- .ytp-big-mode .ytp-progress-bar:hover #sb-lite-previewbar {
- transform: scaleY(1);
- }
-
- /* Mobile YouTube styles */
- .advancement-bar-line #sb-lite-previewbar,
- .advancement-bar #sb-lite-previewbar,
- .progress-bar-line #sb-lite-previewbar {
- position: absolute;
- width: 100%;
- height: 100%;
- top: 0;
- left: 0;
- padding: 0;
- margin: 0;
- overflow: visible;
- pointer-events: none;
- z-index: 42;
- list-style: none;
- transform: none;
- }
-
- .sb-lite-segment {
- position: absolute;
- height: 100%;
- min-width: 1px;
- display: inline-block;
- opacity: 0.7;
- }
-
- .sb-lite-segment:hover {
- opacity: 1;
- }
-
- #sb-lite-category-pill {
- display: none;
- align-items: center;
- padding: 4px 12px;
- border-radius: 4px;
- font-size: 12px;
- font-weight: 500;
- margin-left: 8px;
- color: white;
- font-family: Roboto, Arial, sans-serif;
- white-space: nowrap;
- cursor: default;
- user-select: none;
- }
-
- /* Mobile category pill adjustments */
- .ytm-slim-owner-container #sb-lite-category-pill,
- ytm-slim-owner-renderer #sb-lite-category-pill {
- font-size: 10px;
- padding: 2px 8px;
- margin-left: 4px;
- }
-
- /* Bilibili styles */
- .bpx-player-progress-wrap #sb-lite-previewbar,
- .bpx-player-progress #sb-lite-previewbar,
- .bilibili-player-video-progress #sb-lite-previewbar,
- .squirtle-progress-wrap #sb-lite-previewbar {
- position: absolute;
- width: 100%;
- height: 100%;
- top: 0;
- left: 0;
- padding: 0;
- margin: 0;
- overflow: visible;
- pointer-events: none;
- z-index: 42;
- list-style: none;
- transform: none;
- }
-
- /* Bilibili category pill adjustments */
- .video-title #sb-lite-category-pill,
- .video-info-title #sb-lite-category-pill {
- font-size: 12px;
- padding: 2px 8px;
- margin-left: 8px;
- }
- `;
-
- if (typeof GM_addStyle !== "undefined") {
- GM_addStyle(css);
- } else {
- const style = document.createElement("style");
- style.textContent = css;
- document.head.appendChild(style);
- }
- }
-
- // ==================== UTILITY FUNCTIONS ====================
-
- async function sha256(message) {
- const msgBuffer = new TextEncoder().encode(message);
- const hashBuffer = await crypto.subtle.digest("SHA-256", msgBuffer);
- const hashArray = Array.from(new Uint8Array(hashBuffer));
- return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
- }
-
- async function getHashPrefix(videoID) {
- const hash = await sha256(videoID);
- return hash.slice(0, 4);
- }
-
- function getBilibiliVideoID() {
- const url = window.location.href;
- const patterns = [
- /\/video\/([^/?#]+)/,
- /\/BV([^/?#]+)/,
- /bvid=([^&]+)/,
- ];
- for (const pattern of patterns) {
- const match = url.match(pattern);
- if (match) {
- let videoId = match[1];
- if (!videoId.startsWith("BV")) {
- videoId = "BV" + videoId;
- }
- return videoId;
- }
- }
- return null;
- }
-
- function getVideoID() {
- if (IS_BILIBILI) {
- return getBilibiliVideoID();
- }
-
- const url = new URL(window.location.href);
-
- const vParam = url.searchParams.get("v");
- if (vParam && /^[a-zA-Z0-9_-]{11}$/.test(vParam)) {
- return vParam;
- }
-
- const shortsMatch = url.pathname.match(/\/shorts\/([a-zA-Z0-9_-]{11})/);
- if (shortsMatch) return shortsMatch[1];
-
- const embedMatch = url.pathname.match(/\/embed\/([a-zA-Z0-9_-]{11})/);
- if (embedMatch) return embedMatch[1];
-
- const liveMatch = url.pathname.match(/\/live\/([a-zA-Z0-9_-]{11})/);
- if (liveMatch) return liveMatch[1];
-
- // Mobile watch URL pattern
- const watchMatch = url.pathname.match(/\/watch\/([a-zA-Z0-9_-]{11})/);
- if (watchMatch) return watchMatch[1];
-
- return null;
- }
-
- function getVideoDuration() {
- return video?.duration || 0;
- }
-
- function log(message, ...args) {
- console.log(
- `[SB Lite${IS_BILIBILI ? " Bilibili" : IS_VINEGAR ? " Vinegar" : IS_MOBILE_YOUTUBE ? " Mobile" : ""}]`,
- message,
- ...args,
- );
- }
-
- function logError(message, ...args) {
- console.error(
- `[SB Lite${IS_BILIBILI ? " Bilibili" : IS_VINEGAR ? " Vinegar" : IS_MOBILE_YOUTUBE ? " Mobile" : ""}]`,
- message,
- ...args,
- );
- }
-
- // ==================== API FUNCTIONS ====================
-
- function fetchSegments(videoID) {
- return new Promise(async (resolve) => {
- try {
- const hashPrefix = await getHashPrefix(videoID);
- const params = new URLSearchParams({
- categories: JSON.stringify(CATEGORIES),
- actionTypes: JSON.stringify(ACTION_TYPES),
- });
-
- GM_xmlhttpRequest({
- method: "GET",
- url: `${API_BASE}/api/skipSegments/${hashPrefix}?${params}`,
- headers: { Accept: "application/json" },
- onload(response) {
- if (response.status === 200) {
- try {
- const data = JSON.parse(response.responseText);
- const videoData = data.find((v) => v.videoID === videoID);
- const segs = videoData?.segments || [];
- segs.sort((a, b) => a.segment[0] - b.segment[0]);
- resolve(segs);
- } catch {
- resolve([]);
- }
- } else {
- resolve([]);
- }
- },
- onerror() {
- resolve([]);
- },
- });
- } catch {
- resolve([]);
- }
- });
- }
-
- // ==================== SKIP LOGIC ====================
-
- function computeSkippableSegments() {
- skippableSegments = segments.filter((s) => {
- if (s.actionType === "full") return false;
- if (s.category === "music_offtopic" && !IS_MUSIC_YOUTUBE) return false;
- return true;
- });
- currentSegmentIndex = 0;
- }
-
- function skipToTime(targetTime, retryCount = 0) {
- if (!video || targetTime === undefined) return false;
-
- const maxRetries = 3;
- const previousTime = video.currentTime;
-
- try {
- video.currentTime = targetTime;
-
- // On iOS/Vinegar, verify the skip worked after a short delay
- if (IS_VINEGAR && retryCount < maxRetries) {
- setTimeout(() => {
- // Check if we're still in a segment that should be skipped
- // (meaning the skip might have failed)
- const currentTime = video.currentTime;
- const timeDiff = Math.abs(currentTime - targetTime);
-
- // If we're more than 0.5s away from target and still before target,
- // the skip likely failed
- if (timeDiff > 0.5 && currentTime < targetTime - 0.5) {
- log(`Skip verification failed (attempt ${retryCount + 1}), retrying...`);
- skipToTime(targetTime, retryCount + 1);
- }
- }, 100);
- }
-
- return true;
- } catch (e) {
- logError("Skip failed:", e);
- return false;
- }
- }
-
- function findNextSegment(currentTime) {
- if (
- currentSegmentIndex > 0 &&
- skippableSegments[currentSegmentIndex - 1] &&
- currentTime < skippableSegments[currentSegmentIndex - 1].segment[0]
- ) {
- currentSegmentIndex = 0;
- }
-
- while (currentSegmentIndex < skippableSegments.length) {
- const seg = skippableSegments[currentSegmentIndex];
- if (currentTime < seg.segment[1] - SKIP_BUFFER) {
- return { segment: seg, index: currentSegmentIndex };
- }
- currentSegmentIndex++;
- }
- return null;
- }
-
- // RAF-based skip loop for Vinegar (more responsive than timeupdate)
- function startRAFSkipLoop() {
- if (rafSkipId) {
- cancelAnimationFrame(rafSkipId);
- }
-
- function checkAndSkip() {
- if (!video || !skippableSegments.length) {
- rafSkipId = null;
- return;
- }
-
- // Check for video element replacement
- if (IS_VINEGAR) {
- const currentVideo = document.querySelector("video");
- if (currentVideo && currentVideo !== video) {
- log("Video element replaced, re-attaching...");
- video = currentVideo;
- setupVideoListeners();
- }
- }
-
- if (!video.paused) {
- const currentTime = video.currentTime;
-
- for (const seg of skippableSegments) {
- const [startTime, endTime] = seg.segment;
- if (
- currentTime >= startTime - SKIP_BUFFER &&
- currentTime < endTime - SKIP_BUFFER &&
- lastSkippedUUID !== seg.UUID
- ) {
- lastSkippedUUID = seg.UUID;
- log(`Skipping ${seg.category} segment at ${currentTime.toFixed(2)}s -> ${endTime.toFixed(2)}s`);
- skipToTime(endTime);
- break;
- }
- }
- }
-
- rafSkipId = requestAnimationFrame(checkAndSkip);
- }
-
- rafSkipId = requestAnimationFrame(checkAndSkip);
- }
-
- function stopRAFSkipLoop() {
- if (rafSkipId) {
- cancelAnimationFrame(rafSkipId);
- rafSkipId = null;
- }
- }
-
- function scheduleSkips() {
- // For Vinegar/iOS, use RAF-based skipping for better responsiveness
- if (IS_VINEGAR || IS_MOBILE_YOUTUBE) {
- if (!video?.paused && skippableSegments.length > 0) {
- startRAFSkipLoop();
- }
- return;
- }
-
- // Desktop: use timer-based approach
- if (skipScheduleTimer) {
- clearTimeout(skipScheduleTimer);
- skipScheduleTimer = null;
- }
-
- if (!video || video.paused || !skippableSegments.length) return;
-
- const currentTime = video.currentTime;
- const result = findNextSegment(currentTime);
-
- if (!result) return;
-
- const { segment: nextSegment } = result;
- const [startTime, endTime] = nextSegment.segment;
-
- if (currentTime >= startTime - SKIP_BUFFER) {
- if (lastSkippedUUID !== nextSegment.UUID) {
- lastSkippedUUID = nextSegment.UUID;
- log(`Skipping ${nextSegment.category} segment`);
- skipToTime(endTime);
- currentSegmentIndex++;
- }
- setTimeout(scheduleSkips, 50);
- return;
- }
-
- const timeUntilStart = (startTime - currentTime) / video.playbackRate;
- const delayMs = Math.max(0, timeUntilStart * 1000 - 50);
-
- skipScheduleTimer = setTimeout(() => {
- if (!video || video.paused) return;
-
- const nowTime = video.currentTime;
- if (
- nowTime >= startTime - SKIP_BUFFER &&
- nowTime < endTime - SKIP_BUFFER
- ) {
- if (lastSkippedUUID !== nextSegment.UUID) {
- lastSkippedUUID = nextSegment.UUID;
- log(`Skipping ${nextSegment.category} segment`);
- skipToTime(endTime);
- currentSegmentIndex++;
- }
- }
- scheduleSkips();
- }, delayMs);
- }
-
- // ==================== PREVIEW BAR ====================
-
- function createPreviewBar() {
- const container = document.createElement("ul");
- container.id = "sb-lite-previewbar";
- return container;
- }
-
- function createSegmentBar(segment, duration) {
- const bar = document.createElement("li");
- bar.className = "sb-lite-segment";
-
- const startTime = segment.segment[0];
- const endTime = Math.min(segment.segment[1], duration);
-
- const startPercent = (startTime / duration) * 100;
- const endPercent = (endTime / duration) * 100;
-
- bar.style.left = `${startPercent}%`;
- bar.style.right = `${100 - endPercent}%`;
- bar.style.backgroundColor = CATEGORY_COLORS[segment.category] || "#888";
-
- // Add title tooltip
- bar.title = segment.category.replace(/_/g, " ");
-
- return bar;
- }
-
- function getProgressBar() {
- // Bilibili
- if (IS_BILIBILI) {
- return (
- document.querySelector(".bpx-player-progress-wrap") ||
- document.querySelector(".bilibili-player-video-progress") ||
- document.querySelector(".squirtle-progress-wrap") ||
- document.querySelector(".bpx-player-progress")
- );
- }
-
- // Desktop YouTube
- let progressBar = document.querySelector(".ytp-progress-bar");
-
- // YouTube Music
- if (!progressBar && IS_MUSIC_YOUTUBE) {
- progressBar = document.querySelector("#progress-bar");
- }
-
- // Mobile YouTube - try multiple selectors
- if (!progressBar && IS_MOBILE_YOUTUBE) {
- progressBar =
- document.querySelector(".progress-bar-line") ||
- document.querySelector(".advancement-bar-line") ||
- document.querySelector(".advancement-bar") ||
- document.querySelector("ytm-player .progress-bar") ||
- document.querySelector(".player-controls-content .progress-bar-line") ||
- document.querySelector("[class*='progress-bar']");
- }
-
- return progressBar;
- }
-
- function clearPreviewBar() {
- if (previewBarContainer) {
- previewBarContainer.innerHTML = "";
- }
- }
-
- function removePreviewBar() {
- if (previewBarContainer) {
- previewBarContainer.remove();
- previewBarContainer = null;
- }
- }
-
- function updatePreviewBar() {
- const duration = getVideoDuration();
- if (!duration || duration <= 0) return;
-
- videoDuration = duration;
-
- // Get or create container
- if (!previewBarContainer) {
- previewBarContainer = createPreviewBar();
- }
-
- // Attach to progress bar if not already attached
- const progressBar = getProgressBar();
- if (progressBar && !progressBar.contains(previewBarContainer)) {
- // Ensure progress bar has relative positioning for absolute children
- const computedStyle = window.getComputedStyle(progressBar);
- if (computedStyle.position === "static") {
- progressBar.style.position = "relative";
- }
- progressBar.appendChild(previewBarContainer);
- }
-
- if (!progressBar) {
- // For Vinegar, this is expected since native controls can't be modified
- if (IS_VINEGAR) {
- log("Preview bar not available (Vinegar/native controls)");
- } else {
- log("Progress bar not found, will retry...");
- }
- return;
- }
-
- // Clear existing bars
- clearPreviewBar();
-
- // Filter segments for preview bar (exclude ActionType.Full)
- const previewSegments = segments.filter((s) => s.actionType !== "full");
-
- // Sort by duration (longer first) to render properly
- const sortedSegments = [...previewSegments].sort(
- (a, b) => b.segment[1] - b.segment[0] - (a.segment[1] - a.segment[0]),
- );
-
- // Create segment bars
- for (const segment of sortedSegments) {
- // Skip music_offtopic on non-music YouTube
- if (segment.category === "music_offtopic" && !IS_MUSIC_YOUTUBE) {
- continue;
- }
-
- const bar = createSegmentBar(segment, duration);
- previewBarContainer.appendChild(bar);
- }
- }
-
- // ==================== CATEGORY PILL ====================
-
- function createCategoryPill() {
- const pill = document.createElement("span");
- pill.id = "sb-lite-category-pill";
- return pill;
- }
-
- function attachCategoryPill() {
- let pill = document.getElementById("sb-lite-category-pill");
- if (!pill) {
- pill = createCategoryPill();
- }
-
- let titleContainer = null;
-
- if (IS_BILIBILI) {
- // Bilibili title selectors
- titleContainer =
- document.querySelector(".video-title") ||
- document.querySelector(".title-text") ||
- document.querySelector("h1.video-title") ||
- document.querySelector(".video-info-title");
- } else if (IS_MUSIC_YOUTUBE) {
- titleContainer = document.querySelector("ytmusic-player-bar .title");
- } else if (IS_MOBILE_YOUTUBE) {
- // Mobile YouTube title selectors
- titleContainer =
- document.querySelector(
- ".slim-video-metadata-header .slim-owner-icon-and-title",
- ) ||
- document.querySelector("ytm-slim-owner-renderer") ||
- document.querySelector(".slim-video-information-title") ||
- document.querySelector(".slim-video-metadata-title") ||
- document.querySelector("[class*='video-title']") ||
- document.querySelector("h2.slim-video-information-title");
- } else {
- // Desktop YouTube
- titleContainer =
- document.querySelector("#above-the-fold #title h1") ||
- document.querySelector("ytd-watch-metadata #title h1") ||
- document.querySelector("#info-contents h1") ||
- document.querySelector("h1.ytd-video-primary-info-renderer");
- }
-
- if (titleContainer && !titleContainer.contains(pill)) {
- titleContainer.style.display = "flex";
- titleContainer.style.alignItems = "center";
- titleContainer.style.flexWrap = "wrap";
- titleContainer.appendChild(pill);
- }
-
- return pill;
- }
-
- function showCategoryPill(segment) {
- const pill = attachCategoryPill();
- if (!pill) return;
-
- const label = CATEGORY_LABELS[segment.category] || segment.category;
- const color = CATEGORY_COLORS[segment.category] || "#008a5c";
-
- pill.textContent = label;
- pill.style.backgroundColor = color;
- pill.style.display = "inline-flex";
- }
-
- function hideCategoryPill() {
- const pill = document.getElementById("sb-lite-category-pill");
- if (pill) {
- pill.style.display = "none";
- }
- }
-
- function updateCategoryPill() {
- const fullVideoSegment = segments.find((s) => s.actionType === "full");
- if (fullVideoSegment) {
- showCategoryPill(fullVideoSegment);
- } else {
- hideCategoryPill();
- }
- }
-
- // ==================== VIDEO LISTENERS ====================
-
- function setupVideoListeners() {
- if (!video) return;
-
- // Re-check Vinegar detection now that we have a video
- updateVinegarDetection();
-
- const videoId = video.getAttribute("data-sb-lite-initialized");
- const currentSrc = video.currentSrc || video.src;
-
- // Check if this is a new video or if the source changed
- if (videoId === currentVideoID && lastVideoSrc === currentSrc) return;
-
- video.setAttribute("data-sb-lite-initialized", currentVideoID);
- lastVideoSrc = currentSrc;
-
- log("Setting up video listeners" + (IS_VINEGAR ? " (Vinegar mode)" : ""));
-
- // Remove any existing listeners by cloning (for Vinegar video replacement scenario)
- // We'll use named functions and track them instead
-
- const onPlay = () => {
- log("Video play event");
- scheduleSkips();
- };
-
- const onPlaying = () => {
- log("Video playing event");
- scheduleSkips();
- };
-
- const onSeeked = () => {
- log("Video seeked event");
- lastSkippedUUID = null;
- currentSegmentIndex = 0;
- if (!video.paused) {
- scheduleSkips();
- }
- };
-
- const onRateChange = () => {
- scheduleSkips();
- };
-
- const onPause = () => {
- log("Video pause event");
- if (skipScheduleTimer) {
- clearTimeout(skipScheduleTimer);
- skipScheduleTimer = null;
- }
- stopRAFSkipLoop();
- };
-
- const onDurationChange = () => {
- if (segments.length > 0) {
- updatePreviewBar();
- }
- };
-
- const onLoadedMetadata = () => {
- log("Video loadedmetadata event");
- if (segments.length > 0) {
- updatePreviewBar();
- }
- };
-
- video.addEventListener("play", onPlay);
- video.addEventListener("playing", onPlaying);
- video.addEventListener("seeked", onSeeked);
- video.addEventListener("ratechange", onRateChange);
- video.addEventListener("pause", onPause);
- video.addEventListener("durationchange", onDurationChange);
- video.addEventListener("loadedmetadata", onLoadedMetadata);
-
- // For Vinegar/iOS: also listen to timeupdate as backup
- // (RAF loop is primary, but timeupdate helps when app is backgrounded)
- if (IS_VINEGAR || IS_MOBILE_YOUTUBE) {
- const onTimeUpdate = () => {
- if (!video.paused && skippableSegments.length > 0) {
- const currentTime = video.currentTime;
- for (const seg of skippableSegments) {
- const [startTime, endTime] = seg.segment;
- if (
- currentTime >= startTime &&
- currentTime < endTime - SKIP_BUFFER &&
- lastSkippedUUID !== seg.UUID
- ) {
- lastSkippedUUID = seg.UUID;
- log(`Skipping ${seg.category} segment (timeupdate backup)`);
- skipToTime(endTime);
- break;
- }
- }
- }
- };
- video.addEventListener("timeupdate", onTimeUpdate);
- }
-
- // For Vinegar: Monitor for video element replacement
- if (IS_VINEGAR) {
- // Also start skip loop immediately if video is already playing
- if (!video.paused && skippableSegments.length > 0) {
- startRAFSkipLoop();
- }
- }
- }
-
- function findVideoElement() {
- // Bilibili selectors
- if (IS_BILIBILI) {
- video =
- document.querySelector(".bpx-player-video-area video") ||
- document.querySelector(".bilibili-player video") ||
- document.querySelector("video");
- return video;
- }
-
- // For Vinegar (or when YouTube player is replaced), just find any video element
- const anyVideo = document.querySelector("video");
- if (anyVideo) {
- // Check if this looks like a Vinegar setup (no YouTube player elements)
- const hasYouTubePlayer = document.querySelector("#movie_player, ytm-player") !== null;
- if (!hasYouTubePlayer) {
- if (!IS_VINEGAR) {
- IS_VINEGAR = true;
- log("Vinegar/native video detected");
- }
- video = anyVideo;
- return video;
- }
- }
-
- // Desktop selectors
- video =
- document.querySelector("video.html5-main-video") ||
- document.querySelector("video.video-stream") ||
- document.querySelector("#movie_player video");
-
- // Mobile selectors
- if (!video && IS_MOBILE_YOUTUBE) {
- video =
- document.querySelector("ytm-player video") ||
- document.querySelector(".player-container video") ||
- document.querySelector(".html5-video-container video") ||
- document.querySelector(".video-stream") ||
- document.querySelector("video[playsinline]") ||
- document.querySelector("video");
- }
-
- // Fallback
- if (!video) {
- video = document.querySelector("video");
- }
-
- return video;
- }
-
- // ==================== MUTATION OBSERVER FOR VIDEO ====================
-
- function setupVideoObserver() {
- if (videoObserver) {
- videoObserver.disconnect();
- }
-
- videoObserver = new MutationObserver((mutations) => {
- // Check if video element was added or replaced
- const currentVideo = document.querySelector("video");
-
- if (currentVideo && currentVideo !== video) {
- log("Video element change detected via observer");
- video = currentVideo;
-
- // Re-check Vinegar status
- updateVinegarDetection();
-
- if (currentVideoID) {
- setupVideoListeners();
- if (segments.length > 0 && !video.paused) {
- scheduleSkips();
- }
- }
- } else if (!currentVideo && video) {
- log("Video element removed");
- video = null;
- stopRAFSkipLoop();
- }
- });
-
- videoObserver.observe(document.body, {
- childList: true,
- subtree: true,
- });
- }
-
- // ==================== NAVIGATION & INITIALIZATION ====================
-
- function resetState() {
- currentVideoID = null;
- segments = [];
- skippableSegments = [];
- lastSkippedUUID = null;
- currentSegmentIndex = 0;
- videoDuration = 0;
- lastVideoSrc = null;
-
- if (skipScheduleTimer) {
- clearTimeout(skipScheduleTimer);
- skipScheduleTimer = null;
- }
-
- stopRAFSkipLoop();
-
- hideCategoryPill();
- removePreviewBar();
- }
-
- async function loadSegmentsAndSetup() {
- if (!currentVideoID) return;
-
- try {
- segments = await fetchSegments(currentVideoID);
-
- if (segments.length > 0) {
- log(`Found ${segments.length} segments for video ${currentVideoID}`);
- }
-
- computeSkippableSegments();
- updateCategoryPill();
- updatePreviewBar();
- setupVideoListeners();
-
- if (video && !video.paused) {
- scheduleSkips();
- }
-
- // Retry preview bar attachment after a delay (for slow-loading UI)
- if ((IS_MOBILE_YOUTUBE || IS_VINEGAR) && segments.length > 0) {
- setTimeout(updatePreviewBar, 1000);
- setTimeout(updatePreviewBar, 2000);
- setTimeout(updateCategoryPill, 1000);
- }
- } catch (error) {
- logError("Failed to load segments:", error);
- }
- }
-
- function handleVideoChangeImpl() {
- const newVideoID = getVideoID();
-
- if (!newVideoID || newVideoID === currentVideoID) {
- return;
- }
-
- log(`Video changed to: ${newVideoID}`);
- resetState();
- currentVideoID = newVideoID;
-
- let attempts = 0;
- const maxAttempts = 50;
-
- const checkVideo = setInterval(() => {
- attempts++;
-
- // Re-check Vinegar detection on each attempt
- updateVinegarDetection();
-
- if (findVideoElement()) {
- clearInterval(checkVideo);
- log("Video element found after", attempts, "attempts");
- loadSegmentsAndSetup();
- } else if (attempts >= maxAttempts) {
- clearInterval(checkVideo);
- logError("Failed to find video element after max attempts");
- }
- }, 100);
- }
-
- function handleVideoChange() {
- if (videoChangeDebounce) {
- clearTimeout(videoChangeDebounce);
- }
- videoChangeDebounce = setTimeout(handleVideoChangeImpl, 50);
- }
-
- function setupNavigationListener() {
- // Standard YouTube navigation events (may not fire on mobile)
- document.addEventListener("yt-navigate-finish", () => {
- log("yt-navigate-finish event");
- handleVideoChange();
- });
-
- document.addEventListener("yt-navigate-start", () => {
- hideCategoryPill();
- removePreviewBar();
- stopRAFSkipLoop();
- });
-
- // Mobile-specific events
- if (IS_MOBILE_YOUTUBE) {
- document.addEventListener("state-navigateend", () => {
- log("state-navigateend event");
- handleVideoChange();
- });
-
- document.addEventListener("yt-page-data-updated", () => {
- log("yt-page-data-updated event");
- handleVideoChange();
- });
- }
-
- // History API interception
- const originalPushState = history.pushState;
- history.pushState = function (...args) {
- originalPushState.apply(this, args);
- log("pushState detected");
- handleVideoChange();
- };
-
- const originalReplaceState = history.replaceState;
- history.replaceState = function (...args) {
- originalReplaceState.apply(this, args);
- log("replaceState detected");
- handleVideoChange();
- };
-
- window.addEventListener("popstate", () => {
- log("popstate event");
- handleVideoChange();
- });
-
- // URL polling fallback (essential for mobile and Vinegar)
- urlPollInterval = setInterval(() => {
- if (location.href !== lastUrl) {
- log("URL change detected via polling:", location.href);
- lastUrl = location.href;
- handleVideoChange();
- }
-
- // For Vinegar: periodically check if video element was replaced
- if (IS_VINEGAR && currentVideoID) {
- const currentVideo = document.querySelector("video");
- if (currentVideo && currentVideo !== video) {
- log("Video element replacement detected via polling");
- video = currentVideo;
- setupVideoListeners();
- if (skippableSegments.length > 0 && !video.paused) {
- scheduleSkips();
- }
- }
- }
- }, 500);
- }
-
- function init() {
- log("Initializing SponsorBlock Lite");
-
- // Initial Vinegar detection (may update later when video loads)
- updateVinegarDetection();
-
- log(
- "Platform:",
- IS_BILIBILI ? "Bilibili" : IS_VINEGAR ? "Vinegar" : IS_MOBILE_YOUTUBE ? "Mobile" : IS_MUSIC_YOUTUBE ? "Music" : "Desktop",
- );
-
- injectStyles();
- setupNavigationListener();
- setupVideoObserver();
- handleVideoChange();
-
- // Multiple retry attempts for initial load
- setTimeout(handleVideoChange, 500);
- setTimeout(handleVideoChange, 1000);
- setTimeout(handleVideoChange, 2000);
-
- // Additional retries for mobile/Vinegar
- if (IS_MOBILE_YOUTUBE || IS_VINEGAR) {
- setTimeout(handleVideoChange, 3000);
- setTimeout(handleVideoChange, 5000);
- }
-
- // For Vinegar: also retry after longer delays since the player loads differently
- setTimeout(() => {
- updateVinegarDetection();
- if (IS_VINEGAR) {
- log("Late Vinegar detection check");
- handleVideoChange();
- }
- }, 4000);
- }
-
- // ==================== START ====================
-
- if (document.readyState === "loading") {
- document.addEventListener("DOMContentLoaded", init);
- } else {
- init();
- }
-})();
diff --git a/home/programs/qutebrowser/greasemonkey/startpage-no-ads.user.js b/home/programs/qutebrowser/greasemonkey/startpage-no-ads.user.js
deleted file mode 100644
index 90b2357..0000000
--- a/home/programs/qutebrowser/greasemonkey/startpage-no-ads.user.js
+++ /dev/null
@@ -1,18 +0,0 @@
-// ==UserScript==
-// @name Startpage - Hide Ads
-// @match https://www.startpage.com/*
-// @run-at document-start
-// ==/UserScript==
-
-new MutationObserver(function(mutations) {
- mutations.forEach((mutation) => {
- if (mutation.type === 'childList') {
- mutation.addedNodes.forEach((node) => {
- if (node.nodeType === 1 && node.nodeName === 'DIV' && node.id === 'gcsa-top') {
- node.remove();
- this.disconnect();
- }
- });
- }
- });
-}).observe(document, { childList: true, subtree: true });
diff --git a/home/programs/qutebrowser/greasemonkey/tracking-token-stripper.user.js b/home/programs/qutebrowser/greasemonkey/tracking-token-stripper.user.js
deleted file mode 100644
index a425a03..0000000
--- a/home/programs/qutebrowser/greasemonkey/tracking-token-stripper.user.js
+++ /dev/null
@@ -1,191 +0,0 @@
-// ==UserScript==
-// @name TrackingTokenStripper
-// @version 1.4
-// @description Remove most of the annoying tracking token from URL parameters
-// @license MIT
-// @homepage https://blog.miniasp.com/
-// @homepageURL https://blog.miniasp.com/
-// @website https://www.facebook.com/will.fans
-// @source https://github.com/doggy8088/TrackingTokenStripper/raw/refs/heads/master/TrackingTokenStripper.user.js
-// @namespace https://github.com/doggy8088/TrackingTokenStripper
-// @author Will Huang
-// @match *://*/*
-// @run-at document-start
-// ==/UserScript==
-
-(function () {
- 'use strict';
-
- const oldReplaceState = history.replaceState;
- history.replaceState = function replaceState() {
- let ret = oldReplaceState.apply(this, arguments);
- window.dispatchEvent(new Event('replacestate'));
- window.dispatchEvent(new Event('locationchange'));
- return ret;
- };
-
- window.addEventListener('popstate', () => {
- window.dispatchEvent(new Event('locationchange'));
- });
-
- window.addEventListener('locationchange', function () {
- executeActions();
- });
-
- executeActions();
-
- let id = setInterval(executeActions, 500);
-
- setTimeout(() => { clearInterval(id); }, 2000);
-
- function executeActions() {
-
- var s = TrackingTokenStripper(location.href)
- // facebook
- .remove('fbclid')
- .removeByDomain('www.facebook.com', 'privacy_mutation_token')
- .removeByDomain('www.facebook.com', 'acontext')
- .removeByDomain('www.facebook.com', '__xts__[0]')
- .removeByDomain('www.facebook.com', 'notif_t')
- .removeByDomain('www.facebook.com', 'notif_id')
- .removeByDomain('www.facebook.com', 'notif_ids[0]')
- .removeByDomain('www.facebook.com', 'notif_ids[1]')
- .removeByDomain('www.facebook.com', 'notif_ids[2]')
- .removeByDomain('www.facebook.com', 'notif_ids[3]')
- .removeByDomain('www.facebook.com', 'ref', 'notif')
- .removeByDomain('www.facebook.com', 'ref=watch_permalink')
-
- // Dropbox
- .removeByDomain('www.dropbox.com', '_ad')
- .removeByDomain('www.dropbox.com', '_camp')
- .removeByDomain('www.dropbox.com', '_tk')
-
- // YouTube
- // https://youtu.be/4f-Y9G5ENPc?si=SHSu2hEdSbXGy4_Q
- // https://www.youtube.com/embed/4f-Y9G5ENPc?si=GQFJV_nKMXxpiQb6
- .removeByDomain('youtu.be', 'si')
- .removeByDomain('www.youtube.com', 'si')
-
- // Google Analytics
- // https://support.google.com/analytics/answer/1033863?hl=en
- .remove('utm_id')
- .remove('utm_source')
- .remove('utm_medium')
- .remove('utm_campaign')
- .remove('utm_term')
- .remove('utm_content')
- .remove('_ga')
-
- // GA - others
- .remove('utm_campaignid')
- .remove('utm_cid')
- .remove('utm_reader')
- .remove('utm_referrer')
- .remove('utm_name')
- .remove('utm_social')
- .remove('utm_social-type')
- .remove('gclid')
- .remove('igshid')
- .remove('_hsenc')
- .remove('_hsmi')
- .remove('mc_cid')
- .remove('mc_eid')
- .remove('mkt_tok')
- .remove('yclid')
- .remove('_openstat')
-
- // devblogs.microsoft.com
- .removeByDomain('devblogs.microsoft.com', 'utm_issue')
- .removeByDomain('devblogs.microsoft.com', 'utm_position')
- .removeByDomain('devblogs.microsoft.com', 'utm_topic')
- .removeByDomain('devblogs.microsoft.com', 'utm_section')
- .removeByDomain('devblogs.microsoft.com', 'utm_cta')
- .removeByDomain('devblogs.microsoft.com', 'utm_description')
- .removeByDomain('devblogs.microsoft.com', 'ocid')
-
- // Microsoft
- .remove('wt.mc_id')
- .removeByDomain('learn.microsoft.com', 'ocid')
- .removeByDomain('learn.microsoft.com', 'redirectedfrom')
-
- .removeByDomain('azure.microsoft.com', 'OCID')
- .removeByDomain('azure.microsoft.com', 'ef_id')
-
- .removeByDomain('www.msn.com', 'ocid')
- .removeByDomain('www.msn.com', 'cvid')
-
- // bilibili
- .removeByDomain('www.bilibili.com', 'share_source')
- .removeByDomain('www.bilibili.com', 'share_medium')
-
- // Others
- .remove('__tn__')
- .remove('gclsrc')
- .remove('itm_source')
- .remove('itm_medium')
- .remove('itm_campaign')
- .remove('mc') // sendgrid.com
- .remove('mcd') // sendgrid.com
- .remove('cvosrc') // sendgrid.com
- .remove('cr_cc') // https://blogs.microsoft.com/
-
- .remove('sc_channel')
- .remove('sc_campaign')
- .remove('sc_geo')
- .remove('trk')
- .remove('sc_publisher')
- .remove('trkCampaign')
- .remove('sc_outcome')
- .remove('sc_country')
-
- .remove('__hstc')
- .remove('__hssc')
- .remove('__hsfp')
- .remove('_gl')
-
- // Yahoo News
- .remove('guce_referrer')
- .remove('guce_referrer_sig')
-
- .toString();
-
- if (s && location.href !== s) {
- // console.log('Changing URL', s);
- // location.href = s;
- oldReplaceState.apply(history, [{}, '', s]);
- }
-
- function TrackingTokenStripper(url) {
- const parsedUrl = new URL(url);
- return {
- remove(name, value) {
- if (parsedUrl.searchParams.has(name)) {
- if (value && value === parsedUrl.searchParams.get(name)) {
- parsedUrl.searchParams.delete(name);
- }
- if (!value) {
- parsedUrl.searchParams.delete(name);
- }
- }
- return TrackingTokenStripper(parsedUrl.toString());
- },
- removeByDomain(domain, name) {
- if (parsedUrl.hostname.toLocaleLowerCase() === domain.toLocaleLowerCase()) {
- if (name.indexOf('=') >= 0) {
- var [key, value] = name.split("=");
- return this.remove(key, value);
- } else {
- return this.remove(name);
- }
- } else {
- return this;
- }
- },
- toString() {
- return parsedUrl.toString();
- }
- }
- }
- }
-
-})();
diff --git a/home/programs/qutebrowser/userscripts.nix b/home/programs/qutebrowser/userscripts.nix
index 3ce9611..57a432f 100644
--- a/home/programs/qutebrowser/userscripts.nix
+++ b/home/programs/qutebrowser/userscripts.nix
@@ -1,27 +1,67 @@
-{
+{pkgs, ...}: {
xdg.dataFile = {
- # Startpage - hide sponsored results
- "qutebrowser/greasemonkey/startpage-no-ads.user.js".source =
- ./greasemonkey/startpage-no-ads.user.js;
+ # Startpage: hide sponsored results (custom script, no upstream)
+ "qutebrowser/greasemonkey/startpage-no-ads.user.js".text = ''
+ // ==UserScript==
+ // @name Startpage - Hide Ads
+ // @match https://www.startpage.com/*
+ // @run-at document-start
+ // ==/UserScript==
- # Return YouTube Dislike
- "qutebrowser/greasemonkey/return-youtube-dislike.user.js".source =
- ./greasemonkey/return-youtube-dislike.user.js;
+ new MutationObserver(function(mutations) {
+ mutations.forEach((mutation) => {
+ if (mutation.type === 'childList') {
+ mutation.addedNodes.forEach((node) => {
+ if (node.nodeType === 1 && node.nodeName === 'DIV' && node.id === 'gcsa-top') {
+ node.remove();
+ this.disconnect();
+ }
+ });
+ }
+ });
+ }).observe(document, { childList: true, subtree: true });
+ '';
- # SponsorBlock Lite - auto-skip sponsors on YouTube
- "qutebrowser/greasemonkey/sponsorblock-lite.user.js".source =
- ./greasemonkey/sponsorblock-lite.user.js;
+ # Return YouTube Dislike: restore dislike counts on YouTube
+ "qutebrowser/greasemonkey/return-youtube-dislike.user.js".source = pkgs.fetchurl {
+ url = "https://update.greasyfork.org/scripts/436115/Return%20YouTube%20Dislike.user.js";
+ hash = "sha256-P7dK3v1WbSQaJUo73iHrezkXE+6BOdIuDk/D6GJwwbM=";
+ };
- # Don't Track Me Google - remove Google tracking redirects
- "qutebrowser/greasemonkey/dont-track-me-google.user.js".source =
- ./greasemonkey/dont-track-me-google.user.js;
+ # SponsorBlock Lite: auto-skip sponsors on YouTube
+ "qutebrowser/greasemonkey/sponsorblock-lite.user.js".source = pkgs.fetchurl {
+ url = "https://update.greasyfork.org/scripts/560869/SponsorBlock%20Lite.user.js";
+ hash = "sha256-8DTIRMn+cy/gZeeHa6xJDomQ5QN3lnaK0DG5ZcS5d00=";
+ };
- # I don't care about cookies - auto-dismiss cookie banners
- "qutebrowser/greasemonkey/i-dont-care-about-cookies.user.js".source =
- ./greasemonkey/i-dont-care-about-cookies.user.js;
+ # Don't Track Me Google: remove Google tracking redirects
+ "qutebrowser/greasemonkey/dont-track-me-google.user.js".source = pkgs.fetchurl {
+ url = "https://update.greasyfork.org/scripts/428243/Don%27t%20track%20me%20Google.user.js";
+ hash = "sha256-yEjBZprSjHyDRpd+TJ1vUsSYHrwLspQOztpKunBLPig=";
+ };
- # TrackingTokenStripper - remove tracking params from URLs (utm_*, fbclid, etc.)
- "qutebrowser/greasemonkey/tracking-token-stripper.user.js".source =
- ./greasemonkey/tracking-token-stripper.user.js;
+ # I don't care about cookies: auto-dismiss cookie banners
+ "qutebrowser/greasemonkey/i-dont-care-about-cookies.user.js".source = pkgs.fetchurl {
+ url = "https://update.greasyfork.org/scripts/522645/I%20don%27t%20care%20about%20cookies.user.js";
+ hash = "sha256-Ij7HyBfWemAO0EAGKYxWPPv7OX5twNtGKKPGhOAxM9w=";
+ };
+
+ # TrackingTokenStripper: remove tracking params from URLs (utm_*, fbclid, etc.)
+ "qutebrowser/greasemonkey/tracking-token-stripper.user.js".source = pkgs.fetchurl {
+ url = "https://github.com/doggy8088/TrackingTokenStripper/raw/refs/heads/master/TrackingTokenStripper.user.js";
+ hash = "sha256-EX8xN2Vd8SE/RvMcF/YSGN4Epa5cm355IeD9agTP2h4=";
+ };
+
+ # Bypass Paywalls Clean: bypass news site paywalls (Le Monde, NY Times, etc.)
+ "qutebrowser/greasemonkey/bypass-paywalls-clean.user.js".source = pkgs.fetchurl {
+ url = "https://gitflic.ru/project/magnolia1234/bypass-paywalls-clean-filters/blob/raw?file=userscript/bpc.en.user.js";
+ hash = "sha256-dUgwBkJi5Jrtpw5HJydRjY9xBpZXyD0ZtA/+hDzF97s=";
+ };
+
+ # Anti-Adblock Fuckoff: remove anti-adblock modals and restore scroll
+ "qutebrowser/greasemonkey/anti-adblock-fuckoff.user.js".source = pkgs.fetchurl {
+ url = "https://update.greasyfork.org/scripts/397070/Anti-AdBlocker%20Fuckoff.user.js";
+ hash = "sha256-vFeWxqMg0gPHP7mGNZO9e9Me/2Z81biR5JEXC/Ct4fA=";
+ };
};
}