Initial attempt at updating for 10.9
This commit is contained in:
parent
0cce72b24b
commit
e8c3154a79
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
.htaccess
|
||||
/priv/
|
||||
/.vscode/
|
||||
update.sh
|
||||
|
120
Jadefin.js
120
Jadefin.js
@ -41,33 +41,6 @@ export default JadefinIntegrity("Jadefin", import.meta.url, () => window["Jadefi
|
||||
}
|
||||
|
||||
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.
|
||||
window.Worker = (class Worker extends window.Worker {
|
||||
constructor(scriptURL, options) {
|
||||
@ -92,6 +65,8 @@ export default JadefinIntegrity("Jadefin", import.meta.url, () => window["Jadefi
|
||||
}
|
||||
|
||||
async init(base) {
|
||||
const self = this;
|
||||
|
||||
await super.init("Jadefin", this.modUrl);
|
||||
|
||||
// Wait until webpackChunk and Emby exist.
|
||||
@ -108,10 +83,71 @@ export default JadefinIntegrity("Jadefin", import.meta.url, () => window["Jadefi
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait until webpackChunk and Emby exist.
|
||||
// It might be delayed due to the main jellyfin bundle being replaced by an inject script on Android.
|
||||
/** @type {(id: number | string) => any} */
|
||||
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);
|
||||
|
||||
// this._webpackUnsafeModuleIDs = this.findUnsafeWebpackModules();
|
||||
|
||||
const initing = [
|
||||
this.initHookHtmlVideoPlayer(),
|
||||
];
|
||||
@ -174,21 +210,41 @@ export default JadefinIntegrity("Jadefin", import.meta.url, () => window["Jadefi
|
||||
* @param {(e: any) => any} 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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -89,13 +89,13 @@ export default JadefinIntegrity("JadefinModules", import.meta.url, () => window[
|
||||
// escape-html
|
||||
/** @return {(text: string) => string} */
|
||||
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
|
||||
/** @return {(text: string) => void} */
|
||||
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
|
||||
@ -108,7 +108,7 @@ export default JadefinIntegrity("JadefinModules", import.meta.url, () => window[
|
||||
}}
|
||||
*/
|
||||
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
|
||||
@ -131,7 +131,7 @@ export default JadefinIntegrity("JadefinModules", import.meta.url, () => window[
|
||||
@return {any}
|
||||
*/
|
||||
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
|
||||
@ -156,7 +156,7 @@ export default JadefinIntegrity("JadefinModules", import.meta.url, () => window[
|
||||
}
|
||||
*/
|
||||
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
|
||||
@ -202,7 +202,7 @@ export default JadefinIntegrity("JadefinModules", import.meta.url, () => window[
|
||||
}}
|
||||
*/
|
||||
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
|
||||
@ -220,7 +220,7 @@ export default JadefinIntegrity("JadefinModules", import.meta.url, () => window[
|
||||
}}
|
||||
*/
|
||||
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
|
||||
|
@ -29,11 +29,11 @@ export default JadefinIntegrity("JadefinUtils", import.meta.url, () => window["J
|
||||
}
|
||||
|
||||
get routePath() {
|
||||
return JadefinModules.Emby.Page.currentRouteInfo.route.path;
|
||||
return JadefinModules.Emby.Page.currentRouteInfo.path;
|
||||
}
|
||||
|
||||
get routePathIsVideo() {
|
||||
return this.routePath == "playback/video/index.html";
|
||||
return this.routePath == "/video";
|
||||
}
|
||||
|
||||
get currentPlayer() {
|
||||
|
31
init.js
31
init.js
@ -2,6 +2,37 @@
|
||||
|
||||
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 initedJadefin = false;
|
||||
|
@ -212,7 +212,7 @@ export default JadefinIntegrity("InputEater", import.meta.url, () => new (class
|
||||
}
|
||||
|
||||
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)) {
|
||||
this.log.e("Couldn't hook media session handlers");
|
||||
|
@ -35,7 +35,7 @@ div#videoOsdPage .osdTranscript .line {
|
||||
scroll-snap-align: end;
|
||||
--bg: #000000;
|
||||
--bg-opacity: 0.25;
|
||||
--bar: rgb(var(--accent, 0x00, 0xad, 0xee));
|
||||
--bar: var(--transcript-accent, #00adee);
|
||||
--bar-opacity: 0;
|
||||
}
|
||||
body:not([input-eaten=true]) div#videoOsdPage .osdTranscript .line {
|
||||
|
@ -25,10 +25,10 @@ export default JadefinIntegrity("PatchAndroidHLSJS", import.meta.url, () => new
|
||||
async init(name, url) {
|
||||
await super.init(name, url);
|
||||
|
||||
const htmlMediaHelper = this.htmlMediaPlayer = Jadefin.findWebpackRawLoad(e => (e.rR?.toString().indexOf("x-mpegURL") || -1) != -1)[0];
|
||||
this._enableHlsJsPlayer = htmlMediaHelper.rR.bind(htmlMediaHelper);
|
||||
const htmlMediaHelper = this.htmlMediaPlayer = Jadefin.findWebpackRawLoad(e => (e.JQ?.toString().indexOf("x-mpegURL") || -1) != -1)[0];
|
||||
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"));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user