diff --git a/package.json b/package.json index e252eea..cbe7975 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,8 @@ "homepage": "https://github.com/Xmader/musescore-downloader#readme", "dependencies": { "pdfkit": "git+https://github.com/Xmader/pdfkit.git", - "svg-to-pdfkit": "^0.1.8" + "svg-to-pdfkit": "^0.1.8", + "webmscore": "^0.5.0" }, "devDependencies": { "@rollup/plugin-json": "^4.0.0", diff --git a/src/btn.ts b/src/btn.ts index 89ac15d..accda36 100644 --- a/src/btn.ts +++ b/src/btn.ts @@ -1,4 +1,7 @@ +import { text } from 'pdfkit/js/mixins/text' +import { loadMscore, WebMscore } from './mscore' + type BtnElement = HTMLElement /** @@ -78,6 +81,37 @@ export namespace BtnAction { return (): any => window.open(url) } + export const mscoreWindow = (fn: (w: Window, score: WebMscore, processingTextEl: ChildNode) => any): BtnAction => { + return async (btnName, btn, setText) => { + const _onclick = btn.onclick + btn.onclick = null + setText(BtnAction.PROCESSING_TEXT) + + const w = window.open('') as Window + const txt = document.createTextNode(BtnAction.PROCESSING_TEXT) + w.document.body.append(txt) + + // set page hooks + // eslint-disable-next-line prefer-const + let score: WebMscore + const destroy = (): void => { + score && score.destroy() + w.close() + } + window.addEventListener('unload', destroy) + w.addEventListener('beforeunload', () => { + score && score.destroy() + window.removeEventListener('unload', destroy) + setText(btnName) + btn.onclick = _onclick + }) + + score = await loadMscore(w) + + fn(w, score, txt) + } + } + export const process = (fn: () => any): BtnAction => { return async (name, btn, setText): Promise => { const _onclick = btn.onclick diff --git a/src/main.ts b/src/main.ts index ecd3ec3..326be46 100644 --- a/src/main.ts +++ b/src/main.ts @@ -2,13 +2,11 @@ import './meta' import { waitForDocumentLoaded, saveAs } from './utils' import { downloadPDF } from './pdf' -import { fetchMscz, downloadMscz } from './mscz' +import { downloadMscz } from './mscz' import { getDownloadBtn, BtnList, BtnAction } from './btn' import * as recaptcha from './recaptcha' import scoreinfo from './scoreinfo' -const WEBMSCORE_URL = 'https://cdn.jsdelivr.net/npm/webmscore@0.5/webmscore.js' - const main = (): void => { // @ts-ignore if (!window.UGAPP || !window.UGAPP.store || !window.UGAPP.store.jmuse_settings) { return } @@ -31,7 +29,12 @@ const main = (): void => { btnList.add({ name: 'Download MusicXML', - action: BtnAction.openUrl(scoreinfo.mxlUrl), + action: BtnAction.mscoreWindow(async (w, score) => { + const mxl = await score.saveMxl() + const data = new Blob([mxl]) + saveAs(data, `${scoreinfo.fileName}.mxl`) + w.close() + }), }) btnList.add({ @@ -46,49 +49,14 @@ const main = (): void => { btnList.add({ name: 'Individual Parts', - async action (btnName, btn, setText) { - const _onclick = btn.onclick - btn.onclick = null - setText(BtnAction.PROCESSING_TEXT) - - const w = window.open('') as Window - const txt = document.createTextNode(BtnAction.PROCESSING_TEXT) - w.document.body.append(txt) - - // set page hooks - // eslint-disable-next-line prefer-const - let score: any - const destroy = (): void => { - score && score.destroy() - w.close() - } - window.addEventListener('unload', destroy) - w.addEventListener('beforeunload', () => { - score && score.destroy() - window.removeEventListener('unload', destroy) - setText(btnName) - btn.onclick = _onclick - }) - - // load webmscore (https://github.com/LibreScore/webmscore) - const script = w.document.createElement('script') - script.src = WEBMSCORE_URL - w.document.body.append(script) - await new Promise(resolve => { script.onload = resolve }) - - // parse mscz data - const data = new Uint8Array( - new Uint8Array(await fetchMscz()), // copy its ArrayBuffer - ) - score = await w['WebMscore'].load('mscz', data) - await score.generateExcerpts() + action: BtnAction.mscoreWindow(async (w, score, txt) => { const metadata = await score.metadata() console.log('score metadata loaded by webmscore', metadata) // render the part selection page txt.remove() const fieldset = w.document.createElement('fieldset') - metadata.excerpts.unshift({ id: -1, title: 'Full score' }) + metadata.excerpts.unshift({ id: -1, title: 'Full score', parts: [] }) for (const excerpt of metadata.excerpts) { const id = excerpt.id const partName = excerpt.title @@ -97,7 +65,7 @@ const main = (): void => { e.name = 'score-part' e.type = 'radio' e.alt = partName - e.value = id + e.value = id.toString() e.checked = id === 0 // initially select the first part const label = w.document.createElement('label') @@ -117,13 +85,13 @@ const main = (): void => { const id = checked.value const partName = checked.alt - await score.setExcerptId(id) + await score.setExcerptId(+id) const filename = scoreinfo.fileName const data = new Blob([await score.savePdf()]) saveAs(data, `${filename} - ${partName}.pdf`) } - }, + }), }).title = 'Download individual parts (BETA)' btnList.commit() diff --git a/src/mscore.ts b/src/mscore.ts new file mode 100644 index 0000000..59f40a2 --- /dev/null +++ b/src/mscore.ts @@ -0,0 +1,30 @@ + +import { fetchMscz } from './mscz' + +const WEBMSCORE_URL = 'https://cdn.jsdelivr.net/npm/webmscore@0.10/webmscore.js' + +export type WebMscore = import('webmscore').default + +const initMscore = async (w: Window) => { + if (!w['WebMscore']) { + // init webmscore (https://github.com/LibreScore/webmscore) + const script = w.document.createElement('script') + script.src = WEBMSCORE_URL + w.document.body.append(script) + await new Promise(resolve => { script.onload = resolve }) + } +} + +export const loadMscore = async (w: Window): Promise => { + await initMscore(w) + + const WebMscore: typeof import('webmscore').default = w['WebMscore'] + // parse mscz data + const data = new Uint8Array( + new Uint8Array(await fetchMscz()), // copy its ArrayBuffer + ) + const score = await WebMscore.load('mscz', data) + await score.generateExcerpts() + + return score +}