Move playback setting extras to ExtrasMenu; New mod: Filterworks / Anime4K
This commit is contained in:
parent
e67a71ab3e
commit
d42172174a
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@
|
|||||||
/priv/
|
/priv/
|
||||||
/.vscode/
|
/.vscode/
|
||||||
update.sh
|
update.sh
|
||||||
|
mods_dev.json
|
||||||
|
@ -185,7 +185,7 @@ export default JadefinIntegrity("Jadefin", import.meta.url, () => window["Jadefi
|
|||||||
];
|
];
|
||||||
|
|
||||||
await this._loadingMods;
|
await this._loadingMods;
|
||||||
await this.initMods();
|
await this._initLoadingMods();
|
||||||
|
|
||||||
await Promise.all(initing);
|
await Promise.all(initing);
|
||||||
|
|
||||||
@ -389,7 +389,7 @@ export default JadefinIntegrity("Jadefin", import.meta.url, () => window["Jadefi
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async initMods(list) {
|
async _initLoadingMods() {
|
||||||
await Promise.all(this._loadingMods_all.map(async (mod) => {
|
await Promise.all(this._loadingMods_all.map(async (mod) => {
|
||||||
this.log.i(`Initializing mod ${mod.name}`);
|
this.log.i(`Initializing mod ${mod.name}`);
|
||||||
|
|
||||||
@ -400,7 +400,6 @@ export default JadefinIntegrity("Jadefin", import.meta.url, () => window["Jadefi
|
|||||||
this.log.dir(e);
|
this.log.dir(e);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
})());
|
})());
|
||||||
|
@ -20,7 +20,7 @@ class JadefinMod {
|
|||||||
this.modUrl = url;
|
this.modUrl = url;
|
||||||
}
|
}
|
||||||
|
|
||||||
initStyle() {
|
async initStyle() {
|
||||||
document.head.appendChild(rd$()`<link rel="stylesheet" type="text/css" href=${this.getUrl(".css")}>`);
|
document.head.appendChild(rd$()`<link rel="stylesheet" type="text/css" href=${this.getUrl(".css")}>`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
4
init.js
4
init.js
@ -42,7 +42,7 @@ jadefinInitExtremelyEarly();
|
|||||||
console.log("[jadefin-init] loadJadefin");
|
console.log("[jadefin-init] loadJadefin");
|
||||||
|
|
||||||
const loader = document.createElement("script");
|
const loader = document.createElement("script");
|
||||||
this.document.head.appendChild(loader);
|
document.head.appendChild(loader);
|
||||||
|
|
||||||
window["_JadefinLoaded"] = () => resolve(true);
|
window["_JadefinLoaded"] = () => resolve(true);
|
||||||
window["_JadefinErrored"] = (e) => reject(e);
|
window["_JadefinErrored"] = (e) => reject(e);
|
||||||
@ -95,7 +95,7 @@ jadefinInitExtremelyEarly();
|
|||||||
}
|
}
|
||||||
|
|
||||||
const loader = document.createElement("script");
|
const loader = document.createElement("script");
|
||||||
this.document.head.appendChild(loader);
|
document.head.appendChild(loader);
|
||||||
|
|
||||||
loader.addEventListener("load", () => resolve(true));
|
loader.addEventListener("load", () => resolve(true));
|
||||||
loader.addEventListener("error", (e) => reject(e));
|
loader.addEventListener("error", (e) => reject(e));
|
||||||
|
@ -15,6 +15,8 @@ export default JadefinIntegrity("ExtrasMenu", import.meta.url, () => new (class
|
|||||||
IN_DRAWER = 2;
|
IN_DRAWER = 2;
|
||||||
IN_LIBRARY = 4;
|
IN_LIBRARY = 4;
|
||||||
IN_MOVIE = 8;
|
IN_MOVIE = 8;
|
||||||
|
IN_PLAYBACKSETTINGS = 16;
|
||||||
|
IN_PLAYBACKSETTINGS_ADVANCED = 32;
|
||||||
|
|
||||||
_popupId = 0;
|
_popupId = 0;
|
||||||
_items = [];
|
_items = [];
|
||||||
@ -83,23 +85,25 @@ export default JadefinIntegrity("ExtrasMenu", import.meta.url, () => new (class
|
|||||||
async init(name, url) {
|
async init(name, url) {
|
||||||
await super.init(name, url);
|
await super.init(name, url);
|
||||||
|
|
||||||
await JadefinUtils.waitUntil(() => document.querySelector(".headerRight"));
|
await Promise.all([
|
||||||
|
this.initStyle(),
|
||||||
this.initStyle();
|
this.initHeaderExtras(),
|
||||||
this.initHeaderExtras();
|
this.initDrawerExtras(),
|
||||||
this.initDrawerExtras();
|
this.initHookActionSheetShow()
|
||||||
|
]);
|
||||||
|
|
||||||
this.log.i("Ready");
|
this.log.i("Ready");
|
||||||
}
|
}
|
||||||
|
|
||||||
initHeaderExtras() {
|
async initHeaderExtras() {
|
||||||
|
await JadefinUtils.waitUntil(() => document.querySelector(".headerRight"));
|
||||||
document.querySelector(".headerRight")?.appendChild(this.headerExtrasEl);
|
document.querySelector(".headerRight")?.appendChild(this.headerExtrasEl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {boolean} [silentWarn]
|
* @param {boolean} [silentWarn]
|
||||||
*/
|
*/
|
||||||
initDrawerExtras(silentWarn) {
|
async initDrawerExtras(silentWarn) {
|
||||||
const drawer = document.querySelector(".mainDrawer > .mainDrawer-scrollContainer");
|
const drawer = document.querySelector(".mainDrawer > .mainDrawer-scrollContainer");
|
||||||
const userMenuOptions = drawer?.querySelector("& > .userMenuOptions");
|
const userMenuOptions = drawer?.querySelector("& > .userMenuOptions");
|
||||||
|
|
||||||
@ -129,51 +133,100 @@ export default JadefinIntegrity("ExtrasMenu", import.meta.url, () => new (class
|
|||||||
this.update();
|
this.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async initHookActionSheetShow() {
|
||||||
|
await JadefinUtils.waitUntil(() => JadefinModules.actionSheet);
|
||||||
|
|
||||||
|
const orig = this._actionSheetShowOrig = JadefinModules.actionSheet.show.bind(JadefinModules.actionSheet);
|
||||||
|
JadefinModules.actionSheet.show = (options) => {
|
||||||
|
const optionsOrig = Object.assign({}, options, {
|
||||||
|
items: options.items.slice()
|
||||||
|
});
|
||||||
|
|
||||||
|
// Options menu during playback
|
||||||
|
if (!options.dialogClass &&
|
||||||
|
options.items.length >= 6 &&
|
||||||
|
options.items[0].id == "aspectratio" &&
|
||||||
|
options.items[1].id == "playbackrate" &&
|
||||||
|
options.items[2].id == "quality" &&
|
||||||
|
options.items[3].id == "repeatmode" &&
|
||||||
|
options.items[4].id == "suboffset" &&
|
||||||
|
options.items[5].id == "stats" &&
|
||||||
|
true
|
||||||
|
) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const currentVisibility = this.IN_PLAYBACKSETTINGS;
|
||||||
|
const items = [
|
||||||
|
{id: "extrasMenuPopup-all", name: "Advanced..."},
|
||||||
|
{divider: true},
|
||||||
|
...this._items.map((item, i) => Object.assign({
|
||||||
|
id: i
|
||||||
|
}, item)).filter(item => this.checkVisibility(currentVisibility, item)),
|
||||||
|
...optionsOrig.items.slice(4)
|
||||||
|
];
|
||||||
|
|
||||||
|
const p = this._actionSheetShow({
|
||||||
|
positionTo: optionsOrig.positionTo,
|
||||||
|
currentVisibility,
|
||||||
|
items
|
||||||
|
});
|
||||||
|
|
||||||
|
p.then(id => {
|
||||||
|
if (id == "extrasMenuPopup-all") {
|
||||||
|
const currentVisibility = this.IN_PLAYBACKSETTINGS_ADVANCED;
|
||||||
|
const items = [
|
||||||
|
...optionsOrig.items.slice(0, 4),
|
||||||
|
...this._items.map((item, i) => Object.assign({
|
||||||
|
id: i
|
||||||
|
}, item)).filter(item => this.checkVisibility(currentVisibility, item)),
|
||||||
|
{divider: true},
|
||||||
|
{id: "extrasMenuPopup-back", name: "Back..."}
|
||||||
|
];
|
||||||
|
|
||||||
|
const p = this._actionSheetShow(Object.assign({}, optionsOrig, {
|
||||||
|
currentVisibility,
|
||||||
|
items
|
||||||
|
}));
|
||||||
|
|
||||||
|
p.then(id => {
|
||||||
|
if (id == "extrasMenuPopup-back") {
|
||||||
|
JadefinModules.actionSheet.show(optionsOrig).then(resolve).catch(reject);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id && this._items[id]) {
|
||||||
|
reject();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(id);
|
||||||
|
}).catch(reject);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (id && this._items[id]) {
|
||||||
|
reject();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(id);
|
||||||
|
}).catch(reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return orig(options);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
openExtrasPopup() {
|
openExtrasPopup() {
|
||||||
const currentVisibility = JadefinUtils.isInMovie ? this.IN_MOVIE : this.IN_LIBRARY;
|
const currentVisibility = JadefinUtils.isInMovie ? this.IN_MOVIE : this.IN_LIBRARY;
|
||||||
|
|
||||||
const dialogClass = `extrasMenuPopup-${this._popupId++}`;
|
this._actionSheetShow({
|
||||||
|
|
||||||
const items = this._items.map((item, i) => Object.assign({
|
|
||||||
id: i
|
|
||||||
}, item)).filter(item => this.checkVisibility(currentVisibility, item));
|
|
||||||
|
|
||||||
const p = JadefinModules.actionSheet.show({
|
|
||||||
dialogClass,
|
|
||||||
title: "Extras",
|
title: "Extras",
|
||||||
positionTo: this.headerExtrasEl,
|
positionTo: this.headerExtrasEl,
|
||||||
items
|
currentVisibility,
|
||||||
});
|
items: this._items.map((item, i) => Object.assign({
|
||||||
|
id: i
|
||||||
p.then(id => {
|
}, item)).filter(item => this.checkVisibility(currentVisibility, item))
|
||||||
if (!id) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this._items[id]?.cb?.();
|
|
||||||
});
|
|
||||||
|
|
||||||
const dialogEl = document.querySelector(`.${dialogClass}`);
|
|
||||||
if (!dialogEl) {
|
|
||||||
this.log.e(`Couldn't find .${dialogClass}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.log.i(`Opened .${dialogClass}`);
|
|
||||||
this.log.dir(dialogEl);
|
|
||||||
|
|
||||||
dialogEl.classList.add("extrasMenuPopup");
|
|
||||||
|
|
||||||
const dialogButtons = dialogEl.querySelectorAll("button");
|
|
||||||
|
|
||||||
for (let i in items) {
|
|
||||||
items[i].cbEl?.(dialogButtons[i], currentVisibility, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
p.finally(() => {
|
|
||||||
for (let i in items) {
|
|
||||||
items[i].cbEl?.(dialogButtons[i], currentVisibility, false);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,4 +272,45 @@ export default JadefinIntegrity("ExtrasMenu", import.meta.url, () => new (class
|
|||||||
return (item.in & current) == current;
|
return (item.in & current) == current;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {{ positionTo: any; currentVisibility: any; items: any; title?: string; dialogClass?: any; }} options
|
||||||
|
*/
|
||||||
|
_actionSheetShow(options) {
|
||||||
|
options.dialogClass = `extrasMenuPopup-${this._popupId++}`;
|
||||||
|
|
||||||
|
const p = JadefinModules.actionSheet.show(options);
|
||||||
|
|
||||||
|
p.then(id => {
|
||||||
|
if (!id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._items[id]?.cb?.(options.positionTo);
|
||||||
|
});
|
||||||
|
|
||||||
|
const dialogEl = document.querySelector(`.${options.dialogClass}`);
|
||||||
|
if (!dialogEl) {
|
||||||
|
this.log.e(`Couldn't find .${options.dialogClass}`);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.log.i(`Opened .${options.dialogClass}`);
|
||||||
|
this.log.dir(dialogEl);
|
||||||
|
|
||||||
|
dialogEl.classList.add("extrasMenuPopup");
|
||||||
|
|
||||||
|
const dialogButtons = dialogEl.querySelectorAll("button");
|
||||||
|
|
||||||
|
for (let i in options.items) {
|
||||||
|
options.items[i].cbEl?.(dialogButtons[i], options.currentVisibility, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
p.finally(() => {
|
||||||
|
for (let i in options.items) {
|
||||||
|
options.items[i].cbEl?.(dialogButtons[i], options.currentVisibility, false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return p;
|
||||||
|
}
|
||||||
})());
|
})());
|
||||||
|
@ -72,7 +72,7 @@ export default JadefinIntegrity("InputEater", import.meta.url, () => new (class
|
|||||||
|
|
||||||
await JadefinUtils.waitUntil(() => JadefinModules.syncPlay);
|
await JadefinUtils.waitUntil(() => JadefinModules.syncPlay);
|
||||||
|
|
||||||
this.initStyle();
|
await this.initStyle();
|
||||||
this.initHookSyncPlayEnabled();
|
this.initHookSyncPlayEnabled();
|
||||||
this.initHookSyncPlayDisabled();
|
this.initHookSyncPlayDisabled();
|
||||||
this.initHookMediaSessionHandlers();
|
this.initHookMediaSessionHandlers();
|
||||||
|
@ -121,8 +121,8 @@ export default JadefinIntegrity("Transcript", import.meta.url, () => new (class
|
|||||||
async init(name, url) {
|
async init(name, url) {
|
||||||
await super.init(name, url);
|
await super.init(name, url);
|
||||||
|
|
||||||
this.initStyle();
|
|
||||||
const initing = [
|
const initing = [
|
||||||
|
this.initStyle(),
|
||||||
this.initHookSetTrackForDisplay(),
|
this.initHookSetTrackForDisplay(),
|
||||||
this.initHookFetchSubtitles(),
|
this.initHookFetchSubtitles(),
|
||||||
this.initHookSetOffset(),
|
this.initHookSetOffset(),
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import JadefinIntegrity from '../JadefinIntegrity.js';
|
import JadefinIntegrity from '../JadefinIntegrity.js';
|
||||||
|
|
||||||
|
import Jadefin from "../Jadefin.js";
|
||||||
import JadefinMod from "../JadefinMod.js";
|
import JadefinMod from "../JadefinMod.js";
|
||||||
import JadefinModules from "../JadefinModules.js";
|
import JadefinModules from "../JadefinModules.js";
|
||||||
import JadefinUtils from "../JadefinUtils.js";
|
import JadefinUtils from "../JadefinUtils.js";
|
||||||
@ -62,9 +63,34 @@ export default JadefinIntegrity("VolumeBoost", import.meta.url, () => new (class
|
|||||||
async init(name, url) {
|
async init(name, url) {
|
||||||
await super.init(name, url);
|
await super.init(name, url);
|
||||||
|
|
||||||
await JadefinUtils.waitUntil(() => JadefinModules.actionSheet);
|
const ExtrasMenu = /** @type {import("./ExtrasMenu.js").default} */ (Jadefin.getMod("ExtrasMenu"));
|
||||||
|
|
||||||
this.initHookActionSheetShow();
|
ExtrasMenu.items.push({
|
||||||
|
name: "Volume Boost",
|
||||||
|
in: ExtrasMenu.IN_CUSTOM,
|
||||||
|
inCustom: (current, item) => {
|
||||||
|
item.asideText = `${this.currentGain}x`;
|
||||||
|
|
||||||
|
return (current & (ExtrasMenu.IN_PLAYBACKSETTINGS)) == current;
|
||||||
|
},
|
||||||
|
cb: async (positionTo) => {
|
||||||
|
JadefinModules.actionSheet.show({
|
||||||
|
positionTo,
|
||||||
|
items: [
|
||||||
|
{id: "1", name: "1x", selected: this.currentGain == 1},
|
||||||
|
{id: "2", name: "2x", selected: this.currentGain == 2},
|
||||||
|
{id: "3", name: "3x", selected: this.currentGain == 3},
|
||||||
|
{id: "4", name: "4x", selected: this.currentGain == 4},
|
||||||
|
]
|
||||||
|
}).then(id => {
|
||||||
|
if (!id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentGain = parseInt(id);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
document.addEventListener("viewshow", () => {
|
document.addEventListener("viewshow", () => {
|
||||||
if (JadefinUtils.routePathIsVideo) {
|
if (JadefinUtils.routePathIsVideo) {
|
||||||
@ -83,86 +109,6 @@ export default JadefinIntegrity("VolumeBoost", import.meta.url, () => new (class
|
|||||||
this.log.i("Ready");
|
this.log.i("Ready");
|
||||||
}
|
}
|
||||||
|
|
||||||
initHookActionSheetShow() {
|
|
||||||
const orig = this._actionSheetShowOrig = JadefinModules.actionSheet.show.bind(JadefinModules.actionSheet);
|
|
||||||
JadefinModules.actionSheet.show = (options) => {
|
|
||||||
const optionsOrig = Object.assign({}, options, {
|
|
||||||
items: options.items.slice()
|
|
||||||
});
|
|
||||||
|
|
||||||
this.log.v("actionSheet.show(...)");
|
|
||||||
this.log.dir(options);
|
|
||||||
|
|
||||||
// Options menu during playback
|
|
||||||
if (options.items.length >= 6 &&
|
|
||||||
options.items[0].id == "aspectratio" &&
|
|
||||||
options.items[1].id == "playbackrate" &&
|
|
||||||
options.items[2].id == "quality" &&
|
|
||||||
options.items[3].id == "repeatmode" &&
|
|
||||||
options.items[4].id == "suboffset" &&
|
|
||||||
options.items[5].id == "stats" &&
|
|
||||||
true
|
|
||||||
) {
|
|
||||||
options.items.splice(4, 0, {id: "custom-volumeboost", name: "Volume Boost", asideText: `${this.currentGain}x`});
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
JadefinModules.actionSheet.show({
|
|
||||||
positionTo: options.positionTo,
|
|
||||||
items: [
|
|
||||||
{id: "all", name: "Advanced..."},
|
|
||||||
{divider: true},
|
|
||||||
...options.items.slice(4),
|
|
||||||
]
|
|
||||||
}).then(id => {
|
|
||||||
if (id == "all") {
|
|
||||||
orig(Object.assign({}, options, {
|
|
||||||
items: [
|
|
||||||
...options.items.slice(0, 4),
|
|
||||||
{divider: true},
|
|
||||||
{id: "back", name: "Back..."},
|
|
||||||
]
|
|
||||||
})).then(id => {
|
|
||||||
if (id == "back") {
|
|
||||||
JadefinModules.actionSheet.show(optionsOrig).then(resolve).catch(reject);
|
|
||||||
} else {
|
|
||||||
resolve(id);
|
|
||||||
}
|
|
||||||
}).catch(reject);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (id == "custom-volumeboost") {
|
|
||||||
reject();
|
|
||||||
|
|
||||||
JadefinModules.actionSheet.show({
|
|
||||||
positionTo: options.positionTo,
|
|
||||||
items: [
|
|
||||||
{id: "1", name: "1x", selected: this.currentGain == 1},
|
|
||||||
{id: "2", name: "2x", selected: this.currentGain == 2},
|
|
||||||
{id: "3", name: "3x", selected: this.currentGain == 3},
|
|
||||||
{id: "4", name: "4x", selected: this.currentGain == 4},
|
|
||||||
]
|
|
||||||
}).then(id => {
|
|
||||||
if (!id) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.currentGain = parseInt(id);
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(id);
|
|
||||||
}).catch(reject);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return orig(options);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
connect() {
|
connect() {
|
||||||
const video = JadefinUtils.video;
|
const video = JadefinUtils.video;
|
||||||
if (!video) {
|
if (!video) {
|
||||||
|
29
mods/jade/Filterworks.css
Normal file
29
mods/jade/Filterworks.css
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
.htmlvideoplayer[data-filterworks-canvas="1"] {
|
||||||
|
/* Still needs to be layouted for subs and our own canvas. */
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filterworks-canvasParent {
|
||||||
|
pointer-events: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
order: -2;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filterworks-canvas {
|
||||||
|
position: absolute;
|
||||||
|
display: block;
|
||||||
|
padding: 0;
|
||||||
|
margin: auto;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
228
mods/jade/Filterworks.js
Normal file
228
mods/jade/Filterworks.js
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
//@ts-check
|
||||||
|
|
||||||
|
import JadefinIntegrity from '../../JadefinIntegrity.js';
|
||||||
|
|
||||||
|
import Jadefin from "../../Jadefin.js";
|
||||||
|
import JadefinMod from "../../JadefinMod.js";
|
||||||
|
import JadefinModules from "../../JadefinModules.js";
|
||||||
|
import JadefinUtils from "../../JadefinUtils.js";
|
||||||
|
|
||||||
|
import { rd, rdom, rd$, RDOMListHelper } from "../../utils/rdom.js";
|
||||||
|
|
||||||
|
export class FilterworksFilter {
|
||||||
|
name = "Hello, World!";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {HTMLVideoElement} video
|
||||||
|
*/
|
||||||
|
start(video) {
|
||||||
|
}
|
||||||
|
|
||||||
|
stop(video) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FilterworksSrc {
|
||||||
|
modName = "ExampleSource";
|
||||||
|
|
||||||
|
/** @type {{
|
||||||
|
[id: string]: FilterworksFilter;
|
||||||
|
}} */
|
||||||
|
filters = {
|
||||||
|
test: new FilterworksFilter()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export default JadefinIntegrity("Filterworks", import.meta.url, () => new (class Filterworks extends JadefinMod {
|
||||||
|
PATH_OFF = "Filterworks/Off";
|
||||||
|
|
||||||
|
_sources = [];
|
||||||
|
_pathsToFilters = {};
|
||||||
|
_filtersToMeta = {};
|
||||||
|
|
||||||
|
/** @type {any} */
|
||||||
|
appliedFilter = null;
|
||||||
|
|
||||||
|
canvasParentEl = rd$()`
|
||||||
|
<div class="filterworks-canvasParent">
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
/** @type {typeof this._sources} */
|
||||||
|
sources = new Proxy(this._sources, {
|
||||||
|
deleteProperty: (target, property) => {
|
||||||
|
delete target[property];
|
||||||
|
|
||||||
|
this.updateSources();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
|
set: (target, property, value, receiver) => {
|
||||||
|
target[property] = value;
|
||||||
|
|
||||||
|
this.updateSources();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.sources.push({
|
||||||
|
modName: "Filterworks",
|
||||||
|
filters: {
|
||||||
|
Off: {
|
||||||
|
name: "Off",
|
||||||
|
start: (video) => {},
|
||||||
|
stop: () => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get currentFilterPathPath() {
|
||||||
|
let id = "default";
|
||||||
|
|
||||||
|
const item = JadefinUtils.currentPlayer?.streamInfo?.item;
|
||||||
|
if (item) {
|
||||||
|
id = item.SeriesId || item.ParentId || item.Id || id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return `currentFilterPath-${id}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
get currentFilterPath() {
|
||||||
|
return this.storage.get(this.currentFilterPathPath, this.PATH_OFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
set currentFilterPath(value) {
|
||||||
|
this.storage.set(this.currentFilterPathPath, value);
|
||||||
|
this.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
get currentFilter() {
|
||||||
|
return this._pathsToFilters[this.currentFilterPath] || this._pathsToFilters[this.PATH_OFF];
|
||||||
|
}
|
||||||
|
|
||||||
|
async init(name, url) {
|
||||||
|
await super.init(name, url);
|
||||||
|
|
||||||
|
const ExtrasMenu = /** @type {import("../ExtrasMenu.js").default} */ (Jadefin.getMod("ExtrasMenu"));
|
||||||
|
|
||||||
|
await this.initStyle();
|
||||||
|
|
||||||
|
ExtrasMenu.items.push({
|
||||||
|
name: "Filter",
|
||||||
|
in: ExtrasMenu.IN_CUSTOM,
|
||||||
|
inCustom: (current, item) => {
|
||||||
|
item.asideText = this.currentFilter.name;
|
||||||
|
|
||||||
|
return (current & (ExtrasMenu.IN_PLAYBACKSETTINGS)) == current;
|
||||||
|
},
|
||||||
|
cb: async (positionTo) => {
|
||||||
|
const items = [];
|
||||||
|
|
||||||
|
items.push({id: this.PATH_OFF, name: this._pathsToFilters[this.PATH_OFF].name, selected: this.currentFilter == this._pathsToFilters[this.PATH_OFF]});
|
||||||
|
|
||||||
|
for (const path in this._pathsToFilters) {
|
||||||
|
if (path == this.PATH_OFF) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
items.push({id: path, name: this._pathsToFilters[path].name, selected: this.currentFilterPath == path});
|
||||||
|
}
|
||||||
|
|
||||||
|
JadefinModules.actionSheet.show({
|
||||||
|
positionTo,
|
||||||
|
items
|
||||||
|
}).then(id => {
|
||||||
|
if (!id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.currentFilterPath = id;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener("viewshow", () => {
|
||||||
|
if (JadefinUtils.routePathIsVideo) {
|
||||||
|
if (this._tryUpdateRepeat) {
|
||||||
|
clearInterval(this._tryUpdateRepeat);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearInterval(this._tryUpdateRepeat);
|
||||||
|
this._tryUpdateRepeat = setInterval(() => this.tryUpdate(), 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.update();
|
||||||
|
});
|
||||||
|
|
||||||
|
this.log.i("Ready");
|
||||||
|
}
|
||||||
|
|
||||||
|
updateSources() {
|
||||||
|
this._pathsToFilters = {};
|
||||||
|
|
||||||
|
for (const src of this._sources) {
|
||||||
|
for (const id in src.filters) {
|
||||||
|
this._pathsToFilters[`${src.modName}/${id}`] = src.filters[id];
|
||||||
|
this._filtersToMeta[src.filters[id]] = { src, id };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tryUpdate() {
|
||||||
|
const video = JadefinUtils.video;
|
||||||
|
if (!video) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.update();
|
||||||
|
|
||||||
|
if (this._tryUpdateRepeat) {
|
||||||
|
clearInterval(this._tryUpdateRepeat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
const video = JadefinUtils.video;
|
||||||
|
if (!video) {
|
||||||
|
if (this.appliedFilter) {
|
||||||
|
this.appliedFilter.stop();
|
||||||
|
this.appliedFilter = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.video = null;
|
||||||
|
this.canvas = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.video == video && this.appliedFilter == this.currentFilter) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.appliedFilter?.stop();
|
||||||
|
if (this.canvas) {
|
||||||
|
video.removeAttribute("data-filterworks-canvas");
|
||||||
|
this.canvas.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.video = video;
|
||||||
|
|
||||||
|
this.appliedFilter = this.currentFilter;
|
||||||
|
this.canvas = this.appliedFilter.start(video);
|
||||||
|
if (this.canvas) {
|
||||||
|
this.canvas.classList.add("filterworks-canvas");
|
||||||
|
this.canvasParentEl.append(this.canvas);
|
||||||
|
|
||||||
|
if (this.canvasParentEl.parentElement != video.parentElement) {
|
||||||
|
video.parentElement?.prepend(this.canvasParentEl);
|
||||||
|
}
|
||||||
|
|
||||||
|
video.setAttribute("data-filterworks-canvas", "1");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})());
|
@ -16,7 +16,7 @@ export default JadefinIntegrity("Shortcuts", import.meta.url, () => new (class S
|
|||||||
async init(name, url) {
|
async init(name, url) {
|
||||||
await super.init(name, url);
|
await super.init(name, url);
|
||||||
|
|
||||||
this.initStyle();
|
await this.initStyle();
|
||||||
|
|
||||||
const ExtrasMenu = /** @type {import("../ExtrasMenu.js").default} */ (Jadefin.getMod("ExtrasMenu"));
|
const ExtrasMenu = /** @type {import("../ExtrasMenu.js").default} */ (Jadefin.getMod("ExtrasMenu"));
|
||||||
|
|
||||||
|
1
mods/jade/filters/Anime4K.dist.js
Normal file
1
mods/jade/filters/Anime4K.dist.js
Normal file
File diff suppressed because one or more lines are too long
95
mods/jade/filters/Anime4K.js
Normal file
95
mods/jade/filters/Anime4K.js
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
//@ts-check
|
||||||
|
|
||||||
|
import JadefinIntegrity from '../../../JadefinIntegrity.js';
|
||||||
|
|
||||||
|
import Jadefin from "../../../Jadefin.js";
|
||||||
|
import JadefinMod from "../../../JadefinMod.js";
|
||||||
|
import JadefinModules from "../../../JadefinModules.js";
|
||||||
|
import JadefinUtils from "../../../JadefinUtils.js";
|
||||||
|
|
||||||
|
class FilterworksAnime4KFilter {
|
||||||
|
constructor(name, key) {
|
||||||
|
this.name = name;
|
||||||
|
this.key = key;
|
||||||
|
|
||||||
|
this.a4k = window["Anime4KJS"];
|
||||||
|
if (!this.a4k) {
|
||||||
|
throw new Error("Anime4KJS not loaded");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.profile = this.a4k[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {HTMLVideoElement} video
|
||||||
|
*/
|
||||||
|
start(video) {
|
||||||
|
if (this.upscaler) {
|
||||||
|
throw new Error("Filter already in use");
|
||||||
|
}
|
||||||
|
|
||||||
|
const stream = JadefinUtils.currentPlayer.streamInfo.mediaSource.MediaStreams.find(x => x.Type == "Video");
|
||||||
|
const fps = stream?.RealFrameRate || stream?.AverageFrameRate || 60;
|
||||||
|
this.upscaler = new this.a4k.VideoUpscaler(fps, this.profile);
|
||||||
|
|
||||||
|
this.video = video;
|
||||||
|
this.canvas = document.createElement("canvas");
|
||||||
|
|
||||||
|
this.upscaler.attachVideo(this.video, this.canvas);
|
||||||
|
this.upscaler.start();
|
||||||
|
|
||||||
|
return this.canvas;
|
||||||
|
}
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
this.upscaler?.stop();
|
||||||
|
this.upscaler?.detachVideo();
|
||||||
|
this.upscaler = null;
|
||||||
|
|
||||||
|
this.canvas?.remove();
|
||||||
|
this.video?.removeAttribute("data-filterworks-canvas");
|
||||||
|
|
||||||
|
this.video = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default JadefinIntegrity("FilterworksAnime4KSrc", import.meta.url, () => new (class FilterworksAnime4KSrc extends JadefinMod {
|
||||||
|
filters = {
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
async init(name, url) {
|
||||||
|
await super.init(name, url);
|
||||||
|
|
||||||
|
await new Promise((resolve, reject) => {
|
||||||
|
const loader = document.createElement("script");
|
||||||
|
document.head.appendChild(loader);
|
||||||
|
|
||||||
|
loader.addEventListener("load", () => resolve(true));
|
||||||
|
loader.addEventListener("error", (e) => reject(e));
|
||||||
|
|
||||||
|
loader.defer = true;
|
||||||
|
loader.src = this.getUrl(".dist.js");
|
||||||
|
});
|
||||||
|
|
||||||
|
this.filters = {
|
||||||
|
lqSIMPLE: new FilterworksAnime4KFilter("Anime4K LQ Simple", "ANIME4KJS_SIMPLE_M_2X"),
|
||||||
|
lqA: new FilterworksAnime4KFilter("Anime4K LQ Mode A", "ANIME4K_LOWEREND_MODE_A_FAST"),
|
||||||
|
lqB: new FilterworksAnime4KFilter("Anime4K LQ Mode B", "ANIME4K_LOWEREND_MODE_B_FAST"),
|
||||||
|
lqC: new FilterworksAnime4KFilter("Anime4K LQ Mode C", "ANIME4K_LOWEREND_MODE_C_FAST"),
|
||||||
|
hqSIMPLE: new FilterworksAnime4KFilter("Anime4K HQ Simple", "ANIME4KJS_SIMPLE_L_2X"),
|
||||||
|
hqA: new FilterworksAnime4KFilter("Anime4K HQ Mode A", "ANIME4K_HIGHEREND_MODE_A_FAST"),
|
||||||
|
hqB: new FilterworksAnime4KFilter("Anime4K HQ Mode B", "ANIME4K_HIGHEREND_MODE_B_FAST"),
|
||||||
|
hqC: new FilterworksAnime4KFilter("Anime4K HQ Mode C", "ANIME4K_HIGHEREND_MODE_C_FAST")
|
||||||
|
};
|
||||||
|
|
||||||
|
const Filterworks = /** @type {import("../Filterworks.js").default} */ (Jadefin.getMod("Filterworks"));
|
||||||
|
|
||||||
|
Filterworks.sources.push(this);
|
||||||
|
|
||||||
|
this.log.i("Ready");
|
||||||
|
}
|
||||||
|
})());
|
@ -8,5 +8,8 @@
|
|||||||
"Transcript.js",
|
"Transcript.js",
|
||||||
"PatchForceHLSJS.js",
|
"PatchForceHLSJS.js",
|
||||||
|
|
||||||
"jade/Shortcuts.js"
|
"jade/Shortcuts.js",
|
||||||
|
|
||||||
|
"jade/Filterworks.js",
|
||||||
|
"jade/filters/Anime4K.js"
|
||||||
]
|
]
|
Loading…
Reference in New Issue
Block a user