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
|
.htaccess
|
||||||
/priv/
|
/priv/
|
||||||
/.vscode/
|
/.vscode/
|
||||||
|
update.sh
|
||||||
|
120
Jadefin.js
120
Jadefin.js
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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
|
||||||
|
@ -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
31
init.js
@ -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;
|
||||||
|
@ -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");
|
||||||
|
@ -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 {
|
||||||
|
@ -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"));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user