Initial attempt at updating for 10.9

This commit is contained in:
Jade Macho 2024-05-12 23:21:17 +02:00
parent 0cce72b24b
commit e8c3154a79
Signed by: 0x0ade
GPG Key ID: E1960710FE4FBEEF
8 changed files with 134 additions and 46 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
.htaccess .htaccess
/priv/ /priv/
/.vscode/ /.vscode/
update.sh

View File

@ -41,33 +41,6 @@ export default JadefinIntegrity("Jadefin", import.meta.url, () => window["Jadefi
} }
initEarly() { initEarly() {
// Required for mods to be able to replace some things.
// Might or might not horribly wreck everything.
const defineProperty = this._Object_defineProperty = Object.defineProperty.bind(Object);
const defineProperties = this._Object_defineProperties = Object.defineProperties.bind(Object);
Object.defineProperty = (obj, prop, descriptor) => {
if (descriptor && prop != "prototype") {
descriptor.configurable = true;
}
return defineProperty(obj, prop, descriptor);
};
Object.defineProperties = (obj, props) => {
if (props) {
for (const prop of Object.keys(props)) {
const descriptor = props[prop];
if (descriptor && prop != "prototype") {
descriptor.configurable = true;
}
}
}
return defineProperties(obj, props);
};
// Required for mods to be able to perform certain worker shenanigans. // Required for mods to be able to perform certain worker shenanigans.
window.Worker = (class Worker extends window.Worker { window.Worker = (class Worker extends window.Worker {
constructor(scriptURL, options) { constructor(scriptURL, options) {
@ -92,6 +65,8 @@ export default JadefinIntegrity("Jadefin", import.meta.url, () => window["Jadefi
} }
async init(base) { async init(base) {
const self = this;
await super.init("Jadefin", this.modUrl); await super.init("Jadefin", this.modUrl);
// Wait until webpackChunk and Emby exist. // Wait until webpackChunk and Emby exist.
@ -108,10 +83,71 @@ export default JadefinIntegrity("Jadefin", import.meta.url, () => window["Jadefi
return; return;
} }
// Wait until webpackChunk and Emby exist. /** @type {(id: number | string) => any} */
// It might be delayed due to the main jellyfin bundle being replaced by an inject script on Android. this.webpackTryLoad = id => {
try {
return this.webpackLoad?.(id);
} catch (e) {
this.log.w(`Failed to load webpack module ${id}`);
this.log.dir(e);
return null;
}
};
/** @type {(id: any) => string} */
this.webpackIdToChunkJS = Object.values(this.webpackLoad).find(v => typeof(v) == "function" && v.toString().indexOf(`+".chunk.js"`) != -1);
/** @type {(id: any) => string} */
this.webpackIdToChunkCSS = Object.values(this.webpackLoad).find(v => typeof(v) == "function" && v.toString().indexOf(`+".css"`) != -1);
const webpackIdToChunkJSKey = Object.keys(this.webpackLoad).find(k => this.webpackLoad?.[k] == this.webpackIdToChunkJS);
if (!this.webpackIdToChunkJS || !webpackIdToChunkJSKey) {
this.log.e("Couldn't obtain webpackIdToChunkJS");
return;
}
this.webpackLoad[webpackIdToChunkJSKey] = function(id) {
const rv = self.webpackIdToChunkJS?.(id);
self.log.v(`Webpack converted chunk ID to JS name: ${id} -> ${rv}`);
return rv;
};
/** @type {(name: any, cb: any, sid: any, id: any) => any} */
this.webpackLoadChunkLowLevel = Object.values(this.webpackLoad).find(v => typeof(v) == "function" && v.toString().indexOf(`document.head.appendChild`) != -1);
const webpackLoadChunkLowLevelKey = Object.keys(this.webpackLoad).find(k => this.webpackLoad?.[k] == this.webpackLoadChunkLowLevel);
if (!this.webpackLoadChunkLowLevel || !webpackLoadChunkLowLevelKey) {
this.log.e("Couldn't obtain webpackLoadChunkLowLevel");
return;
}
this.webpackLoad[webpackLoadChunkLowLevelKey] = function(name, cb, sid, id) {
const _cb = cb;
self.log.v(`Webpack loading chunk ${id} (${sid}) from ${name}`);
/*
cb = (event) => {
self.log.v(`Webpack loaded chunk ${id} (${sid}) from ${name}: ${event.type}`);
return _cb(event);
};
*/
const rv = self.webpackLoadChunkLowLevel?.(name, cb, sid, id);
return rv;
};
/** @type {(id: any) => Promise<any>} */
this.webpackLoadChunk = Object.values(this.webpackLoad).find(v => typeof(v) == "function" && v.toString().indexOf(`Object.keys(`) != -1 && v.toString().indexOf(`}),[])`) != -1);
// HACKFIX: Load all chunks when Jadefin initializes!
// webpackIdToChunkJS contains all IDs either ahead of === or :
// FIXME: This smells like race condition hell! We might be too late for this kind of hooking.
// FIXME: Ideally, don't. This makes startup take ages.
const webpackChunks = [...this.webpackIdToChunkJS.toString().matchAll(/\d+(?=:|=)/g)].map(v => parseInt(v[0]));
await Promise.all(webpackChunks.map(id => this.webpackLoadChunk?.(id)));
// Wait until everything else is ready.
await JadefinUtils.waitUntil(() => this.webpackModuleFuncs); await JadefinUtils.waitUntil(() => this.webpackModuleFuncs);
// this._webpackUnsafeModuleIDs = this.findUnsafeWebpackModules();
const initing = [ const initing = [
this.initHookHtmlVideoPlayer(), this.initHookHtmlVideoPlayer(),
]; ];
@ -174,21 +210,41 @@ export default JadefinIntegrity("Jadefin", import.meta.url, () => window["Jadefi
* @param {(e: any) => any} cb * @param {(e: any) => any} cb
*/ */
findWebpackRawLoad(cb) { findWebpackRawLoad(cb) {
return Object.keys(this.webpackModuleFuncs).map(id => this.webpackLoad?.(id)).filter(e => e && cb(e)); return Object.keys(this.webpackModuleFuncs).map(id => this.webpackTryLoad?.(id)).filter(e => e && cb(e));
} }
/** /**
* @param {(e: any) => any} cb * @param {(e: any) => any} cb
*/ */
findWebpackModules(cb) { findWebpackModules(cb) {
return Object.keys(this.webpackModuleFuncs).map(id => this.webpackLoad?.(id)?.default).filter(e => e && cb(e)); return Object.keys(this.webpackModuleFuncs).map(id => this.webpackTryLoad?.(id)?.default).filter(e => e && cb(e));
} }
/** /**
* @param {(e: any) => any} cb * @param {(e: any) => any} cb
*/ */
findWebpackFunctions(cb) { findWebpackFunctions(cb) {
return Object.keys(this.webpackModuleFuncs).map(id => this.webpackLoad?.(id)).filter(e => e && e instanceof Function && cb(e)); return Object.keys(this.webpackModuleFuncs).map(id => this.webpackTryLoad?.(id)).filter(e => e && e instanceof Function && cb(e));
}
/**
* @param {any} [modules]
*/
findUnsafeWebpackModules(modules) {
const unsafe = [];
for (const id of Object.keys(modules || this.webpackModuleFuncs)) {
try {
this.webpackLoad?.(id);
} catch (e) {
this.log.w(`Failed to load webpack module ${id}`);
this.log.w(this.webpackModuleFuncs[id].toString());
this.log.dir(e);
unsafe.push(id);
}
}
return unsafe;
} }
/** /**

View File

@ -89,13 +89,13 @@ export default JadefinIntegrity("JadefinModules", import.meta.url, () => window[
// escape-html // escape-html
/** @return {(text: string) => string} */ /** @return {(text: string) => string} */
get escapeHtml() { get escapeHtml() {
return this._.escapeHtml ??= this.Jadefin.findWebpackFunctions(e => e.toString().indexOf(`{switch(r.charCodeAt(a)){case 34`) != -1)[0]; return this._.escapeHtml ??= this.Jadefin.findWebpackFunctions(e => e.toString().indexOf(`charCodeAt(a)){case 34`) != -1)[0];
} }
// toast // toast
/** @return {(text: string) => void} */ /** @return {(text: string) => void} */
get toast() { get toast() {
return this._.toast ??= this.Jadefin.findWebpackRawLoad(e => (e.Z?.toString().indexOf(`toast"),t.textContent=`) || -1) != -1)[0]?.Z; return this._.toast ??= this.Jadefin.findWebpackRawLoad(e => (e.A?.toString().indexOf(`toast"),t.textContent=`) || -1) != -1)[0]?.A;
} }
// plugins/syncPlay/core/index // plugins/syncPlay/core/index
@ -108,7 +108,7 @@ export default JadefinIntegrity("JadefinModules", import.meta.url, () => window[
}} }}
*/ */
get syncPlay() { get syncPlay() {
return this._.syncPlay ??= this.Jadefin.findWebpackRawLoad(e => e.Z?.Manager?.isSyncPlayEnabled)[0]?.Z; return this._.syncPlay ??= this.Jadefin.findWebpackModules(e => e.Manager?.isSyncPlayEnabled)[0];
} }
// inputManager // inputManager
@ -131,7 +131,7 @@ export default JadefinIntegrity("JadefinModules", import.meta.url, () => window[
@return {any} @return {any}
*/ */
get playbackManager() { get playbackManager() {
return this._.playbackManager ??= this.Jadefin.findWebpackRawLoad(e => e.O?.canHandleOffsetOnCurrentSubtitle)[0]?.O; return this._.playbackManager ??= this.Jadefin.findWebpackRawLoad(e => e.f?.canHandleOffsetOnCurrentSubtitle)[0]?.f;
} }
// plugins/htmlVideoPlayer/plugin.js // plugins/htmlVideoPlayer/plugin.js
@ -156,7 +156,7 @@ export default JadefinIntegrity("JadefinModules", import.meta.url, () => window[
} }
*/ */
get taskButton() { get taskButton() {
return this._.taskButton ??= this.Jadefin.findWebpackRawLoad(e => (e.Z?.toString().indexOf(`sendMessage("ScheduledTasksInfoStart","1000,1000")`) || -1) != -1)[0]?.Z; return this._.taskButton ??= this.Jadefin.findWebpackRawLoad(e => (e.A?.toString().indexOf(`sendMessage("ScheduledTasksInfoStart","1000,1000")`) || -1) != -1)[0]?.A;
} }
// browser // browser
@ -202,7 +202,7 @@ export default JadefinIntegrity("JadefinModules", import.meta.url, () => window[
}} }}
*/ */
get browser() { get browser() {
return this._.browser ??= this.Jadefin.findWebpackRawLoad(e => e.Z && "supportsCssAnimation" in e.Z && "version" in e.Z)[0]?.Z; return this._.browser ??= this.Jadefin.findWebpackRawLoad(e => typeof(e.A) == "object" && "supportsCssAnimation" in e.A && "version" in e.A)[0]?.A;
} }
// datetime // datetime
@ -220,7 +220,7 @@ export default JadefinIntegrity("JadefinModules", import.meta.url, () => window[
}} }}
*/ */
get datetime() { get datetime() {
return this._.datetime ??= this.Jadefin.findWebpackRawLoad(e => e.ZP?.getDisplayRunningTime)[0]?.ZP; return this._.datetime ??= this.Jadefin.findWebpackRawLoad(e => e.Ay?.getDisplayRunningTime)[0]?.Ay;
} }
// events // events

View File

@ -29,11 +29,11 @@ export default JadefinIntegrity("JadefinUtils", import.meta.url, () => window["J
} }
get routePath() { get routePath() {
return JadefinModules.Emby.Page.currentRouteInfo.route.path; return JadefinModules.Emby.Page.currentRouteInfo.path;
} }
get routePathIsVideo() { get routePathIsVideo() {
return this.routePath == "playback/video/index.html"; return this.routePath == "/video";
} }
get currentPlayer() { get currentPlayer() {

31
init.js
View File

@ -2,6 +2,37 @@
let jadefinInit = /** @type {HTMLScriptElement} */ (document.currentScript); let jadefinInit = /** @type {HTMLScriptElement} */ (document.currentScript);
function jadefinInitExtremelyEarly() {
// Required for mods to be able to replace some things.
// Might or might not horribly wreck everything.
const defineProperty = this._Object_defineProperty = Object.defineProperty.bind(Object);
const defineProperties = this._Object_defineProperties = Object.defineProperties.bind(Object);
Object.defineProperty = (obj, prop, descriptor) => {
if (descriptor && prop != "prototype") {
descriptor.configurable = true;
}
return defineProperty(obj, prop, descriptor);
};
Object.defineProperties = (obj, props) => {
if (props) {
for (const prop of Object.keys(props)) {
const descriptor = props[prop];
if (descriptor && prop != "prototype") {
descriptor.configurable = true;
}
}
}
return defineProperties(obj, props);
};
}
jadefinInitExtremelyEarly();
(() => { (() => {
let loadedJellyfin = false; let loadedJellyfin = false;
let initedJadefin = false; let initedJadefin = false;

View File

@ -212,7 +212,7 @@ export default JadefinIntegrity("InputEater", import.meta.url, () => new (class
} }
initHookMediaSessionHandlers() { initHookMediaSessionHandlers() {
const owner = Jadefin.findWebpackRawLoad(e => e?.O?.nextTrack && e?.O?.fastForward)[0].O; const owner = Jadefin.findWebpackRawLoad(e => e?.f?.nextTrack && e?.f?.fastForward)[0].f;
if (!owner || !("mediaSession" in navigator)) { if (!owner || !("mediaSession" in navigator)) {
this.log.e("Couldn't hook media session handlers"); this.log.e("Couldn't hook media session handlers");

View File

@ -35,7 +35,7 @@ div#videoOsdPage .osdTranscript .line {
scroll-snap-align: end; scroll-snap-align: end;
--bg: #000000; --bg: #000000;
--bg-opacity: 0.25; --bg-opacity: 0.25;
--bar: rgb(var(--accent, 0x00, 0xad, 0xee)); --bar: var(--transcript-accent, #00adee);
--bar-opacity: 0; --bar-opacity: 0;
} }
body:not([input-eaten=true]) div#videoOsdPage .osdTranscript .line { body:not([input-eaten=true]) div#videoOsdPage .osdTranscript .line {

View File

@ -25,10 +25,10 @@ export default JadefinIntegrity("PatchAndroidHLSJS", import.meta.url, () => new
async init(name, url) { async init(name, url) {
await super.init(name, url); await super.init(name, url);
const htmlMediaHelper = this.htmlMediaPlayer = Jadefin.findWebpackRawLoad(e => (e.rR?.toString().indexOf("x-mpegURL") || -1) != -1)[0]; const htmlMediaHelper = this.htmlMediaPlayer = Jadefin.findWebpackRawLoad(e => (e.JQ?.toString().indexOf("x-mpegURL") || -1) != -1)[0];
this._enableHlsJsPlayer = htmlMediaHelper.rR.bind(htmlMediaHelper); this._enableHlsJsPlayer = htmlMediaHelper.JQ.bind(htmlMediaHelper);
Object.defineProperty(htmlMediaHelper, "rR", { get: () => this.enableHlsJsPlayer }); Object.defineProperty(htmlMediaHelper, "JQ", { get: () => this.enableHlsJsPlayer });
const ExtrasMenu = /** @type {import("../ExtrasMenu.js").default} */ (Jadefin.getMod("ExtrasMenu")); const ExtrasMenu = /** @type {import("../ExtrasMenu.js").default} */ (Jadefin.getMod("ExtrasMenu"));