mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-11 10:31:47 +00:00
Implement both blocklists and in-player blocking
This commit is contained in:
@ -1,8 +1,13 @@
|
|||||||
const { loadAdBlockerEngine } = require("./blocker");
|
const { loadAdBlockerEngine } = require("./blocker");
|
||||||
module.exports = (win, options) =>
|
const config = require("./config");
|
||||||
|
|
||||||
|
module.exports = async (win, options) => {
|
||||||
|
if (await config.shouldUseBlocklists()) {
|
||||||
loadAdBlockerEngine(
|
loadAdBlockerEngine(
|
||||||
win.webContents.session,
|
win.webContents.session,
|
||||||
options.cache,
|
options.cache,
|
||||||
options.additionalBlockLists,
|
options.additionalBlockLists,
|
||||||
options.disableDefaultLists
|
options.disableDefaultLists,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|||||||
13
plugins/adblocker/config.js
Normal file
13
plugins/adblocker/config.js
Normal 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
289
plugins/adblocker/inject.js
Normal 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
15
plugins/adblocker/menu.js
Normal 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") === blocker,
|
||||||
|
click: () => {
|
||||||
|
config.set("blocker", blocker);
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
},
|
||||||
|
];
|
||||||
@ -1,4 +1,10 @@
|
|||||||
module.exports = () => {
|
const config = require("./config");
|
||||||
|
|
||||||
|
module.exports = async () => {
|
||||||
|
if (await config.shouldUseBlocklists()) {
|
||||||
// Preload adblocker to inject scripts/styles
|
// Preload adblocker to inject scripts/styles
|
||||||
require("@cliqz/adblocker-electron-preload");
|
require("@cliqz/adblocker-electron-preload");
|
||||||
|
} else if ((await config.get("blocker")) === config.blockers.InPlayer) {
|
||||||
|
require("./inject");
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user