mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-11 18:41:47 +00:00
refactor: remove dynamic require (partial of #2)
Co-authored-by: Su-Yong <simssy2205@gmail.com>
This commit is contained in:
3
plugins/adblocker/inject-cliqz-preload.ts
Normal file
3
plugins/adblocker/inject-cliqz-preload.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export default () => {
|
||||
require('@cliqz/adblocker-electron-preload');
|
||||
};
|
||||
3
plugins/adblocker/inject.d.ts
vendored
Normal file
3
plugins/adblocker/inject.d.ts
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
const inject: () => void;
|
||||
|
||||
export default inject;
|
||||
@ -7,428 +7,429 @@
|
||||
Parts of this code is derived from set-constant.js:
|
||||
https://github.com/gorhill/uBlock/blob/5de0ce975753b7565759ac40983d31978d1f84ca/assets/resources/scriptlets.js#L704
|
||||
*/
|
||||
|
||||
{
|
||||
const 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() {
|
||||
return pruner(Reflect.apply(...arguments));
|
||||
},
|
||||
});
|
||||
|
||||
Response.prototype.json = new Proxy(Response.prototype.json, {
|
||||
apply() {
|
||||
return Reflect.apply(...arguments).then((o) => pruner(o));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
(function () {
|
||||
let cValue = 'undefined';
|
||||
const chain = 'playerResponse.adPlacements';
|
||||
const thisScript = document.currentScript;
|
||||
//
|
||||
switch (cValue) {
|
||||
case 'null': {
|
||||
cValue = null;
|
||||
break;
|
||||
}
|
||||
|
||||
case "''": {
|
||||
cValue = '';
|
||||
break;
|
||||
}
|
||||
|
||||
case 'true': {
|
||||
cValue = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'false': {
|
||||
cValue = false;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'undefined': {
|
||||
cValue = undefined;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'noopFunc': {
|
||||
cValue = function () {
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'trueFunc': {
|
||||
cValue = function () {
|
||||
return true;
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'falseFunc': {
|
||||
cValue = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
if (/^\d+$/.test(cValue)) {
|
||||
cValue = Number.parseFloat(cValue);
|
||||
//
|
||||
if (isNaN(cValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Math.abs(cValue) > 0x7F_FF) {
|
||||
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 previousGetter;
|
||||
let previousSetter;
|
||||
if (odesc instanceof Object) {
|
||||
if (odesc.configurable === false) {
|
||||
return;
|
||||
module.exports = () => {
|
||||
{
|
||||
const pruner = function (o) {
|
||||
delete o.playerAds;
|
||||
delete o.adPlacements;
|
||||
//
|
||||
if (o.playerResponse) {
|
||||
delete o.playerResponse.playerAds;
|
||||
delete o.playerResponse.adPlacements;
|
||||
}
|
||||
|
||||
if (odesc.get instanceof Function) {
|
||||
previousGetter = odesc.get;
|
||||
}
|
||||
//
|
||||
return o;
|
||||
};
|
||||
|
||||
if (odesc.set instanceof Function) {
|
||||
previousSetter = odesc.set;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
Object.defineProperty(owner, prop, {
|
||||
configurable,
|
||||
get() {
|
||||
if (previousGetter !== undefined) {
|
||||
previousGetter();
|
||||
}
|
||||
|
||||
//
|
||||
return handler.getter();
|
||||
},
|
||||
set(a) {
|
||||
if (previousSetter !== undefined) {
|
||||
previousSetter(a);
|
||||
}
|
||||
|
||||
//
|
||||
handler.setter(a);
|
||||
JSON.parse = new Proxy(JSON.parse, {
|
||||
apply() {
|
||||
return pruner(Reflect.apply(...arguments));
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const trapChain = function (owner, chain) {
|
||||
const pos = chain.indexOf('.');
|
||||
if (pos === -1) {
|
||||
trapProp(owner, chain, false, {
|
||||
v: undefined,
|
||||
getter() {
|
||||
return document.currentScript === thisScript ? this.v : cValue;
|
||||
},
|
||||
setter(a) {
|
||||
if (mustAbort(a) === false) {
|
||||
Response.prototype.json = new Proxy(Response.prototype.json, {
|
||||
apply() {
|
||||
return Reflect.apply(...arguments).then((o) => pruner(o));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
(function () {
|
||||
let cValue = 'undefined';
|
||||
const chain = 'playerResponse.adPlacements';
|
||||
const thisScript = document.currentScript;
|
||||
//
|
||||
switch (cValue) {
|
||||
case 'null': {
|
||||
cValue = null;
|
||||
break;
|
||||
}
|
||||
|
||||
case "''": {
|
||||
cValue = '';
|
||||
break;
|
||||
}
|
||||
|
||||
case 'true': {
|
||||
cValue = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'false': {
|
||||
cValue = false;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'undefined': {
|
||||
cValue = undefined;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'noopFunc': {
|
||||
cValue = function () {
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'trueFunc': {
|
||||
cValue = function () {
|
||||
return true;
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'falseFunc': {
|
||||
cValue = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
if (/^\d+$/.test(cValue)) {
|
||||
cValue = Number.parseFloat(cValue);
|
||||
//
|
||||
if (isNaN(cValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
cValue = a;
|
||||
},
|
||||
init(v) {
|
||||
if (mustAbort(v)) {
|
||||
return false;
|
||||
if (Math.abs(cValue) > 0x7F_FF) {
|
||||
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 previousGetter;
|
||||
let previousSetter;
|
||||
if (odesc instanceof Object) {
|
||||
if (odesc.configurable === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (odesc.get instanceof Function) {
|
||||
previousGetter = odesc.get;
|
||||
}
|
||||
|
||||
if (odesc.set instanceof Function) {
|
||||
previousSetter = odesc.set;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
Object.defineProperty(owner, prop, {
|
||||
configurable,
|
||||
get() {
|
||||
if (previousGetter !== undefined) {
|
||||
previousGetter();
|
||||
}
|
||||
|
||||
//
|
||||
return handler.getter();
|
||||
},
|
||||
set(a) {
|
||||
if (previousSetter !== undefined) {
|
||||
previousSetter(a);
|
||||
}
|
||||
|
||||
//
|
||||
handler.setter(a);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const trapChain = function (owner, chain) {
|
||||
const pos = chain.indexOf('.');
|
||||
if (pos === -1) {
|
||||
trapProp(owner, chain, false, {
|
||||
v: undefined,
|
||||
getter() {
|
||||
return document.currentScript === thisScript ? this.v : cValue;
|
||||
},
|
||||
setter(a) {
|
||||
if (mustAbort(a) === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
cValue = a;
|
||||
},
|
||||
init(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() {
|
||||
return this.v;
|
||||
},
|
||||
setter(a) {
|
||||
this.v = a;
|
||||
if (a instanceof Object) {
|
||||
trapChain(a, chain);
|
||||
}
|
||||
},
|
||||
init(v) {
|
||||
this.v = v;
|
||||
return true;
|
||||
},
|
||||
});
|
||||
//
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
const prop = chain.slice(0, pos);
|
||||
const v = owner[prop];
|
||||
trapChain(window, chain);
|
||||
})();
|
||||
|
||||
(function () {
|
||||
let cValue = 'undefined';
|
||||
const thisScript = document.currentScript;
|
||||
const chain = 'ytInitialPlayerResponse.adPlacements';
|
||||
//
|
||||
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() {
|
||||
return this.v;
|
||||
},
|
||||
setter(a) {
|
||||
this.v = a;
|
||||
if (a instanceof Object) {
|
||||
trapChain(a, chain);
|
||||
}
|
||||
},
|
||||
init(v) {
|
||||
this.v = v;
|
||||
return true;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
//
|
||||
trapChain(window, chain);
|
||||
})();
|
||||
|
||||
(function () {
|
||||
let cValue = 'undefined';
|
||||
const thisScript = document.currentScript;
|
||||
const chain = 'ytInitialPlayerResponse.adPlacements';
|
||||
//
|
||||
switch (cValue) {
|
||||
case 'null': {
|
||||
cValue = null;
|
||||
break;
|
||||
}
|
||||
|
||||
case "''": {
|
||||
cValue = '';
|
||||
break;
|
||||
}
|
||||
|
||||
case 'true': {
|
||||
cValue = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'false': {
|
||||
cValue = false;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'undefined': {
|
||||
cValue = undefined;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'noopFunc': {
|
||||
cValue = function () {
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'trueFunc': {
|
||||
cValue = function () {
|
||||
return true;
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'falseFunc': {
|
||||
cValue = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
if (/^\d+$/.test(cValue)) {
|
||||
cValue = Number.parseFloat(cValue);
|
||||
//
|
||||
if (isNaN(cValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Math.abs(cValue) > 0x7F_FF) {
|
||||
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 previousGetter;
|
||||
let previousSetter;
|
||||
if (odesc instanceof Object) {
|
||||
if (odesc.configurable === false) {
|
||||
return;
|
||||
switch (cValue) {
|
||||
case 'null': {
|
||||
cValue = null;
|
||||
break;
|
||||
}
|
||||
|
||||
if (odesc.get instanceof Function) {
|
||||
previousGetter = odesc.get;
|
||||
case "''": {
|
||||
cValue = '';
|
||||
break;
|
||||
}
|
||||
|
||||
if (odesc.set instanceof Function) {
|
||||
previousSetter = odesc.set;
|
||||
case 'true': {
|
||||
cValue = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
Object.defineProperty(owner, prop, {
|
||||
configurable,
|
||||
get() {
|
||||
if (previousGetter !== undefined) {
|
||||
previousGetter();
|
||||
}
|
||||
case 'false': {
|
||||
cValue = false;
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
return handler.getter();
|
||||
},
|
||||
set(a) {
|
||||
if (previousSetter !== undefined) {
|
||||
previousSetter(a);
|
||||
}
|
||||
case 'undefined': {
|
||||
cValue = undefined;
|
||||
break;
|
||||
}
|
||||
|
||||
//
|
||||
handler.setter(a);
|
||||
},
|
||||
});
|
||||
};
|
||||
case 'noopFunc': {
|
||||
cValue = function () {
|
||||
};
|
||||
|
||||
const trapChain = function (owner, chain) {
|
||||
const pos = chain.indexOf('.');
|
||||
if (pos === -1) {
|
||||
trapProp(owner, chain, false, {
|
||||
v: undefined,
|
||||
getter() {
|
||||
return document.currentScript === thisScript ? this.v : cValue;
|
||||
},
|
||||
setter(a) {
|
||||
if (mustAbort(a) === false) {
|
||||
break;
|
||||
}
|
||||
|
||||
case 'trueFunc': {
|
||||
cValue = function () {
|
||||
return true;
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 'falseFunc': {
|
||||
cValue = function () {
|
||||
return false;
|
||||
};
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
if (/^\d+$/.test(cValue)) {
|
||||
cValue = Number.parseFloat(cValue);
|
||||
//
|
||||
if (isNaN(cValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
cValue = a;
|
||||
},
|
||||
init(v) {
|
||||
if (mustAbort(v)) {
|
||||
return false;
|
||||
if (Math.abs(cValue) > 0x7F_FF) {
|
||||
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 previousGetter;
|
||||
let previousSetter;
|
||||
if (odesc instanceof Object) {
|
||||
if (odesc.configurable === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (odesc.get instanceof Function) {
|
||||
previousGetter = odesc.get;
|
||||
}
|
||||
|
||||
if (odesc.set instanceof Function) {
|
||||
previousSetter = odesc.set;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
Object.defineProperty(owner, prop, {
|
||||
configurable,
|
||||
get() {
|
||||
if (previousGetter !== undefined) {
|
||||
previousGetter();
|
||||
}
|
||||
|
||||
//
|
||||
return handler.getter();
|
||||
},
|
||||
set(a) {
|
||||
if (previousSetter !== undefined) {
|
||||
previousSetter(a);
|
||||
}
|
||||
|
||||
//
|
||||
handler.setter(a);
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const trapChain = function (owner, chain) {
|
||||
const pos = chain.indexOf('.');
|
||||
if (pos === -1) {
|
||||
trapProp(owner, chain, false, {
|
||||
v: undefined,
|
||||
getter() {
|
||||
return document.currentScript === thisScript ? this.v : cValue;
|
||||
},
|
||||
setter(a) {
|
||||
if (mustAbort(a) === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
cValue = a;
|
||||
},
|
||||
init(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() {
|
||||
return this.v;
|
||||
},
|
||||
setter(a) {
|
||||
this.v = a;
|
||||
if (a instanceof Object) {
|
||||
trapChain(a, chain);
|
||||
}
|
||||
},
|
||||
init(v) {
|
||||
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() {
|
||||
return this.v;
|
||||
},
|
||||
setter(a) {
|
||||
this.v = a;
|
||||
if (a instanceof Object) {
|
||||
trapChain(a, chain);
|
||||
}
|
||||
},
|
||||
init(v) {
|
||||
this.v = v;
|
||||
return true;
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
//
|
||||
trapChain(window, chain);
|
||||
})();
|
||||
trapChain(window, chain);
|
||||
})();
|
||||
};
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import config, { blockers } from './config';
|
||||
|
||||
export default () => {
|
||||
import { MenuTemplate } from '../../menu';
|
||||
|
||||
export default (): MenuTemplate => {
|
||||
return [
|
||||
{
|
||||
label: 'Blocker',
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
import config from './config';
|
||||
import inject from './inject';
|
||||
import injectCliqzPreload from './inject-cliqz-preload';
|
||||
|
||||
export default async () => {
|
||||
if (await config.shouldUseBlocklists()) {
|
||||
// Preload adblocker to inject scripts/styles
|
||||
require('@cliqz/adblocker-electron-preload');
|
||||
injectCliqzPreload();
|
||||
// eslint-disable-next-line @typescript-eslint/await-thenable
|
||||
} else if ((await config.get('blocker')) === config.blockers.InPlayer) {
|
||||
require('./inject.js');
|
||||
inject();
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import { ipcRenderer } from 'electron';
|
||||
|
||||
import { ConfigType } from '../../config/dynamic';
|
||||
|
||||
import type { FastAverageColorResult } from 'fast-average-color';
|
||||
|
||||
function hexToHSL(H: string) {
|
||||
@ -71,7 +73,7 @@ function changeElementColor(element: HTMLElement | null, hue: number, saturation
|
||||
}
|
||||
}
|
||||
|
||||
export default () => {
|
||||
export default (_: ConfigType<'album-color-theme'>) => {
|
||||
const observer = new MutationObserver((mutationsList) => {
|
||||
for (const mutation of mutationsList) {
|
||||
if (mutation.type === 'attributes') {
|
||||
|
||||
@ -7,11 +7,13 @@ import config from './config';
|
||||
import promptOptions from '../../providers/prompt-options';
|
||||
import configOptions from '../../config/defaults';
|
||||
|
||||
import { MenuTemplate } from '../../menu';
|
||||
|
||||
import type { ConfigType } from '../../config/dynamic';
|
||||
|
||||
const defaultOptions = configOptions.plugins.crossfade;
|
||||
|
||||
export default (win: BrowserWindow) => [
|
||||
export default (win: BrowserWindow): MenuTemplate => [
|
||||
{
|
||||
label: 'Advanced',
|
||||
async click() {
|
||||
|
||||
@ -7,6 +7,7 @@ import { clear, connect, isConnected, registerRefresh } from './back';
|
||||
import { setMenuOptions } from '../../config/plugins';
|
||||
import promptOptions from '../../providers/prompt-options';
|
||||
import { singleton } from '../../providers/decorators';
|
||||
import { MenuTemplate } from '../../menu';
|
||||
|
||||
import type { ConfigType } from '../../config/dynamic';
|
||||
|
||||
@ -16,14 +17,14 @@ const registerRefreshOnce = singleton((refreshMenu: () => void) => {
|
||||
|
||||
type DiscordOptions = ConfigType<'discord'>;
|
||||
|
||||
export default (win: Electron.BrowserWindow, options: DiscordOptions, refreshMenu: () => void) => {
|
||||
export default (win: Electron.BrowserWindow, options: DiscordOptions, refreshMenu: () => void): MenuTemplate => {
|
||||
registerRefreshOnce(refreshMenu);
|
||||
|
||||
return [
|
||||
{
|
||||
label: isConnected() ? 'Connected' : 'Reconnect',
|
||||
enabled: !isConnected(),
|
||||
click: connect,
|
||||
click: () => connect(),
|
||||
},
|
||||
{
|
||||
label: 'Auto reconnect',
|
||||
|
||||
@ -15,7 +15,7 @@ import type { ConfigType } from '../../config/dynamic';
|
||||
const eastAsianChars = /\p{Script=Katakana}|\p{Script=Hiragana}|\p{Script=Hangul}|\p{Script=Han}/u;
|
||||
let revRomanized = false;
|
||||
|
||||
export type LyricGeniusType = ConfigType<'lyric-genius'>;
|
||||
export type LyricGeniusType = ConfigType<'lyrics-genius'>;
|
||||
|
||||
export default (win: BrowserWindow, options: LyricGeniusType) => {
|
||||
if (options.romanizedLyrics) {
|
||||
|
||||
@ -3,8 +3,9 @@ import { BrowserWindow, MenuItem } from 'electron';
|
||||
import { LyricGeniusType, toggleRomanized } from './back';
|
||||
|
||||
import { setOptions } from '../../config/plugins';
|
||||
import { MenuTemplate } from '../../menu';
|
||||
|
||||
export default (_: BrowserWindow, options: LyricGeniusType) => [
|
||||
export default (_: BrowserWindow, options: LyricGeniusType): MenuTemplate => [
|
||||
{
|
||||
label: 'Romanized Lyrics',
|
||||
type: 'checkbox',
|
||||
|
||||
@ -1,27 +0,0 @@
|
||||
import { Actions, triggerAction } from '../utils';
|
||||
|
||||
export const CHANNEL = 'navigation';
|
||||
export const ACTIONS = Actions;
|
||||
|
||||
export function goToNextPage() {
|
||||
triggerAction(CHANNEL, Actions.NEXT);
|
||||
}
|
||||
// for HTML
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-explicit-any
|
||||
(global as any).goToNextPage = goToNextPage;
|
||||
|
||||
export function goToPreviousPage() {
|
||||
triggerAction(CHANNEL, Actions.BACK);
|
||||
}
|
||||
// for HTML
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-explicit-any
|
||||
(global as any).goToPreviousPage = goToPreviousPage;
|
||||
|
||||
export default {
|
||||
CHANNEL,
|
||||
ACTIONS,
|
||||
actions: {
|
||||
goToNextPage,
|
||||
goToPreviousPage,
|
||||
},
|
||||
};
|
||||
@ -2,38 +2,12 @@ import path from 'node:path';
|
||||
|
||||
import { BrowserWindow } from 'electron';
|
||||
|
||||
import { ACTIONS, CHANNEL } from './actions';
|
||||
|
||||
import { injectCSS, listenAction } from '../utils';
|
||||
import { injectCSS } from '../utils';
|
||||
|
||||
export function handle(win: BrowserWindow) {
|
||||
injectCSS(win.webContents, path.join(__dirname, 'style.css'), () => {
|
||||
win.webContents.send('navigation-css-ready');
|
||||
});
|
||||
|
||||
listenAction(CHANNEL, (_, action) => {
|
||||
switch (action) {
|
||||
case ACTIONS.NEXT: {
|
||||
if (win.webContents.canGoForward()) {
|
||||
win.webContents.goForward();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ACTIONS.BACK: {
|
||||
if (win.webContents.canGoBack()) {
|
||||
win.webContents.goBack();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
console.log('Unknown action: ' + action);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default handle;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<div
|
||||
class="style-scope ytmusic-pivot-bar-renderer navigation-item"
|
||||
onclick="goToPreviousPage()"
|
||||
onclick="history.back()"
|
||||
role="tab"
|
||||
tab-id="FEmusic_back"
|
||||
>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<div
|
||||
class="style-scope ytmusic-pivot-bar-renderer navigation-item"
|
||||
onclick="goToNextPage()"
|
||||
onclick="history.forward()"
|
||||
role="tab"
|
||||
tab-id="FEmusic_next"
|
||||
>
|
||||
|
||||
@ -6,11 +6,13 @@ import { snakeToCamel, ToastStyles, urgencyLevels } from './utils';
|
||||
|
||||
import config from './config';
|
||||
|
||||
import { MenuTemplate } from '../../menu';
|
||||
|
||||
import type { ConfigType } from '../../config/dynamic';
|
||||
|
||||
export default (_win: BrowserWindow, options: ConfigType<'notifications'>) => [
|
||||
...(is.linux()
|
||||
? [
|
||||
const getMenu = (options: ConfigType<'notifications'>): MenuTemplate => {
|
||||
if (is.linux()) {
|
||||
return [
|
||||
{
|
||||
label: 'Notification Priority',
|
||||
submenu: urgencyLevels.map((level) => ({
|
||||
@ -19,11 +21,10 @@ export default (_win: BrowserWindow, options: ConfigType<'notifications'>) => [
|
||||
checked: options.urgency === level.value,
|
||||
click: () => config.set('urgency', level.value),
|
||||
})),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(is.windows()
|
||||
? [
|
||||
}
|
||||
];
|
||||
} else if (is.windows()) {
|
||||
return [
|
||||
{
|
||||
label: 'Interactive Notifications',
|
||||
type: 'checkbox',
|
||||
@ -59,8 +60,14 @@ export default (_win: BrowserWindow, options: ConfigType<'notifications'>) => [
|
||||
label: 'Style',
|
||||
submenu: getToastStyleMenuItems(options),
|
||||
},
|
||||
]
|
||||
: []),
|
||||
];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
export default (_win: BrowserWindow, options: ConfigType<'notifications'>): MenuTemplate => [
|
||||
...getMenu(options),
|
||||
{
|
||||
label: 'Show notification on unpause',
|
||||
type: 'checkbox',
|
||||
@ -79,8 +86,8 @@ export function getToastStyleMenuItems(options: ConfigType<'notifications'>) {
|
||||
type: 'radio',
|
||||
checked: options.toastStyle === index,
|
||||
click: () => config.set('toastStyle', index),
|
||||
};
|
||||
} satisfies Electron.MenuItemConstructorOptions;
|
||||
}
|
||||
|
||||
return array;
|
||||
return array as Electron.MenuItemConstructorOptions[];
|
||||
}
|
||||
|
||||
@ -10,8 +10,6 @@ import defaultConfig from '../../config/defaults';
|
||||
import type { GetPlayerResponse } from '../../types/get-player-response';
|
||||
import type { ConfigType } from '../../config/dynamic';
|
||||
|
||||
let videoID: string;
|
||||
|
||||
export default (win: BrowserWindow, options: ConfigType<'sponsorblock'>) => {
|
||||
const { apiURL, categories } = {
|
||||
...defaultConfig.plugins.sponsorblock,
|
||||
@ -19,14 +17,13 @@ export default (win: BrowserWindow, options: ConfigType<'sponsorblock'>) => {
|
||||
};
|
||||
|
||||
ipcMain.on('video-src-changed', async (_, data: GetPlayerResponse) => {
|
||||
videoID = data?.videoDetails?.videoId;
|
||||
const segments = await fetchSegments(apiURL, categories);
|
||||
const segments = await fetchSegments(apiURL, categories, data?.videoDetails?.videoId);
|
||||
win.webContents.send('sponsorblock-skip', segments);
|
||||
});
|
||||
};
|
||||
|
||||
const fetchSegments = async (apiURL: string, categories: string[]) => {
|
||||
const sponsorBlockURL = `${apiURL}/api/skipSegments?videoID=${videoID}&categories=${JSON.stringify(
|
||||
const fetchSegments = async (apiURL: string, categories: string[], videoId: string) => {
|
||||
const sponsorBlockURL = `${apiURL}/api/skipSegments?videoID=${videoId}&categories=${JSON.stringify(
|
||||
categories,
|
||||
)}`;
|
||||
try {
|
||||
|
||||
@ -5,17 +5,46 @@ import { BrowserWindow, nativeImage } from 'electron';
|
||||
import getSongControls from '../../providers/song-controls';
|
||||
import registerCallback, { SongInfo } from '../../providers/song-info';
|
||||
|
||||
|
||||
let controls: {
|
||||
playPause: () => void;
|
||||
next: () => void;
|
||||
previous: () => void;
|
||||
};
|
||||
let currentSongInfo: SongInfo;
|
||||
|
||||
export default (win: BrowserWindow) => {
|
||||
let currentSongInfo: SongInfo;
|
||||
|
||||
const { playPause, next, previous } = getSongControls(win);
|
||||
controls = { playPause, next, previous };
|
||||
|
||||
const setThumbar = (win: BrowserWindow, songInfo: SongInfo) => {
|
||||
// Wait for song to start before setting thumbar
|
||||
if (!songInfo?.title) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Win32 require full rewrite of components
|
||||
win.setThumbarButtons([
|
||||
{
|
||||
tooltip: 'Previous',
|
||||
icon: nativeImage.createFromPath(get('previous')),
|
||||
click() {
|
||||
previous();
|
||||
},
|
||||
}, {
|
||||
tooltip: 'Play/Pause',
|
||||
// Update icon based on play state
|
||||
icon: nativeImage.createFromPath(songInfo.isPaused ? get('play') : get('pause')),
|
||||
click() {
|
||||
playPause();
|
||||
},
|
||||
}, {
|
||||
tooltip: 'Next',
|
||||
icon: nativeImage.createFromPath(get('next')),
|
||||
click() {
|
||||
next();
|
||||
},
|
||||
},
|
||||
]);
|
||||
};
|
||||
|
||||
// Util
|
||||
const get = (kind: string) => {
|
||||
return path.join(__dirname, '../../assets/media-icons-black', `${kind}.png`);
|
||||
};
|
||||
|
||||
registerCallback((songInfo) => {
|
||||
// Update currentsonginfo for win.on('show')
|
||||
@ -29,39 +58,3 @@ export default (win: BrowserWindow) => {
|
||||
setThumbar(win, currentSongInfo);
|
||||
});
|
||||
};
|
||||
|
||||
function setThumbar(win: BrowserWindow, songInfo: SongInfo) {
|
||||
// Wait for song to start before setting thumbar
|
||||
if (!songInfo?.title) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Win32 require full rewrite of components
|
||||
win.setThumbarButtons([
|
||||
{
|
||||
tooltip: 'Previous',
|
||||
icon: nativeImage.createFromPath(get('previous')),
|
||||
click() {
|
||||
controls.previous();
|
||||
},
|
||||
}, {
|
||||
tooltip: 'Play/Pause',
|
||||
// Update icon based on play state
|
||||
icon: nativeImage.createFromPath(songInfo.isPaused ? get('play') : get('pause')),
|
||||
click() {
|
||||
controls.playPause();
|
||||
},
|
||||
}, {
|
||||
tooltip: 'Next',
|
||||
icon: nativeImage.createFromPath(get('next')),
|
||||
click() {
|
||||
controls.next();
|
||||
},
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
// Util
|
||||
function get(kind: string) {
|
||||
return path.join(__dirname, '../../assets/media-icons-black', `${kind}.png`);
|
||||
}
|
||||
|
||||
@ -3,65 +3,66 @@ import { TouchBar, NativeImage, BrowserWindow } from 'electron';
|
||||
import registerCallback from '../../providers/song-info';
|
||||
import getSongControls from '../../providers/song-controls';
|
||||
|
||||
const {
|
||||
TouchBarButton,
|
||||
TouchBarLabel,
|
||||
TouchBarSpacer,
|
||||
TouchBarSegmentedControl,
|
||||
TouchBarScrubber,
|
||||
} = TouchBar;
|
||||
|
||||
// Songtitle label
|
||||
const songTitle = new TouchBarLabel({
|
||||
label: '',
|
||||
});
|
||||
// This will store the song controls once available
|
||||
let controls: (() => void)[] = [];
|
||||
|
||||
// This will store the song image once available
|
||||
const songImage: {
|
||||
icon?: NativeImage;
|
||||
} = {};
|
||||
|
||||
// Pause/play button
|
||||
const pausePlayButton = new TouchBarButton({});
|
||||
|
||||
// The song control buttons (control functions are in the same order)
|
||||
const buttons = new TouchBarSegmentedControl({
|
||||
mode: 'buttons',
|
||||
segments: [
|
||||
new TouchBarButton({
|
||||
label: '⏮',
|
||||
}),
|
||||
pausePlayButton,
|
||||
new TouchBarButton({
|
||||
label: '⏭',
|
||||
}),
|
||||
new TouchBarButton({
|
||||
label: '👎',
|
||||
}),
|
||||
new TouchBarButton({
|
||||
label: '👍',
|
||||
}),
|
||||
],
|
||||
change: (i) => controls[i](),
|
||||
});
|
||||
|
||||
// This is the touchbar object, this combines everything with proper layout
|
||||
const touchBar = new TouchBar({
|
||||
items: [
|
||||
new TouchBarScrubber({
|
||||
items: [songImage, songTitle],
|
||||
continuous: false,
|
||||
}),
|
||||
new TouchBarSpacer({
|
||||
size: 'flexible',
|
||||
}),
|
||||
buttons,
|
||||
],
|
||||
});
|
||||
|
||||
export default (win: BrowserWindow) => {
|
||||
const {
|
||||
TouchBarButton,
|
||||
TouchBarLabel,
|
||||
TouchBarSpacer,
|
||||
TouchBarSegmentedControl,
|
||||
TouchBarScrubber,
|
||||
} = TouchBar;
|
||||
|
||||
// Songtitle label
|
||||
const songTitle = new TouchBarLabel({
|
||||
label: '',
|
||||
});
|
||||
// This will store the song controls once available
|
||||
let controls: (() => void)[] = [];
|
||||
|
||||
// This will store the song image once available
|
||||
const songImage: {
|
||||
icon?: NativeImage;
|
||||
} = {};
|
||||
|
||||
// Pause/play button
|
||||
const pausePlayButton = new TouchBarButton({});
|
||||
|
||||
// The song control buttons (control functions are in the same order)
|
||||
const buttons = new TouchBarSegmentedControl({
|
||||
mode: 'buttons',
|
||||
segments: [
|
||||
new TouchBarButton({
|
||||
label: '⏮',
|
||||
}),
|
||||
pausePlayButton,
|
||||
new TouchBarButton({
|
||||
label: '⏭',
|
||||
}),
|
||||
new TouchBarButton({
|
||||
label: '👎',
|
||||
}),
|
||||
new TouchBarButton({
|
||||
label: '👍',
|
||||
}),
|
||||
],
|
||||
change: (i) => controls[i](),
|
||||
});
|
||||
|
||||
// This is the touchbar object, this combines everything with proper layout
|
||||
const touchBar = new TouchBar({
|
||||
items: [
|
||||
new TouchBarScrubber({
|
||||
items: [songImage, songTitle],
|
||||
continuous: false,
|
||||
}),
|
||||
new TouchBarSpacer({
|
||||
size: 'flexible',
|
||||
}),
|
||||
buttons,
|
||||
],
|
||||
});
|
||||
|
||||
|
||||
const { playPause, next, previous, dislike, like } = getSongControls(win);
|
||||
|
||||
// If the page is ready, register the callback
|
||||
|
||||
@ -3,7 +3,10 @@ import path from 'node:path';
|
||||
|
||||
import { ipcMain, ipcRenderer } from 'electron';
|
||||
|
||||
import is from 'electron-is';
|
||||
|
||||
import { ValueOf } from '../utils/type-utils';
|
||||
import defaultConfig from '../config/defaults';
|
||||
|
||||
// Creates a DOM element from an HTML string
|
||||
export const ElementFromHtml = (html: string): HTMLElement => {
|
||||
@ -64,11 +67,15 @@ const setupCssInjection = (webContents: Electron.WebContents) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const getAllPlugins = () => {
|
||||
const isDirectory = (source: fs.PathLike) => fs.lstatSync(source).isDirectory();
|
||||
return fs
|
||||
.readdirSync(__dirname)
|
||||
.map((name) => path.join(__dirname, name))
|
||||
.filter(isDirectory)
|
||||
.map((name) => path.basename(name));
|
||||
export const getAvailablePluginNames = () => {
|
||||
return Object.keys(defaultConfig.plugins).filter((name) => {
|
||||
if (is.windows() && name === 'touchbar') {
|
||||
return false;
|
||||
} else if (is.macOS() && name === 'taskbar-mediacontrol') {
|
||||
return false;
|
||||
} else if (is.linux() && (name === 'taskbar-mediacontrol' || name === 'touchbar')) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user