v0.7.1 - refactor, generate full score PDF by webmscore
This commit is contained in:
parent
6cc6a4a33b
commit
b50552bf12
2 changed files with 477 additions and 410 deletions
885
dist/main.js
vendored
885
dist/main.js
vendored
|
@ -3,7 +3,7 @@
|
||||||
// @namespace https://www.xmader.com/
|
// @namespace https://www.xmader.com/
|
||||||
// @homepageURL https://github.com/Xmader/musescore-downloader/
|
// @homepageURL https://github.com/Xmader/musescore-downloader/
|
||||||
// @supportURL https://github.com/Xmader/musescore-downloader/issues
|
// @supportURL https://github.com/Xmader/musescore-downloader/issues
|
||||||
// @version 0.7.0
|
// @version 0.7.1
|
||||||
// @description download sheet music from musescore.com for free, no login or Musescore Pro required | 免登录、免 Musescore Pro,免费下载 musescore.com 上的曲谱
|
// @description download sheet music from musescore.com for free, no login or Musescore Pro required | 免登录、免 Musescore Pro,免费下载 musescore.com 上的曲谱
|
||||||
// @author Xmader
|
// @author Xmader
|
||||||
// @match https://musescore.com/*/*
|
// @match https://musescore.com/*/*
|
||||||
|
@ -27,11 +27,196 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
||||||
|
|
||||||
|
function createCommonjsModule(fn, module) {
|
||||||
|
return module = { exports: {} }, fn(module, module.exports), module.exports;
|
||||||
|
}
|
||||||
|
|
||||||
|
var FileSaver = createCommonjsModule(function (module, exports) {
|
||||||
|
(function (global, factory) {
|
||||||
|
{
|
||||||
|
factory();
|
||||||
|
}
|
||||||
|
})(commonjsGlobal, function () {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FileSaver.js
|
||||||
|
* A saveAs() FileSaver implementation.
|
||||||
|
*
|
||||||
|
* By Eli Grey, http://eligrey.com
|
||||||
|
*
|
||||||
|
* License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT)
|
||||||
|
* source : http://purl.eligrey.com/github/FileSaver.js
|
||||||
|
*/
|
||||||
|
// The one and only way of getting global scope in all environments
|
||||||
|
// https://stackoverflow.com/q/3277182/1008999
|
||||||
|
var _global = typeof window === 'object' && window.window === window ? window : typeof self === 'object' && self.self === self ? self : typeof commonjsGlobal === 'object' && commonjsGlobal.global === commonjsGlobal ? commonjsGlobal : void 0;
|
||||||
|
|
||||||
|
function bom(blob, opts) {
|
||||||
|
if (typeof opts === 'undefined') opts = {
|
||||||
|
autoBom: false
|
||||||
|
};else if (typeof opts !== 'object') {
|
||||||
|
console.warn('Deprecated: Expected third argument to be a object');
|
||||||
|
opts = {
|
||||||
|
autoBom: !opts
|
||||||
|
};
|
||||||
|
} // prepend BOM for UTF-8 XML and text/* types (including HTML)
|
||||||
|
// note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
|
||||||
|
|
||||||
|
if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
|
||||||
|
return new Blob([String.fromCharCode(0xFEFF), blob], {
|
||||||
|
type: blob.type
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return blob;
|
||||||
|
}
|
||||||
|
|
||||||
|
function download(url, name, opts) {
|
||||||
|
var xhr = new XMLHttpRequest();
|
||||||
|
xhr.open('GET', url);
|
||||||
|
xhr.responseType = 'blob';
|
||||||
|
|
||||||
|
xhr.onload = function () {
|
||||||
|
saveAs(xhr.response, name, opts);
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.onerror = function () {
|
||||||
|
console.error('could not download file');
|
||||||
|
};
|
||||||
|
|
||||||
|
xhr.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
function corsEnabled(url) {
|
||||||
|
var xhr = new XMLHttpRequest(); // use sync to avoid popup blocker
|
||||||
|
|
||||||
|
xhr.open('HEAD', url, false);
|
||||||
|
|
||||||
|
try {
|
||||||
|
xhr.send();
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
return xhr.status >= 200 && xhr.status <= 299;
|
||||||
|
} // `a.click()` doesn't work for all browsers (#465)
|
||||||
|
|
||||||
|
|
||||||
|
function click(node) {
|
||||||
|
try {
|
||||||
|
node.dispatchEvent(new MouseEvent('click'));
|
||||||
|
} catch (e) {
|
||||||
|
var evt = document.createEvent('MouseEvents');
|
||||||
|
evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null);
|
||||||
|
node.dispatchEvent(evt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var saveAs = _global.saveAs || ( // probably in some web worker
|
||||||
|
typeof window !== 'object' || window !== _global ? function saveAs() {}
|
||||||
|
/* noop */
|
||||||
|
// Use download attribute first if possible (#193 Lumia mobile)
|
||||||
|
: 'download' in HTMLAnchorElement.prototype ? function saveAs(blob, name, opts) {
|
||||||
|
var URL = _global.URL || _global.webkitURL;
|
||||||
|
var a = document.createElement('a');
|
||||||
|
name = name || blob.name || 'download';
|
||||||
|
a.download = name;
|
||||||
|
a.rel = 'noopener'; // tabnabbing
|
||||||
|
// TODO: detect chrome extensions & packaged apps
|
||||||
|
// a.target = '_blank'
|
||||||
|
|
||||||
|
if (typeof blob === 'string') {
|
||||||
|
// Support regular links
|
||||||
|
a.href = blob;
|
||||||
|
|
||||||
|
if (a.origin !== location.origin) {
|
||||||
|
corsEnabled(a.href) ? download(blob, name, opts) : click(a, a.target = '_blank');
|
||||||
|
} else {
|
||||||
|
click(a);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Support blobs
|
||||||
|
a.href = URL.createObjectURL(blob);
|
||||||
|
setTimeout(function () {
|
||||||
|
URL.revokeObjectURL(a.href);
|
||||||
|
}, 4E4); // 40s
|
||||||
|
|
||||||
|
setTimeout(function () {
|
||||||
|
click(a);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
} // Use msSaveOrOpenBlob as a second approach
|
||||||
|
: 'msSaveOrOpenBlob' in navigator ? function saveAs(blob, name, opts) {
|
||||||
|
name = name || blob.name || 'download';
|
||||||
|
|
||||||
|
if (typeof blob === 'string') {
|
||||||
|
if (corsEnabled(blob)) {
|
||||||
|
download(blob, name, opts);
|
||||||
|
} else {
|
||||||
|
var a = document.createElement('a');
|
||||||
|
a.href = blob;
|
||||||
|
a.target = '_blank';
|
||||||
|
setTimeout(function () {
|
||||||
|
click(a);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
navigator.msSaveOrOpenBlob(bom(blob, opts), name);
|
||||||
|
}
|
||||||
|
} // Fallback to using FileReader and a popup
|
||||||
|
: function saveAs(blob, name, opts, popup) {
|
||||||
|
// Open a popup immediately do go around popup blocker
|
||||||
|
// Mostly only available on user interaction and the fileReader is async so...
|
||||||
|
popup = popup || open('', '_blank');
|
||||||
|
|
||||||
|
if (popup) {
|
||||||
|
popup.document.title = popup.document.body.innerText = 'downloading...';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof blob === 'string') return download(blob, name, opts);
|
||||||
|
var force = blob.type === 'application/octet-stream';
|
||||||
|
|
||||||
|
var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari;
|
||||||
|
|
||||||
|
var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent);
|
||||||
|
|
||||||
|
if ((isChromeIOS || force && isSafari) && typeof FileReader === 'object') {
|
||||||
|
// Safari doesn't allow downloading of blob URLs
|
||||||
|
var reader = new FileReader();
|
||||||
|
|
||||||
|
reader.onloadend = function () {
|
||||||
|
var url = reader.result;
|
||||||
|
url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;');
|
||||||
|
if (popup) popup.location.href = url;else location = url;
|
||||||
|
popup = null; // reverse-tabnabbing #460
|
||||||
|
};
|
||||||
|
|
||||||
|
reader.readAsDataURL(blob);
|
||||||
|
} else {
|
||||||
|
var URL = _global.URL || _global.webkitURL;
|
||||||
|
var url = URL.createObjectURL(blob);
|
||||||
|
if (popup) popup.location = url;else location.href = url;
|
||||||
|
popup = null; // reverse-tabnabbing #460
|
||||||
|
|
||||||
|
setTimeout(function () {
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
}, 4E4); // 40s
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_global.saveAs = saveAs.saveAs = saveAs;
|
||||||
|
|
||||||
|
{
|
||||||
|
module.exports = saveAs;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const saveAs = FileSaver.saveAs;
|
||||||
const waitForDocumentLoaded = () => {
|
const waitForDocumentLoaded = () => {
|
||||||
if (document.readyState !== "complete") {
|
if (document.readyState !== 'complete') {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
document.addEventListener("readystatechange", () => {
|
document.addEventListener('readystatechange', () => {
|
||||||
if (document.readyState == "complete") {
|
if (document.readyState === 'complete') {
|
||||||
resolve();
|
resolve();
|
||||||
}
|
}
|
||||||
}, { once: true });
|
}, { once: true });
|
||||||
|
@ -42,42 +227,6 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* the site key for Google reCAPTCHA v3
|
|
||||||
*/
|
|
||||||
const SITE_KEY = "6Ldxtt8UAAAAALvcRqWTlVOVIB7MmEWwN-zw_9fM";
|
|
||||||
let gr;
|
|
||||||
/**
|
|
||||||
* load reCAPTCHA
|
|
||||||
*/
|
|
||||||
const load = () => {
|
|
||||||
// load script
|
|
||||||
const script = document.createElement("script");
|
|
||||||
script.src = `https://www.recaptcha.net/recaptcha/api.js?render=${SITE_KEY}`;
|
|
||||||
script.async = true;
|
|
||||||
document.body.appendChild(script);
|
|
||||||
// add css
|
|
||||||
const style = document.createElement("style");
|
|
||||||
style.innerHTML = ".grecaptcha-badge { display: none !important; }";
|
|
||||||
document.head.appendChild(style);
|
|
||||||
return new Promise((resolve) => {
|
|
||||||
script.onload = () => {
|
|
||||||
const grecaptcha = window["grecaptcha"];
|
|
||||||
grecaptcha.ready(() => resolve(grecaptcha));
|
|
||||||
};
|
|
||||||
});
|
|
||||||
};
|
|
||||||
const init = () => {
|
|
||||||
if (!gr) {
|
|
||||||
gr = load();
|
|
||||||
}
|
|
||||||
return gr;
|
|
||||||
};
|
|
||||||
const execute = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
||||||
const captcha = yield init();
|
|
||||||
return captcha.execute(SITE_KEY, { action: "downloadmscz" });
|
|
||||||
});
|
|
||||||
|
|
||||||
var global$1 = (typeof global !== "undefined" ? global :
|
var global$1 = (typeof global !== "undefined" ? global :
|
||||||
typeof self !== "undefined" ? self :
|
typeof self !== "undefined" ? self :
|
||||||
typeof window !== "undefined" ? window : {});
|
typeof window !== "undefined" ? window : {});
|
||||||
|
@ -26073,38 +26222,6 @@ Please pipe the document into a Node stream.\
|
||||||
});
|
});
|
||||||
|
|
||||||
/// <reference lib="webworker" />
|
/// <reference lib="webworker" />
|
||||||
const generatePDF = (imgURLs, imgType, width, height) => __awaiter(void 0, void 0, void 0, function* () {
|
|
||||||
// @ts-ignore
|
|
||||||
const pdf = new PDFDocument({
|
|
||||||
// compress: true,
|
|
||||||
size: [width, height],
|
|
||||||
autoFirstPage: false,
|
|
||||||
margin: 0,
|
|
||||||
layout: "portrait",
|
|
||||||
});
|
|
||||||
if (imgType == "png") {
|
|
||||||
const imgDataUrlList = yield Promise.all(imgURLs.map(fetchDataURL));
|
|
||||||
imgDataUrlList.forEach((data) => {
|
|
||||||
pdf.addPage();
|
|
||||||
pdf.image(data, {
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else { // imgType == "svg"
|
|
||||||
const svgList = yield Promise.all(imgURLs.map(fetchText));
|
|
||||||
svgList.forEach((svg) => {
|
|
||||||
pdf.addPage();
|
|
||||||
source(pdf, svg, 0, 0, {
|
|
||||||
preserveAspectRatio: "none",
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// @ts-ignore
|
|
||||||
const buf = yield pdf.getBuffer();
|
|
||||||
return buf.buffer;
|
|
||||||
});
|
|
||||||
const getDataURL = (blob) => {
|
const getDataURL = (blob) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const reader = new FileReader();
|
const reader = new FileReader();
|
||||||
|
@ -26125,6 +26242,38 @@ Please pipe the document into a Node stream.\
|
||||||
const r = yield fetch(imgUrl);
|
const r = yield fetch(imgUrl);
|
||||||
return r.text();
|
return r.text();
|
||||||
});
|
});
|
||||||
|
const generatePDF = (imgURLs, imgType, width, height) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
|
// @ts-ignore
|
||||||
|
const pdf = new PDFDocument({
|
||||||
|
// compress: true,
|
||||||
|
size: [width, height],
|
||||||
|
autoFirstPage: false,
|
||||||
|
margin: 0,
|
||||||
|
layout: 'portrait',
|
||||||
|
});
|
||||||
|
if (imgType === 'png') {
|
||||||
|
const imgDataUrlList = yield Promise.all(imgURLs.map(fetchDataURL));
|
||||||
|
imgDataUrlList.forEach((data) => {
|
||||||
|
pdf.addPage();
|
||||||
|
pdf.image(data, {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else { // imgType == "svg"
|
||||||
|
const svgList = yield Promise.all(imgURLs.map(fetchText));
|
||||||
|
svgList.forEach((svg) => {
|
||||||
|
pdf.addPage();
|
||||||
|
source(pdf, svg, 0, 0, {
|
||||||
|
preserveAspectRatio: 'none',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// @ts-ignore
|
||||||
|
const buf = yield pdf.getBuffer();
|
||||||
|
return buf.buffer;
|
||||||
|
});
|
||||||
onmessage = (e) => __awaiter(void 0, void 0, void 0, function* () {
|
onmessage = (e) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
const [imgURLs, imgType, width, height,] = e.data;
|
const [imgURLs, imgType, width, height,] = e.data;
|
||||||
const pdfBuf = yield generatePDF(imgURLs, imgType, width, height);
|
const pdfBuf = yield generatePDF(imgURLs, imgType, width, height);
|
||||||
|
@ -26135,7 +26284,7 @@ Please pipe the document into a Node stream.\
|
||||||
};
|
};
|
||||||
|
|
||||||
const scriptUrlFromFunction = (fn) => {
|
const scriptUrlFromFunction = (fn) => {
|
||||||
const blob = new Blob(["(" + fn.toString() + ")()"], { type: "application/javascript" });
|
const blob = new Blob(['(' + fn.toString() + ')()'], { type: 'application/javascript' });
|
||||||
return URL.createObjectURL(blob);
|
return URL.createObjectURL(blob);
|
||||||
};
|
};
|
||||||
class PDFWorkerHelper extends Worker {
|
class PDFWorkerHelper extends Worker {
|
||||||
|
@ -26152,208 +26301,77 @@ Please pipe the document into a Node stream.\
|
||||||
];
|
];
|
||||||
this.postMessage(msg);
|
this.postMessage(msg);
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
this.addEventListener("message", (e) => {
|
this.addEventListener('message', (e) => {
|
||||||
resolve(e.data);
|
resolve(e.data);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
const scoreinfo = {
|
||||||
|
get playerdata() {
|
||||||
|
// @ts-ignore
|
||||||
|
return window.UGAPP.store.jmuse_settings.score_player;
|
||||||
|
},
|
||||||
|
get id() {
|
||||||
|
return this.playerdata.json.id;
|
||||||
|
},
|
||||||
|
get title() {
|
||||||
|
try {
|
||||||
|
return this.playerdata.json.metadata.title;
|
||||||
|
}
|
||||||
|
catch (_) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
get fileName() {
|
||||||
|
return this.title.replace(/[\s<>:{}"/\\|?*~.\0\cA-\cZ]+/g, '_');
|
||||||
|
},
|
||||||
|
get pageCount() {
|
||||||
|
try {
|
||||||
|
return this.playerdata.json.metadata.pages;
|
||||||
|
}
|
||||||
|
catch (_) {
|
||||||
|
return document.querySelectorAll('img[src*=score_]').length;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
get baseUrl() {
|
||||||
|
return this.playerdata.urls.image_path;
|
||||||
|
},
|
||||||
|
get mxlUrl() {
|
||||||
|
return this.baseUrl + 'score.mxl';
|
||||||
|
},
|
||||||
|
get midiUrl() {
|
||||||
|
return this.playerdata.urls.midi;
|
||||||
|
},
|
||||||
|
get mp3Url() {
|
||||||
|
return this.playerdata.urls.mp3;
|
||||||
|
},
|
||||||
|
get msczUrl() {
|
||||||
|
// https://github.com/Xmader/cloudflare-worker-musescore-mscz
|
||||||
|
return `https://musescore.now.sh/api/mscz?id=${this.id}&token=`;
|
||||||
|
},
|
||||||
|
get sheetImgType() {
|
||||||
|
try {
|
||||||
|
const imgE = document.querySelector('img[src*=score_]');
|
||||||
|
const { pathname } = new URL(imgE.src);
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
const imgtype = pathname.match(/\.(\w+)$/)[1];
|
||||||
|
return imgtype;
|
||||||
|
}
|
||||||
|
catch (_) {
|
||||||
|
// return null
|
||||||
|
return 'svg';
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
function createCommonjsModule(fn, module) {
|
|
||||||
return module = { exports: {} }, fn(module, module.exports), module.exports;
|
|
||||||
}
|
|
||||||
|
|
||||||
var FileSaver = createCommonjsModule(function (module, exports) {
|
|
||||||
(function (global, factory) {
|
|
||||||
{
|
|
||||||
factory();
|
|
||||||
}
|
|
||||||
})(commonjsGlobal, function () {
|
|
||||||
|
|
||||||
/*
|
|
||||||
* FileSaver.js
|
|
||||||
* A saveAs() FileSaver implementation.
|
|
||||||
*
|
|
||||||
* By Eli Grey, http://eligrey.com
|
|
||||||
*
|
|
||||||
* License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT)
|
|
||||||
* source : http://purl.eligrey.com/github/FileSaver.js
|
|
||||||
*/
|
|
||||||
// The one and only way of getting global scope in all environments
|
|
||||||
// https://stackoverflow.com/q/3277182/1008999
|
|
||||||
var _global = typeof window === 'object' && window.window === window ? window : typeof self === 'object' && self.self === self ? self : typeof commonjsGlobal === 'object' && commonjsGlobal.global === commonjsGlobal ? commonjsGlobal : void 0;
|
|
||||||
|
|
||||||
function bom(blob, opts) {
|
|
||||||
if (typeof opts === 'undefined') opts = {
|
|
||||||
autoBom: false
|
|
||||||
};else if (typeof opts !== 'object') {
|
|
||||||
console.warn('Deprecated: Expected third argument to be a object');
|
|
||||||
opts = {
|
|
||||||
autoBom: !opts
|
|
||||||
};
|
|
||||||
} // prepend BOM for UTF-8 XML and text/* types (including HTML)
|
|
||||||
// note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
|
|
||||||
|
|
||||||
if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
|
|
||||||
return new Blob([String.fromCharCode(0xFEFF), blob], {
|
|
||||||
type: blob.type
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return blob;
|
|
||||||
}
|
|
||||||
|
|
||||||
function download(url, name, opts) {
|
|
||||||
var xhr = new XMLHttpRequest();
|
|
||||||
xhr.open('GET', url);
|
|
||||||
xhr.responseType = 'blob';
|
|
||||||
|
|
||||||
xhr.onload = function () {
|
|
||||||
saveAs(xhr.response, name, opts);
|
|
||||||
};
|
|
||||||
|
|
||||||
xhr.onerror = function () {
|
|
||||||
console.error('could not download file');
|
|
||||||
};
|
|
||||||
|
|
||||||
xhr.send();
|
|
||||||
}
|
|
||||||
|
|
||||||
function corsEnabled(url) {
|
|
||||||
var xhr = new XMLHttpRequest(); // use sync to avoid popup blocker
|
|
||||||
|
|
||||||
xhr.open('HEAD', url, false);
|
|
||||||
|
|
||||||
try {
|
|
||||||
xhr.send();
|
|
||||||
} catch (e) {}
|
|
||||||
|
|
||||||
return xhr.status >= 200 && xhr.status <= 299;
|
|
||||||
} // `a.click()` doesn't work for all browsers (#465)
|
|
||||||
|
|
||||||
|
|
||||||
function click(node) {
|
|
||||||
try {
|
|
||||||
node.dispatchEvent(new MouseEvent('click'));
|
|
||||||
} catch (e) {
|
|
||||||
var evt = document.createEvent('MouseEvents');
|
|
||||||
evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null);
|
|
||||||
node.dispatchEvent(evt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var saveAs = _global.saveAs || ( // probably in some web worker
|
|
||||||
typeof window !== 'object' || window !== _global ? function saveAs() {}
|
|
||||||
/* noop */
|
|
||||||
// Use download attribute first if possible (#193 Lumia mobile)
|
|
||||||
: 'download' in HTMLAnchorElement.prototype ? function saveAs(blob, name, opts) {
|
|
||||||
var URL = _global.URL || _global.webkitURL;
|
|
||||||
var a = document.createElement('a');
|
|
||||||
name = name || blob.name || 'download';
|
|
||||||
a.download = name;
|
|
||||||
a.rel = 'noopener'; // tabnabbing
|
|
||||||
// TODO: detect chrome extensions & packaged apps
|
|
||||||
// a.target = '_blank'
|
|
||||||
|
|
||||||
if (typeof blob === 'string') {
|
|
||||||
// Support regular links
|
|
||||||
a.href = blob;
|
|
||||||
|
|
||||||
if (a.origin !== location.origin) {
|
|
||||||
corsEnabled(a.href) ? download(blob, name, opts) : click(a, a.target = '_blank');
|
|
||||||
} else {
|
|
||||||
click(a);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Support blobs
|
|
||||||
a.href = URL.createObjectURL(blob);
|
|
||||||
setTimeout(function () {
|
|
||||||
URL.revokeObjectURL(a.href);
|
|
||||||
}, 4E4); // 40s
|
|
||||||
|
|
||||||
setTimeout(function () {
|
|
||||||
click(a);
|
|
||||||
}, 0);
|
|
||||||
}
|
|
||||||
} // Use msSaveOrOpenBlob as a second approach
|
|
||||||
: 'msSaveOrOpenBlob' in navigator ? function saveAs(blob, name, opts) {
|
|
||||||
name = name || blob.name || 'download';
|
|
||||||
|
|
||||||
if (typeof blob === 'string') {
|
|
||||||
if (corsEnabled(blob)) {
|
|
||||||
download(blob, name, opts);
|
|
||||||
} else {
|
|
||||||
var a = document.createElement('a');
|
|
||||||
a.href = blob;
|
|
||||||
a.target = '_blank';
|
|
||||||
setTimeout(function () {
|
|
||||||
click(a);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
navigator.msSaveOrOpenBlob(bom(blob, opts), name);
|
|
||||||
}
|
|
||||||
} // Fallback to using FileReader and a popup
|
|
||||||
: function saveAs(blob, name, opts, popup) {
|
|
||||||
// Open a popup immediately do go around popup blocker
|
|
||||||
// Mostly only available on user interaction and the fileReader is async so...
|
|
||||||
popup = popup || open('', '_blank');
|
|
||||||
|
|
||||||
if (popup) {
|
|
||||||
popup.document.title = popup.document.body.innerText = 'downloading...';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof blob === 'string') return download(blob, name, opts);
|
|
||||||
var force = blob.type === 'application/octet-stream';
|
|
||||||
|
|
||||||
var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari;
|
|
||||||
|
|
||||||
var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent);
|
|
||||||
|
|
||||||
if ((isChromeIOS || force && isSafari) && typeof FileReader === 'object') {
|
|
||||||
// Safari doesn't allow downloading of blob URLs
|
|
||||||
var reader = new FileReader();
|
|
||||||
|
|
||||||
reader.onloadend = function () {
|
|
||||||
var url = reader.result;
|
|
||||||
url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;');
|
|
||||||
if (popup) popup.location.href = url;else location = url;
|
|
||||||
popup = null; // reverse-tabnabbing #460
|
|
||||||
};
|
|
||||||
|
|
||||||
reader.readAsDataURL(blob);
|
|
||||||
} else {
|
|
||||||
var URL = _global.URL || _global.webkitURL;
|
|
||||||
var url = URL.createObjectURL(blob);
|
|
||||||
if (popup) popup.location = url;else location.href = url;
|
|
||||||
popup = null; // reverse-tabnabbing #460
|
|
||||||
|
|
||||||
setTimeout(function () {
|
|
||||||
URL.revokeObjectURL(url);
|
|
||||||
}, 4E4); // 40s
|
|
||||||
}
|
|
||||||
});
|
|
||||||
_global.saveAs = saveAs.saveAs = saveAs;
|
|
||||||
|
|
||||||
{
|
|
||||||
module.exports = saveAs;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const saveAs = FileSaver.saveAs;
|
|
||||||
const PROCESSING_TEXT = "Processing…";
|
|
||||||
const FAILED_TEXT = "❌Download Failed!";
|
|
||||||
const WEBMSCORE_URL = "https://cdn.jsdelivr.net/npm/webmscore@0.5/webmscore.js";
|
|
||||||
let pdfBlob;
|
let pdfBlob;
|
||||||
let msczBufferP;
|
const _downloadPDF = (imgURLs, imgType, name) => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
const generatePDF = (imgURLs, imgType, name) => __awaiter(void 0, void 0, void 0, function* () {
|
|
||||||
if (pdfBlob) {
|
if (pdfBlob) {
|
||||||
return saveAs(pdfBlob, `${name}.pdf`);
|
return saveAs(pdfBlob, `${name}.pdf`);
|
||||||
}
|
}
|
||||||
const cachedImg = document.querySelector("img[src*=score_]");
|
const cachedImg = document.querySelector('img[src*=score_]');
|
||||||
const { naturalWidth: width, naturalHeight: height } = cachedImg;
|
const { naturalWidth: width, naturalHeight: height } = cachedImg;
|
||||||
const worker = new PDFWorkerHelper();
|
const worker = new PDFWorkerHelper();
|
||||||
const pdfArrayBuffer = yield worker.generatePDF(imgURLs, imgType, width, height);
|
const pdfArrayBuffer = yield worker.generatePDF(imgURLs, imgType, width, height);
|
||||||
|
@ -26361,38 +26379,55 @@ Please pipe the document into a Node stream.\
|
||||||
pdfBlob = new Blob([pdfArrayBuffer]);
|
pdfBlob = new Blob([pdfArrayBuffer]);
|
||||||
saveAs(pdfBlob, `${name}.pdf`);
|
saveAs(pdfBlob, `${name}.pdf`);
|
||||||
});
|
});
|
||||||
const getPagesNumber = (scorePlayerData) => {
|
const downloadPDF = () => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
try {
|
const imgType = scoreinfo.sheetImgType;
|
||||||
return scorePlayerData.json.metadata.pages;
|
const pageCount = scoreinfo.pageCount;
|
||||||
}
|
const sheetImgURLs = Array.from({ length: pageCount }).map((_, i) => {
|
||||||
catch (_) {
|
return scoreinfo.baseUrl + `score_${i}.${imgType}`;
|
||||||
return document.querySelectorAll("img[src*=score_]").length;
|
});
|
||||||
}
|
return _downloadPDF(sheetImgURLs, imgType, scoreinfo.fileName);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the site key for Google reCAPTCHA v3
|
||||||
|
*/
|
||||||
|
const SITE_KEY = '6Ldxtt8UAAAAALvcRqWTlVOVIB7MmEWwN-zw_9fM';
|
||||||
|
let gr;
|
||||||
|
/**
|
||||||
|
* load reCAPTCHA
|
||||||
|
*/
|
||||||
|
const load = () => {
|
||||||
|
// load script
|
||||||
|
const script = document.createElement('script');
|
||||||
|
script.src = `https://www.recaptcha.net/recaptcha/api.js?render=${SITE_KEY}`;
|
||||||
|
script.async = true;
|
||||||
|
document.body.appendChild(script);
|
||||||
|
// add css
|
||||||
|
const style = document.createElement('style');
|
||||||
|
style.innerHTML = '.grecaptcha-badge { display: none !important; }';
|
||||||
|
document.head.appendChild(style);
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
script.onload = () => {
|
||||||
|
const grecaptcha = window['grecaptcha'];
|
||||||
|
grecaptcha.ready(() => resolve(grecaptcha));
|
||||||
|
};
|
||||||
|
});
|
||||||
};
|
};
|
||||||
const getImgType = () => {
|
const init = () => {
|
||||||
try {
|
if (!gr) {
|
||||||
const imgE = document.querySelector("img[src*=score_]");
|
gr = load();
|
||||||
const { pathname } = new URL(imgE.src);
|
|
||||||
const imgtype = pathname.match(/\.(\w+)$/)[1];
|
|
||||||
return imgtype;
|
|
||||||
}
|
|
||||||
catch (_) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
return gr;
|
||||||
};
|
};
|
||||||
const getTitle = (scorePlayerData) => {
|
const execute = () => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
try {
|
const captcha = yield init();
|
||||||
return scorePlayerData.json.metadata.title;
|
return captcha.execute(SITE_KEY, { action: 'downloadmscz' });
|
||||||
}
|
});
|
||||||
catch (_) {
|
|
||||||
return "";
|
let msczBufferP;
|
||||||
}
|
const fetchMscz = () => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
};
|
|
||||||
const getScoreFileName = (scorePlayerData) => {
|
|
||||||
return getTitle(scorePlayerData).replace(/[\s<>:{}"/\\|?*~.\0\cA-\cZ]+/g, "_");
|
|
||||||
};
|
|
||||||
const fetchMscz = (url) => __awaiter(void 0, void 0, void 0, function* () {
|
|
||||||
if (!msczBufferP) {
|
if (!msczBufferP) {
|
||||||
|
const url = scoreinfo.msczUrl;
|
||||||
msczBufferP = (() => __awaiter(void 0, void 0, void 0, function* () {
|
msczBufferP = (() => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
const token = yield execute();
|
const token = yield execute();
|
||||||
const r = yield fetch(url + token);
|
const r = yield fetch(url + token);
|
||||||
|
@ -26402,159 +26437,191 @@ Please pipe the document into a Node stream.\
|
||||||
}
|
}
|
||||||
return msczBufferP;
|
return msczBufferP;
|
||||||
});
|
});
|
||||||
|
const downloadMscz = () => __awaiter(void 0, void 0, void 0, function* () {
|
||||||
|
const data = new Blob([yield fetchMscz()]);
|
||||||
|
const filename = scoreinfo.fileName;
|
||||||
|
saveAs(data, `${filename}.mscz`);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select the original Download Button
|
||||||
|
*/
|
||||||
|
const getDownloadBtn = () => {
|
||||||
|
const btnsDiv = document.querySelector('.score-right .buttons-wrapper') || document.querySelectorAll('aside section > div')[4];
|
||||||
|
const btn = btnsDiv.querySelector('button, .button');
|
||||||
|
btn.onclick = null;
|
||||||
|
// fix the icon of the download btn
|
||||||
|
// if the `btn` seleted was a `Print` btn, replace the `print` icon with the `download` icon
|
||||||
|
const svgPath = btn.querySelector('svg > path');
|
||||||
|
if (svgPath) {
|
||||||
|
svgPath.setAttribute('d', 'M9.6 2.4h4.8V12h2.784l-5.18 5.18L6.823 12H9.6V2.4zM19.2 19.2H4.8v2.4h14.4v-2.4z');
|
||||||
|
}
|
||||||
|
if (btn.nodeName.toLowerCase() === 'button') {
|
||||||
|
btn.setAttribute('style', 'width: 205px !important');
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
btn.dataset.target = '';
|
||||||
|
}
|
||||||
|
return btn;
|
||||||
|
};
|
||||||
|
class BtnList {
|
||||||
|
constructor(templateBtn) {
|
||||||
|
this.templateBtn = templateBtn;
|
||||||
|
this.list = [];
|
||||||
|
}
|
||||||
|
add(options) {
|
||||||
|
const btn = this.templateBtn.cloneNode(true);
|
||||||
|
const textNode = [...btn.childNodes].find((x) => {
|
||||||
|
const txt = x.textContent;
|
||||||
|
return txt.includes('Download') || txt.includes('Print');
|
||||||
|
});
|
||||||
|
const setText = (str) => {
|
||||||
|
textNode.textContent = str;
|
||||||
|
};
|
||||||
|
setText(options.name);
|
||||||
|
btn.onclick = () => {
|
||||||
|
options.action(options.name, btn, setText);
|
||||||
|
};
|
||||||
|
this.list.push(btn);
|
||||||
|
return btn;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* replace the template button with the list of new buttons
|
||||||
|
*/
|
||||||
|
commit() {
|
||||||
|
this.templateBtn.replaceWith(...this.list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-namespace
|
||||||
|
var BtnAction;
|
||||||
|
(function (BtnAction) {
|
||||||
|
BtnAction.PROCESSING_TEXT = 'Processing…';
|
||||||
|
BtnAction.ERROR_TEXT = '❌Download Failed!';
|
||||||
|
BtnAction.openUrl = (url) => {
|
||||||
|
return () => window.open(url);
|
||||||
|
};
|
||||||
|
BtnAction.process = (fn) => {
|
||||||
|
return (name, btn, setText) => __awaiter(this, void 0, void 0, function* () {
|
||||||
|
const _onclick = btn.onclick;
|
||||||
|
btn.onclick = null;
|
||||||
|
setText(BtnAction.PROCESSING_TEXT);
|
||||||
|
try {
|
||||||
|
yield fn();
|
||||||
|
setText(name);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
setText(BtnAction.ERROR_TEXT);
|
||||||
|
console.error(err);
|
||||||
|
}
|
||||||
|
btn.onclick = _onclick;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
})(BtnAction || (BtnAction = {}));
|
||||||
|
|
||||||
|
const WEBMSCORE_URL = 'https://cdn.jsdelivr.net/npm/webmscore@0.5/webmscore.js';
|
||||||
const main = () => {
|
const main = () => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
if (!window.UGAPP || !window.UGAPP.store || !window.UGAPP.store.jmuse_settings) {
|
if (!window.UGAPP || !window.UGAPP.store || !window.UGAPP.store.jmuse_settings) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// init recaptcha
|
// init recaptcha
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
init();
|
init();
|
||||||
// @ts-ignore
|
const btnList = new BtnList(getDownloadBtn());
|
||||||
const scorePlayer = window.UGAPP.store.jmuse_settings.score_player;
|
btnList.add({
|
||||||
const { id } = scorePlayer.json;
|
name: 'Download MSCZ',
|
||||||
const baseURL = scorePlayer.urls.image_path;
|
action: BtnAction.process(downloadMscz),
|
||||||
const filename = getScoreFileName(scorePlayer);
|
|
||||||
// https://github.com/Xmader/cloudflare-worker-musescore-mscz
|
|
||||||
const msczURL = `https://musescore.now.sh/api/mscz?id=${id}&token=`;
|
|
||||||
const mxlURL = baseURL + "score.mxl";
|
|
||||||
const { midi: midiURL, mp3: mp3URL } = scorePlayer.urls;
|
|
||||||
const btnsDiv = document.querySelector(".score-right .buttons-wrapper") || document.querySelectorAll("aside section > div")[4];
|
|
||||||
const downloadBtn = btnsDiv.querySelector("button, .button");
|
|
||||||
downloadBtn.onclick = null;
|
|
||||||
// fix the icon of the download btn
|
|
||||||
// if the `downloadBtn` seleted was a `Print` btn, replace the `print` icon with the `download` icon
|
|
||||||
const svgPath = downloadBtn.querySelector("svg > path");
|
|
||||||
if (svgPath) {
|
|
||||||
svgPath.setAttribute("d", "M9.6 2.4h4.8V12h2.784l-5.18 5.18L6.823 12H9.6V2.4zM19.2 19.2H4.8v2.4h14.4v-2.4z");
|
|
||||||
}
|
|
||||||
const imgType = getImgType() || "svg";
|
|
||||||
const sheetImgURLs = Array.from({ length: getPagesNumber(scorePlayer) }).fill(null).map((_, i) => {
|
|
||||||
return baseURL + `score_${i}.${imgType}`;
|
|
||||||
});
|
});
|
||||||
const downloadURLs = {
|
btnList.add({
|
||||||
"MSCZ": null,
|
name: 'Download PDF',
|
||||||
"PDF": null,
|
action: BtnAction.process(downloadPDF),
|
||||||
"MusicXML": mxlURL,
|
});
|
||||||
"MIDI": midiURL,
|
btnList.add({
|
||||||
"MP3": mp3URL,
|
name: 'Download MusicXML',
|
||||||
"Parts": null,
|
action: BtnAction.openUrl(scoreinfo.mxlUrl),
|
||||||
};
|
});
|
||||||
const createBtn = (name) => {
|
btnList.add({
|
||||||
const btn = downloadBtn.cloneNode(true);
|
name: 'Download MIDI',
|
||||||
if (btn.nodeName.toLowerCase() == "button") {
|
action: BtnAction.openUrl(scoreinfo.midiUrl),
|
||||||
btn.setAttribute("style", "width: 205px !important");
|
});
|
||||||
}
|
btnList.add({
|
||||||
else {
|
name: 'Download MP3',
|
||||||
btn.dataset.target = "";
|
action: BtnAction.openUrl(scoreinfo.mp3Url),
|
||||||
}
|
});
|
||||||
const textNode = [...btn.childNodes].find((x) => {
|
btnList.add({
|
||||||
return x.textContent.includes("Download") || x.textContent.includes("Print");
|
name: 'Individual Parts',
|
||||||
});
|
action(btnName, btn, setText) {
|
||||||
textNode.textContent = `Download ${name}`;
|
return __awaiter(this, void 0, void 0, function* () {
|
||||||
return {
|
const _onclick = btn.onclick;
|
||||||
btn,
|
|
||||||
textNode,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
const newDownloadBtns = Object.keys(downloadURLs).map((name) => {
|
|
||||||
const url = downloadURLs[name];
|
|
||||||
const { btn, textNode } = createBtn(name);
|
|
||||||
if (name == "PDF") {
|
|
||||||
btn.onclick = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
||||||
const filename = getScoreFileName(scorePlayer);
|
|
||||||
textNode.textContent = PROCESSING_TEXT;
|
|
||||||
try {
|
|
||||||
yield generatePDF(sheetImgURLs, imgType, filename);
|
|
||||||
textNode.textContent = "Download PDF";
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
textNode.textContent = FAILED_TEXT;
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if (name == "MSCZ") {
|
|
||||||
btn.onclick = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
||||||
textNode.textContent = PROCESSING_TEXT;
|
|
||||||
try {
|
|
||||||
const data = new Blob([yield fetchMscz(msczURL)]);
|
|
||||||
textNode.textContent = "Download MSCZ";
|
|
||||||
saveAs(data, `${filename}.mscz`);
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
textNode.textContent = FAILED_TEXT;
|
|
||||||
console.error(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if (name == "Parts") { // download individual parts
|
|
||||||
btn.title = "Download individual parts (BETA)";
|
|
||||||
const cb = btn.onclick = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
||||||
btn.onclick = null;
|
btn.onclick = null;
|
||||||
textNode.textContent = PROCESSING_TEXT;
|
setText(BtnAction.PROCESSING_TEXT);
|
||||||
const w = window.open("");
|
const w = window.open('');
|
||||||
const txt = document.createTextNode(PROCESSING_TEXT);
|
const txt = document.createTextNode(BtnAction.PROCESSING_TEXT);
|
||||||
w.document.body.append(txt);
|
w.document.body.append(txt);
|
||||||
// set page hooks
|
// set page hooks
|
||||||
|
// eslint-disable-next-line prefer-const
|
||||||
|
let score;
|
||||||
const destroy = () => {
|
const destroy = () => {
|
||||||
score.destroy();
|
score && score.destroy();
|
||||||
w.close();
|
w.close();
|
||||||
};
|
};
|
||||||
window.addEventListener("unload", destroy);
|
window.addEventListener('unload', destroy);
|
||||||
w.addEventListener("beforeunload", () => {
|
w.addEventListener('beforeunload', () => {
|
||||||
score.destroy();
|
score && score.destroy();
|
||||||
window.removeEventListener("unload", destroy);
|
window.removeEventListener('unload', destroy);
|
||||||
textNode.textContent = "Download Parts";
|
setText(btnName);
|
||||||
btn.onclick = cb;
|
btn.onclick = _onclick;
|
||||||
});
|
});
|
||||||
// load webmscore (https://github.com/LibreScore/webmscore)
|
// load webmscore (https://github.com/LibreScore/webmscore)
|
||||||
const script = w.document.createElement("script");
|
const script = w.document.createElement('script');
|
||||||
script.src = WEBMSCORE_URL;
|
script.src = WEBMSCORE_URL;
|
||||||
w.document.body.append(script);
|
w.document.body.append(script);
|
||||||
yield new Promise(resolve => { script.onload = resolve; });
|
yield new Promise(resolve => { script.onload = resolve; });
|
||||||
// parse mscz data
|
// parse mscz data
|
||||||
const data = new Uint8Array(new Uint8Array(yield fetchMscz(msczURL)) // copy its ArrayBuffer
|
const data = new Uint8Array(new Uint8Array(yield fetchMscz()) // copy its ArrayBuffer
|
||||||
);
|
);
|
||||||
const score = yield w["WebMscore"].load("mscz", data);
|
score = yield w['WebMscore'].load('mscz', data);
|
||||||
yield score.generateExcerpts();
|
yield score.generateExcerpts();
|
||||||
const metadata = yield score.metadata();
|
const metadata = yield score.metadata();
|
||||||
console.log("score metadata loaded by webmscore", metadata);
|
console.log('score metadata loaded by webmscore', metadata);
|
||||||
// render the part selection page
|
// render the part selection page
|
||||||
txt.remove();
|
txt.remove();
|
||||||
const fieldset = w.document.createElement("fieldset");
|
const fieldset = w.document.createElement('fieldset');
|
||||||
|
metadata.excerpts.unshift({ id: -1, title: 'Full score' });
|
||||||
for (const excerpt of metadata.excerpts) {
|
for (const excerpt of metadata.excerpts) {
|
||||||
const e = w.document.createElement("input");
|
const id = excerpt.id;
|
||||||
e.name = "score-part";
|
const partName = excerpt.title;
|
||||||
e.type = "radio";
|
const e = w.document.createElement('input');
|
||||||
e.value = excerpt.id;
|
e.name = 'score-part';
|
||||||
const label = w.document.createElement("label");
|
e.type = 'radio';
|
||||||
label.innerText = excerpt.title;
|
e.alt = partName;
|
||||||
const br = w.document.createElement("br");
|
e.value = id;
|
||||||
|
e.checked = id === 0; // initially select the first part
|
||||||
|
const label = w.document.createElement('label');
|
||||||
|
label.innerText = partName;
|
||||||
|
const br = w.document.createElement('br');
|
||||||
fieldset.append(e, label, br);
|
fieldset.append(e, label, br);
|
||||||
}
|
}
|
||||||
const submitBtn = w.document.createElement("input");
|
const submitBtn = w.document.createElement('input');
|
||||||
submitBtn.type = "submit";
|
submitBtn.type = 'submit';
|
||||||
submitBtn.value = "Download PDF";
|
submitBtn.value = 'Download PDF';
|
||||||
fieldset.append(submitBtn);
|
fieldset.append(submitBtn);
|
||||||
w.document.body.append(fieldset);
|
w.document.body.append(fieldset);
|
||||||
submitBtn.onclick = () => __awaiter(void 0, void 0, void 0, function* () {
|
submitBtn.onclick = () => __awaiter(this, void 0, void 0, function* () {
|
||||||
const checked = w.document.querySelector("input:checked");
|
const checked = fieldset.querySelector('input:checked');
|
||||||
const id = checked.value;
|
const id = checked.value;
|
||||||
|
const partName = checked.alt;
|
||||||
yield score.setExcerptId(id);
|
yield score.setExcerptId(id);
|
||||||
|
const filename = scoreinfo.fileName;
|
||||||
const data = new Blob([yield score.savePdf()]);
|
const data = new Blob([yield score.savePdf()]);
|
||||||
saveAs(data, `${filename}-part-${id}.pdf`);
|
saveAs(data, `${filename} - ${partName}.pdf`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
},
|
||||||
else {
|
}).title = 'Download individual parts (BETA)';
|
||||||
btn.onclick = () => {
|
btnList.commit();
|
||||||
window.open(url);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return btn;
|
|
||||||
});
|
|
||||||
downloadBtn.replaceWith(...newDownloadBtns);
|
|
||||||
};
|
};
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
waitForDocumentLoaded().then(main);
|
waitForDocumentLoaded().then(main);
|
||||||
|
|
||||||
}.toString() + ')()')
|
}.toString() + ')()')
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "musescore-downloader",
|
"name": "musescore-downloader",
|
||||||
"version": "0.7.0",
|
"version": "0.7.1",
|
||||||
"description": "download sheet music from musescore.com for free, no login or Musescore Pro required | 免登录、免 Musescore Pro,免费下载 musescore.com 上的曲谱",
|
"description": "download sheet music from musescore.com for free, no login or Musescore Pro required | 免登录、免 Musescore Pro,免费下载 musescore.com 上的曲谱",
|
||||||
"main": "dist/main.js",
|
"main": "dist/main.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue