parent
efa676b921
commit
9a0f51fa15
4 changed files with 78 additions and 45 deletions
|
@ -15,7 +15,8 @@
|
||||||
"homepage": "https://github.com/Xmader/musescore-downloader#readme",
|
"homepage": "https://github.com/Xmader/musescore-downloader#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"pdfkit": "git+https://github.com/Xmader/pdfkit.git",
|
"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": {
|
"devDependencies": {
|
||||||
"@rollup/plugin-json": "^4.0.0",
|
"@rollup/plugin-json": "^4.0.0",
|
||||||
|
|
34
src/btn.ts
34
src/btn.ts
|
@ -1,4 +1,7 @@
|
||||||
|
|
||||||
|
import { text } from 'pdfkit/js/mixins/text'
|
||||||
|
import { loadMscore, WebMscore } from './mscore'
|
||||||
|
|
||||||
type BtnElement = HTMLElement
|
type BtnElement = HTMLElement
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,6 +81,37 @@ export namespace BtnAction {
|
||||||
return (): any => window.open(url)
|
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 => {
|
export const process = (fn: () => any): BtnAction => {
|
||||||
return async (name, btn, setText): Promise<void> => {
|
return async (name, btn, setText): Promise<void> => {
|
||||||
const _onclick = btn.onclick
|
const _onclick = btn.onclick
|
||||||
|
|
56
src/main.ts
56
src/main.ts
|
@ -2,13 +2,11 @@ import './meta'
|
||||||
|
|
||||||
import { waitForDocumentLoaded, saveAs } from './utils'
|
import { waitForDocumentLoaded, saveAs } from './utils'
|
||||||
import { downloadPDF } from './pdf'
|
import { downloadPDF } from './pdf'
|
||||||
import { fetchMscz, downloadMscz } from './mscz'
|
import { downloadMscz } from './mscz'
|
||||||
import { getDownloadBtn, BtnList, BtnAction } from './btn'
|
import { getDownloadBtn, BtnList, BtnAction } from './btn'
|
||||||
import * as recaptcha from './recaptcha'
|
import * as recaptcha from './recaptcha'
|
||||||
import scoreinfo from './scoreinfo'
|
import scoreinfo from './scoreinfo'
|
||||||
|
|
||||||
const WEBMSCORE_URL = 'https://cdn.jsdelivr.net/npm/webmscore@0.5/webmscore.js'
|
|
||||||
|
|
||||||
const main = (): void => {
|
const main = (): void => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
if (!window.UGAPP || !window.UGAPP.store || !window.UGAPP.store.jmuse_settings) { return }
|
if (!window.UGAPP || !window.UGAPP.store || !window.UGAPP.store.jmuse_settings) { return }
|
||||||
|
@ -31,7 +29,12 @@ const main = (): void => {
|
||||||
|
|
||||||
btnList.add({
|
btnList.add({
|
||||||
name: 'Download MusicXML',
|
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({
|
btnList.add({
|
||||||
|
@ -46,49 +49,14 @@ const main = (): void => {
|
||||||
|
|
||||||
btnList.add({
|
btnList.add({
|
||||||
name: 'Individual Parts',
|
name: 'Individual Parts',
|
||||||
async action (btnName, btn, setText) {
|
action: BtnAction.mscoreWindow(async (w, score, txt) => {
|
||||||
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()
|
|
||||||
const metadata = await score.metadata()
|
const metadata = await 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' })
|
metadata.excerpts.unshift({ id: -1, title: 'Full score', parts: [] })
|
||||||
for (const excerpt of metadata.excerpts) {
|
for (const excerpt of metadata.excerpts) {
|
||||||
const id = excerpt.id
|
const id = excerpt.id
|
||||||
const partName = excerpt.title
|
const partName = excerpt.title
|
||||||
|
@ -97,7 +65,7 @@ const main = (): void => {
|
||||||
e.name = 'score-part'
|
e.name = 'score-part'
|
||||||
e.type = 'radio'
|
e.type = 'radio'
|
||||||
e.alt = partName
|
e.alt = partName
|
||||||
e.value = id
|
e.value = id.toString()
|
||||||
e.checked = id === 0 // initially select the first part
|
e.checked = id === 0 // initially select the first part
|
||||||
|
|
||||||
const label = w.document.createElement('label')
|
const label = w.document.createElement('label')
|
||||||
|
@ -117,13 +85,13 @@ const main = (): void => {
|
||||||
const id = checked.value
|
const id = checked.value
|
||||||
const partName = checked.alt
|
const partName = checked.alt
|
||||||
|
|
||||||
await score.setExcerptId(id)
|
await score.setExcerptId(+id)
|
||||||
|
|
||||||
const filename = scoreinfo.fileName
|
const filename = scoreinfo.fileName
|
||||||
const data = new Blob([await score.savePdf()])
|
const data = new Blob([await score.savePdf()])
|
||||||
saveAs(data, `${filename} - ${partName}.pdf`)
|
saveAs(data, `${filename} - ${partName}.pdf`)
|
||||||
}
|
}
|
||||||
},
|
}),
|
||||||
}).title = 'Download individual parts (BETA)'
|
}).title = 'Download individual parts (BETA)'
|
||||||
|
|
||||||
btnList.commit()
|
btnList.commit()
|
||||||
|
|
30
src/mscore.ts
Normal file
30
src/mscore.ts
Normal file
|
@ -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<WebMscore> => {
|
||||||
|
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
|
||||||
|
}
|
Loading…
Reference in a new issue