Merge pull request #1134 from th-ch/adblocker-multi-implem

Multiple implementations for the Adblocker plugin
This commit is contained in:
th-ch
2023-05-12 22:32:14 +02:00
committed by GitHub
7 changed files with 348 additions and 20 deletions

View File

@ -105,7 +105,7 @@
"npm": "Please use yarn instead"
},
"dependencies": {
"@cliqz/adblocker-electron": "1.26.3",
"@cliqz/adblocker-electron": "^1.26.5",
"@ffmpeg/core": "^0.11.0",
"@ffmpeg/ffmpeg": "^0.11.6",
"@foobar404/wave": "^2.0.4",

View File

@ -1,8 +1,13 @@
const { loadAdBlockerEngine } = require("./blocker");
module.exports = (win, options) =>
loadAdBlockerEngine(
win.webContents.session,
options.cache,
options.additionalBlockLists,
options.disableDefaultLists
);
const config = require("./config");
module.exports = async (win, options) => {
if (await config.shouldUseBlocklists()) {
loadAdBlockerEngine(
win.webContents.session,
options.cache,
options.additionalBlockLists,
options.disableDefaultLists,
);
}
};

View File

@ -0,0 +1,13 @@
const { PluginConfig } = require("../../config/dynamic");
const config = new PluginConfig("adblocker", { enableFront: true });
const blockers = {
WithBlocklists: "With blocklists",
InPlayer: "In player",
};
const shouldUseBlocklists = async () =>
(await config.get("blocker")) !== blockers.InPlayer;
module.exports = { shouldUseBlocklists, blockers, ...config };

289
plugins/adblocker/inject.js Normal file
View File

@ -0,0 +1,289 @@
// Source: https://addons.mozilla.org/en-US/firefox/addon/adblock-for-youtube/
// https://robwu.nl/crxviewer/?crx=https%3A%2F%2Faddons.mozilla.org%2Fen-US%2Ffirefox%2Faddon%2Fadblock-for-youtube%2F
/*
Parts of this code is derived from set-constant.js:
https://github.com/gorhill/uBlock/blob/5de0ce975753b7565759ac40983d31978d1f84ca/assets/resources/scriptlets.js#L704
*/
{
let pruner = function (o) {
delete o.playerAds;
delete o.adPlacements;
//
if (o.playerResponse) {
delete o.playerResponse.playerAds;
delete o.playerResponse.adPlacements;
}
//
return o;
};
JSON.parse = new Proxy(JSON.parse, {
apply: function () {
return pruner(Reflect.apply(...arguments));
},
});
Response.prototype.json = new Proxy(Response.prototype.json, {
apply: function () {
return Reflect.apply(...arguments).then((o) => pruner(o));
},
});
}
(function () {
let cValue = "undefined";
const chain = "playerResponse.adPlacements";
const thisScript = document.currentScript;
//
if (cValue === "null") cValue = null;
else if (cValue === "''") cValue = "";
else if (cValue === "true") cValue = true;
else if (cValue === "false") cValue = false;
else if (cValue === "undefined") cValue = undefined;
else if (cValue === "noopFunc") cValue = function () {};
else if (cValue === "trueFunc")
cValue = function () {
return true;
};
else if (cValue === "falseFunc")
cValue = function () {
return false;
};
else if (/^\d+$/.test(cValue)) {
cValue = parseFloat(cValue);
//
if (isNaN(cValue)) return;
if (Math.abs(cValue) > 0x7fff) return;
} else {
return;
}
//
let aborted = false;
const mustAbort = function (v) {
if (aborted) return true;
aborted =
v !== undefined &&
v !== null &&
cValue !== undefined &&
cValue !== null &&
typeof v !== typeof cValue;
return aborted;
};
/*
Support multiple trappers for the same property:
https://github.com/uBlockOrigin/uBlock-issues/issues/156
*/
const trapProp = function (owner, prop, configurable, handler) {
if (handler.init(owner[prop]) === false) {
return;
}
//
const odesc = Object.getOwnPropertyDescriptor(owner, prop);
let prevGetter, prevSetter;
if (odesc instanceof Object) {
if (odesc.configurable === false) return;
if (odesc.get instanceof Function) prevGetter = odesc.get;
if (odesc.set instanceof Function) prevSetter = odesc.set;
}
//
Object.defineProperty(owner, prop, {
configurable,
get() {
if (prevGetter !== undefined) {
prevGetter();
}
//
return handler.getter();
},
set(a) {
if (prevSetter !== undefined) {
prevSetter(a);
}
//
handler.setter(a);
},
});
};
const trapChain = function (owner, chain) {
const pos = chain.indexOf(".");
if (pos === -1) {
trapProp(owner, chain, false, {
v: undefined,
getter: function () {
return document.currentScript === thisScript ? this.v : cValue;
},
setter: function (a) {
if (mustAbort(a) === false) return;
cValue = a;
},
init: function (v) {
if (mustAbort(v)) return false;
//
this.v = v;
return true;
},
});
//
return;
}
//
const prop = chain.slice(0, pos);
const v = owner[prop];
//
chain = chain.slice(pos + 1);
if (v instanceof Object || (typeof v === "object" && v !== null)) {
trapChain(v, chain);
return;
}
//
trapProp(owner, prop, true, {
v: undefined,
getter: function () {
return this.v;
},
setter: function (a) {
this.v = a;
if (a instanceof Object) trapChain(a, chain);
},
init: function (v) {
this.v = v;
return true;
},
});
};
//
trapChain(window, chain);
})();
(function () {
let cValue = "undefined";
const thisScript = document.currentScript;
const chain = "ytInitialPlayerResponse.adPlacements";
//
if (cValue === "null") cValue = null;
else if (cValue === "''") cValue = "";
else if (cValue === "true") cValue = true;
else if (cValue === "false") cValue = false;
else if (cValue === "undefined") cValue = undefined;
else if (cValue === "noopFunc") cValue = function () {};
else if (cValue === "trueFunc")
cValue = function () {
return true;
};
else if (cValue === "falseFunc")
cValue = function () {
return false;
};
else if (/^\d+$/.test(cValue)) {
cValue = parseFloat(cValue);
//
if (isNaN(cValue)) return;
if (Math.abs(cValue) > 0x7fff) return;
} else {
return;
}
//
let aborted = false;
const mustAbort = function (v) {
if (aborted) return true;
aborted =
v !== undefined &&
v !== null &&
cValue !== undefined &&
cValue !== null &&
typeof v !== typeof cValue;
return aborted;
};
/*
Support multiple trappers for the same property:
https://github.com/uBlockOrigin/uBlock-issues/issues/156
*/
const trapProp = function (owner, prop, configurable, handler) {
if (handler.init(owner[prop]) === false) {
return;
}
//
const odesc = Object.getOwnPropertyDescriptor(owner, prop);
let prevGetter, prevSetter;
if (odesc instanceof Object) {
if (odesc.configurable === false) return;
if (odesc.get instanceof Function) prevGetter = odesc.get;
if (odesc.set instanceof Function) prevSetter = odesc.set;
}
//
Object.defineProperty(owner, prop, {
configurable,
get() {
if (prevGetter !== undefined) {
prevGetter();
}
//
return handler.getter();
},
set(a) {
if (prevSetter !== undefined) {
prevSetter(a);
}
//
handler.setter(a);
},
});
};
const trapChain = function (owner, chain) {
const pos = chain.indexOf(".");
if (pos === -1) {
trapProp(owner, chain, false, {
v: undefined,
getter: function () {
return document.currentScript === thisScript ? this.v : cValue;
},
setter: function (a) {
if (mustAbort(a) === false) return;
cValue = a;
},
init: function (v) {
if (mustAbort(v)) return false;
//
this.v = v;
return true;
},
});
//
return;
}
//
const prop = chain.slice(0, pos);
const v = owner[prop];
//
chain = chain.slice(pos + 1);
if (v instanceof Object || (typeof v === "object" && v !== null)) {
trapChain(v, chain);
return;
}
//
trapProp(owner, prop, true, {
v: undefined,
getter: function () {
return this.v;
},
setter: function (a) {
this.v = a;
if (a instanceof Object) trapChain(a, chain);
},
init: function (v) {
this.v = v;
return true;
},
});
};
//
trapChain(window, chain);
})();

15
plugins/adblocker/menu.js Normal file
View File

@ -0,0 +1,15 @@
const config = require("./config");
module.exports = () => [
{
label: "Blocker",
submenu: Object.values(config.blockers).map((blocker) => ({
label: blocker,
type: "radio",
checked: (config.get("blocker") || config.blockers.WithBlocklists) === blocker,
click: () => {
config.set("blocker", blocker);
},
})),
},
];

View File

@ -1,4 +1,10 @@
module.exports = () => {
// Preload adblocker to inject scripts/styles
require("@cliqz/adblocker-electron-preload");
const config = require("./config");
module.exports = async () => {
if (await config.shouldUseBlocklists()) {
// Preload adblocker to inject scripts/styles
require("@cliqz/adblocker-electron-preload");
} else if ((await config.get("blocker")) === config.blockers.InPlayer) {
require("./inject");
}
};

View File

@ -57,7 +57,7 @@ __metadata:
languageName: node
linkType: hard
"@cliqz/adblocker-electron-preload@npm:^1.26.3":
"@cliqz/adblocker-electron-preload@npm:^1.26.5":
version: 1.26.5
resolution: "@cliqz/adblocker-electron-preload@npm:1.26.5"
dependencies:
@ -68,16 +68,16 @@ __metadata:
languageName: node
linkType: hard
"@cliqz/adblocker-electron@npm:1.26.3":
version: 1.26.3
resolution: "@cliqz/adblocker-electron@npm:1.26.3"
"@cliqz/adblocker-electron@npm:^1.26.5":
version: 1.26.5
resolution: "@cliqz/adblocker-electron@npm:1.26.5"
dependencies:
"@cliqz/adblocker": ^1.26.3
"@cliqz/adblocker-electron-preload": ^1.26.3
"@cliqz/adblocker": ^1.26.5
"@cliqz/adblocker-electron-preload": ^1.26.5
tldts-experimental: ^5.6.21
peerDependencies:
electron: ">11"
checksum: 3a649ff7aaebeb4265f3d9f75ffed11a29b06005a437f92873b1b286fd742631cb8beaf83b7973adda334a1b91075ac27a864503ae5451ac3dddfe5c0bd59bb4
checksum: 666f562a5745cf0e54b26253d6c9506a049c9a84a8a1002d3027a951bf195f094f7d506997872e0774dc4b6bc5b7b1a02db0c1aa9c44219ead283e0b90394d3c
languageName: node
linkType: hard
@ -88,7 +88,7 @@ __metadata:
languageName: node
linkType: hard
"@cliqz/adblocker@npm:^1.26.3":
"@cliqz/adblocker@npm:^1.26.5":
version: 1.26.5
resolution: "@cliqz/adblocker@npm:1.26.5"
dependencies:
@ -7325,7 +7325,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "youtube-music@workspace:."
dependencies:
"@cliqz/adblocker-electron": 1.26.3
"@cliqz/adblocker-electron": ^1.26.5
"@ffmpeg/core": ^0.11.0
"@ffmpeg/ffmpeg": ^0.11.6
"@foobar404/wave": ^2.0.4