5
5
// @supportURL https://github.com/Xmader/musescore-downloader/issues
6
6
// @updateURL https://msdl.librescore.org/install.user.js
7
7
// @downloadURL https://msdl.librescore.org/install.user.js
8
- // @version 0.24.3
8
+ // @version 0.25.0
9
9
// @description download sheet music from musescore.com for free, no login or Musescore Pro required | 免登录、免 Musescore Pro,免费下载 musescore.com 上的曲谱
10
10
// @author Xmader
11
11
// @icon https://librescore.org/img/icons/logo.svg
348
348
// eslint-disable-next-line @typescript-eslint/no-var-requires
349
349
const nodeFetch = require('node-fetch');
350
350
return (input, init) => {
351
+ if (typeof input === 'string' && !input.startsWith('http')) { // fix: Only absolute URLs are supported
352
+ input = 'https://musescore.com' + input;
353
+ }
351
354
init = Object.assign({ headers: NODE_FETCH_HEADERS }, init);
352
355
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
353
356
return nodeFetch(input, init);
417
420
targetEl.setAttribute(eventName, `this['${id}'](document.createElement('iframe'))`);
418
421
});
419
422
});
420
- const console$1 = (window || global).console; // Object.is(window.console, unsafeWindow.console) == false
423
+ const console$1 = (typeof window !== 'undefined' ? window : global).console; // Object.is(window.console, unsafeWindow.console) == false
421
424
const windowOpenAsync = (targetEl, ...args) => {
422
425
return getSandboxWindowAsync(targetEl).then(w => w.open(...args));
423
426
};
@@ -26575,13 +26578,15 @@ Please pipe the document into a Node stream.\
26575
26578
}
26576
26579
}
26577
26580
26578
- /* eslint-disable no-extend-native */
26579
26581
const TYPE_REG = /type=(img|mp3|midi)/;
26580
26582
/**
26581
26583
* I know this is super hacky.
26582
26584
*/
26583
26585
const magicHookConstr = (() => {
26584
26586
const l = {};
26587
+ if (detectNode) { // noop in CLI
26588
+ return () => Promise.resolve('');
26589
+ }
26585
26590
try {
26586
26591
const p = Object.getPrototypeOf(document.body);
26587
26592
Object.setPrototypeOf(document.body, null);
@@ -26597,7 +26602,7 @@ Please pipe the document into a Node stream.\
26597
26602
const token = (_a = init === null || init === void 0 ? void 0 : init.headers) === null || _a === void 0 ? void 0 : _a.Authorization;
26598
26603
if (typeof url === 'string' && token) {
26599
26604
const m = url.match(TYPE_REG);
26600
- console$1 .debug(url, token, m);
26605
+ console.debug(url, token, m);
26601
26606
if (m) {
26602
26607
const type = m[1];
26603
26608
// eslint-disable-next-line no-unused-expressions
@@ -26613,7 +26618,7 @@ Please pipe the document into a Node stream.\
26613
26618
Object.setPrototypeOf(document.body, p);
26614
26619
}
26615
26620
catch (err) {
26616
- console$1 .error(err);
26621
+ console.error(err);
26617
26622
}
26618
26623
return (type) => __awaiter(void 0, void 0, void 0, function* () {
26619
26624
return new Promise((resolve) => {
@@ -26629,51 +26634,70 @@ Please pipe the document into a Node stream.\
26629
26634
midi: magicHookConstr('midi'),
26630
26635
mp3: magicHookConstr('mp3'),
26631
26636
};
26637
+
26638
+ /* eslint-disable no-extend-native */
26632
26639
const getApiUrl = (id, type, index) => {
26633
26640
return `/api/jmuse?id=${id}&type=${type}&index=${index}&v2=1`;
26634
26641
};
26642
+ /**
26643
+ * hard-coded auth tokens
26644
+ */
26645
+ const useBuiltinAuth = (type) => {
26646
+ switch (type) {
26647
+ case 'img': return '8c022bdef45341074ce876ae57a48f64b86cdcf5';
26648
+ case 'midi': return '38fb9efaae51b0c83b5bb5791a698b48292129e7';
26649
+ case 'mp3': return '63794e5461e4cfa046edfbdddfccc1ac16daffd2';
26650
+ }
26651
+ };
26635
26652
const getApiAuth = (type, index) => __awaiter(void 0, void 0, void 0, function* () {
26636
- var _a;
26653
+ var _a, _b, _c;
26654
+ if (detectNode) {
26655
+ // we cannot intercept API requests in Node.js (as no requests are sent), so go straightforward to the hard-coded tokens
26656
+ return useBuiltinAuth(type);
26657
+ }
26637
26658
const magic = magics[type];
26638
26659
if (magic instanceof Promise) {
26639
26660
// force to retrieve the MAGIC
26640
- switch (type) {
26641
- case 'midi': {
26642
- const el = document.querySelector('button[hasaccess]');
26643
- el.click();
26644
- break;
26645
- }
26646
- case 'mp3': {
26647
- const el = document.querySelector('button[title="Toggle Play"]');
26648
- el.click();
26649
- break;
26650
- }
26651
- case 'img': {
26652
- const imgE = document.querySelector('img[src*=score_]');
26653
- const nextE = (_a = imgE === null || imgE === void 0 ? void 0 : imgE.parentElement) === null || _a === void 0 ? void 0 : _a.nextElementSibling;
26654
- if (nextE)
26655
- nextE.scrollIntoView();
26656
- break;
26661
+ try {
26662
+ switch (type) {
26663
+ case 'midi': {
26664
+ const fsBtn = document.querySelector('button[title="Toggle Fullscreen"]');
26665
+ const el = (_b = (_a = fsBtn.parentElement) === null || _a === void 0 ? void 0 : _a.parentElement) === null || _b === void 0 ? void 0 : _b.querySelector('button');
26666
+ el.click();
26667
+ break;
26668
+ }
26669
+ case 'mp3': {
26670
+ const el = document.querySelector('button[title="Toggle Play"]');
26671
+ el.click();
26672
+ break;
26673
+ }
26674
+ case 'img': {
26675
+ const imgE = document.querySelector('img[src*=score_]');
26676
+ const nextE = (_c = imgE === null || imgE === void 0 ? void 0 : imgE.parentElement) === null || _c === void 0 ? void 0 : _c.nextElementSibling;
26677
+ if (nextE)
26678
+ nextE.scrollIntoView();
26679
+ break;
26680
+ }
26657
26681
}
26658
26682
}
26683
+ catch (err) {
26684
+ console.error(err);
26685
+ return useBuiltinAuth(type);
26686
+ }
26659
26687
}
26660
26688
try {
26661
26689
return yield useTimeout(magic, 5 * 1000 /* 5s */);
26662
26690
}
26663
- catch (_b) {
26664
- console$1.error(type, 'token timeout');
26665
- switch (type) {
26666
- // try hard-coded tokens
26667
- case 'img': return '8c022bdef45341074ce876ae57a48f64b86cdcf5';
26668
- case 'midi': return '38fb9efaae51b0c83b5bb5791a698b48292129e7';
26669
- case 'mp3': return '63794e5461e4cfa046edfbdddfccc1ac16daffd2';
26670
- }
26691
+ catch (_d) {
26692
+ console.error(type, 'token timeout');
26693
+ // try hard-coded tokens
26694
+ return useBuiltinAuth(type);
26671
26695
}
26672
26696
});
26673
- const getFileUrl = (id, type, index = 0) => __awaiter(void 0, void 0, void 0, function* () {
26697
+ const getFileUrl = (id, type, index = 0, _fetch = getFetch() ) => __awaiter(void 0, void 0, void 0, function* () {
26674
26698
const url = getApiUrl(id, type, index);
26675
26699
const auth = yield getApiAuth(type);
26676
- const r = yield fetch (url, {
26700
+ const r = yield _fetch (url, {
26677
26701
headers: {
26678
26702
Authorization: auth,
26679
26703
},
@@ -27273,15 +27297,19 @@ Please pipe the document into a Node stream.\
27273
27297
BtnAction.openUrl = BtnAction.download;
27274
27298
BtnAction.mscoreWindow = (scoreinfo, fn) => {
27275
27299
return (btnName, btn, setText) => __awaiter(this, void 0, void 0, function* () {
27300
+ // save btn event for later use
27276
27301
const _onclick = btn.onclick;
27302
+ // clear btn event
27277
27303
btn.onclick = null;
27304
+ // set btn text to "PROCESSING"
27278
27305
setText(i18n('PROCESSING')());
27306
+ // open a new tab
27279
27307
const w = yield windowOpenAsync(btn, '');
27308
+ // add texts to the new tab
27280
27309
const txt = document.createTextNode(i18n('PROCESSING')());
27281
27310
w.document.body.append(txt);
27282
- // set page hooks
27283
- // eslint-disable-next-line prefer-const
27284
- let score;
27311
+ // set page hooks that the new tab also closes as the og tab closes
27312
+ let score; // eslint-disable-line prefer-const
27285
27313
const destroy = () => {
27286
27314
score && score.destroy();
27287
27315
w.close();
@@ -27290,13 +27318,38 @@ Please pipe the document into a Node stream.\
27290
27318
w.addEventListener('beforeunload', () => {
27291
27319
score && score.destroy();
27292
27320
window.removeEventListener('unload', destroy);
27321
+ // reset btn text
27293
27322
setText(btnName);
27323
+ // reinstate btn event
27294
27324
btn.onclick = _onclick;
27295
27325
});
27296
- score = yield loadMscore(scoreinfo, w);
27297
- fn(w, score, txt);
27326
+ try {
27327
+ // fetch mscz & process using mscore
27328
+ score = yield loadMscore(scoreinfo, w);
27329
+ fn(w, score, txt);
27330
+ }
27331
+ catch (err) {
27332
+ console$1.error(err);
27333
+ // close the new tab & show error popup
27334
+ w.close();
27335
+ BtnAction.errorPopup()(btnName, btn, setText);
27336
+ }
27298
27337
});
27299
27338
};
27339
+ BtnAction.errorPopup = () => {
27340
+ return (btnName, btn, setText) => {
27341
+ setText(i18n('BTN_ERROR')());
27342
+ // ask user to send Discord message
27343
+ alert('❌Download Failed!\n\n' +
27344
+ 'Send your URL to the #dataset-patcher channel ' +
27345
+ 'in the LibreScore Community Discord server:\n' + DISCORD_URL);
27346
+ // open Discord on 'OK'
27347
+ const a = document.createElement('a');
27348
+ a.href = DISCORD_URL;
27349
+ a.target = '_blank';
27350
+ a.dispatchEvent(new MouseEvent('click'));
27351
+ };
27352
+ };
27300
27353
BtnAction.process = (fn, fallback, timeout = 10 * 60 * 1000 /* 10min */) => {
27301
27354
return (name, btn, setText) => __awaiter(this, void 0, void 0, function* () {
27302
27355
const _onclick = btn.onclick;
@@ -27314,16 +27367,7 @@ Please pipe the document into a Node stream.\
27314
27367
setText(name);
27315
27368
}
27316
27369
else {
27317
- setText(i18n('BTN_ERROR')());
27318
- // ask user to send Discord message
27319
- alert('❌Download Failed!\n\n' +
27320
- 'Send your URL to the #dataset-patcher channel ' +
27321
- 'in the LibreScore Community Discord server:\n' + DISCORD_URL);
27322
- // open Discord on 'OK'
27323
- const a = document.createElement('a');
27324
- a.href = DISCORD_URL;
27325
- a.target = '_blank';
27326
- a.dispatchEvent(new MouseEvent('click'));
27370
+ BtnAction.errorPopup()(name, btn, setText);
27327
27371
}
27328
27372
}
27329
27373
btn.onclick = _onclick;
0 commit comments