1
0
mirror of https://github.com/LibreScore/dl-librescore synced 2025-01-22 01:50:52 +01:00

fix: PDF downloads

This commit is contained in:
Peter Njeim 2024-02-10 02:19:22 -04:00
parent c5bd971da5
commit 772e7b37a1
2 changed files with 84 additions and 67 deletions

@ -3,13 +3,13 @@ import { hookNative } from "./anti-detection";
import type { FileType } from "./file";
const TYPE_REG = /type=(img|mp3|midi)/;
// first page has different URL
const INIT_PAGE_REG = /(score_0\.png@0|score_0\.svg)/;
const INDEX_REG = /index=(\d+)/;
/**
* I know this is super hacky.
*/
const magicHookConstr = (() => {
const l = {};
export const auths = {};
(() => {
if (isNodeJs) {
// noop in CLI
return () => Promise.resolve("");
@ -29,14 +29,20 @@ const magicHookConstr = (() => {
hookNative(w, "fetch", () => {
return function (url, init) {
const token = init?.headers?.Authorization;
if (typeof url === "string" && token) {
const m = url.match(TYPE_REG);
console.debug(url, token, m);
if (m) {
let token = init?.headers?.Authorization;
if (
typeof url === "string" &&
(token || url.match(INIT_PAGE_REG))
) {
let m = url.match(TYPE_REG);
let i = url.match(INDEX_REG);
if (m && i) {
// console.log(url, token, m[1], i[1]);
const type = m[1];
// eslint-disable-next-line no-unused-expressions
l[type]?.(token);
const index = i[1];
auths[type + index] = token;
} else if (url.match(INIT_PAGE_REG)) {
auths["img0"] = url;
}
}
return fetch(url, init);
@ -50,19 +56,4 @@ const magicHookConstr = (() => {
} catch (err) {
console.error(err);
}
return async (type: FileType) => {
return new Promise<string>((resolve) => {
l[type] = (token) => {
resolve(token);
magics[type] = token;
};
});
};
})();
export const magics: Record<FileType, Promise<string>> = {
img: magicHookConstr("img"),
midi: magicHookConstr("midi"),
mp3: magicHookConstr("mp3"),
};

@ -2,8 +2,8 @@
/* eslint-disable @typescript-eslint/no-unsafe-return */
import isNodeJs from "detect-node";
import { useTimeout, getFetch } from "./utils";
import { magics } from "./file-magics";
import { getFetch } from "./utils";
import { auths } from "./file-magics";
export type FileType = "img" | "mp3" | "midi";
@ -11,29 +11,17 @@ const getApiUrl = (id: number, type: FileType, index: number): string => {
return `/api/jmuse?id=${id}&type=${type}&index=${index}`;
};
/**
* hard-coded auth tokens
*/
const useBuiltinAuth = (type: FileType): string => {
switch (type) {
case "img":
return "8c022bdef45341074ce876ae57a48f64b86cdcf5";
case "midi":
return "38fb9efaae51b0c83b5bb5791a698b48292129e7";
case "mp3":
return "63794e5461e4cfa046edfbdddfccc1ac16daffd2";
}
};
let imgInProgress = false;
const getApiAuth = async (type: FileType, index: number): Promise<string> => {
if (isNodeJs) {
// we cannot intercept API requests in Node.js (as no requests are sent), so go straightforward to the hard-coded tokens
return useBuiltinAuth(type);
// fix later
throw Error;
}
const magic = magics[type];
if (magic instanceof Promise) {
// force to retrieve the MAGIC
let numPages = 0;
let pageCooldown = 25;
if (!auths[type + index]) {
try {
switch (type) {
case "midi": {
@ -51,10 +39,6 @@ const getApiAuth = async (type: FileType, index: number): Promise<string> => {
break;
}
case "mp3": {
// Mobile doesn't support click() function, find another method
if (navigator.userAgentData.mobile) {
throw Error;
}
const el = document.querySelector(
'button[title="Toggle Play"]'
) as HTMLButtonElement;
@ -62,23 +46,69 @@ const getApiAuth = async (type: FileType, index: number): Promise<string> => {
break;
}
case "img": {
// Use fallback until better method is found
throw Error;
if (!imgInProgress) {
imgInProgress = true;
let parentDiv = document.querySelector(
"#jmuse-scroller-component"
)!;
numPages = parentDiv.children.length - 3;
let i = 0;
function scrollToNextChild() {
let childDiv = parentDiv.children[i];
if (childDiv) {
childDiv.scrollIntoView();
}
i++;
if (i < numPages) {
setTimeout(scrollToNextChild, pageCooldown);
}
}
scrollToNextChild();
}
imgInProgress = false;
break;
}
}
} catch (err) {
console.error(err);
return useBuiltinAuth(type);
throw Error;
}
}
try {
return await useTimeout(magic, 5 * 1000 /* 5s */);
return new Promise((resolve, reject) => {
let timer = setTimeout(
() => {
reject(new Error("token timeout"));
},
type === "img"
? numPages * pageCooldown * 2 + 2100
: 5 * 1000 /* 5s */
);
// Check the auths object periodically
let interval = setInterval(() => {
if (auths.hasOwnProperty(type + index)) {
clearTimeout(timer);
clearInterval(interval);
setInterval(
() => {
resolve(auths[type + index]);
},
// long delay for images to give time for them to load fully
type === "img" ? 2000 : 100
);
}
}, 100);
});
} catch {
console.error(type, "token timeout");
// try hard-coded tokens
return useBuiltinAuth(type);
throw Error;
}
};
@ -88,23 +118,19 @@ export const getFileUrl = async (
index = 0,
_fetch = getFetch()
): Promise<string> => {
let r;
const url = getApiUrl(id, type, index);
const auth = await getApiAuth(type, index);
let r = await _fetch(url, {
headers: {
Authorization: auth,
},
});
if (!r.ok) {
r = await _fetch(url + "&v2=1", {
if (type === "img" && index === 0) {
// auth is the URL for the first page
r = await _fetch(auth);
} else {
r = await _fetch(url, {
headers: {
Authorization: auth,
},
});
}
const { info } = await r.json();
return info.url as string;
};