feat: view score in LibreScore
This commit is contained in:
parent
eb0f2b4b1d
commit
2eca89e672
15
src/btn.ts
15
src/btn.ts
|
@ -9,6 +9,11 @@ import btnListCss from './btn.css'
|
||||||
|
|
||||||
type BtnElement = HTMLButtonElement
|
type BtnElement = HTMLButtonElement
|
||||||
|
|
||||||
|
export enum ICON {
|
||||||
|
DOWNLOAD = 'M9.6 2.4h4.8V12h2.784l-5.18 5.18L6.823 12H9.6V2.4zM19.2 19.2H4.8v2.4h14.4v-2.4z',
|
||||||
|
LIBRESCORE = 'm5.4837 4.4735v10.405c-1.25-0.89936-3.0285-0.40896-4.1658 0.45816-1.0052 0.76659-1.7881 2.3316-0.98365 3.4943 1 1.1346 2.7702 0.70402 3.8817-0.02809 1.0896-0.66323 1.9667-1.8569 1.8125-3.1814v-5.4822h8.3278v9.3865h9.6438v-2.6282h-6.4567v-12.417c-4.0064-0.015181-8.0424-0.0027-12.06-0.00676zm0.54477 2.2697h8.3278v1.1258h-8.3278v-1.1258z',
|
||||||
|
}
|
||||||
|
|
||||||
const getBtnContainer = (): HTMLDivElement => {
|
const getBtnContainer = (): HTMLDivElement => {
|
||||||
const els = [...document.querySelectorAll('*')].reverse()
|
const els = [...document.querySelectorAll('*')].reverse()
|
||||||
const el = els.find(b => {
|
const el = els.find(b => {
|
||||||
|
@ -20,7 +25,7 @@ const getBtnContainer = (): HTMLDivElement => {
|
||||||
return btnParent
|
return btnParent
|
||||||
}
|
}
|
||||||
|
|
||||||
const buildDownloadBtn = () => {
|
const buildDownloadBtn = (icon: ICON) => {
|
||||||
const btn = document.createElement('button')
|
const btn = document.createElement('button')
|
||||||
btn.type = 'button'
|
btn.type = 'button'
|
||||||
|
|
||||||
|
@ -28,7 +33,7 @@ const buildDownloadBtn = () => {
|
||||||
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
|
const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')
|
||||||
svg.setAttribute('viewBox', '0 0 24 24')
|
svg.setAttribute('viewBox', '0 0 24 24')
|
||||||
const svgPath = document.createElementNS('http://www.w3.org/2000/svg', 'path')
|
const svgPath = document.createElementNS('http://www.w3.org/2000/svg', 'path')
|
||||||
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')
|
svgPath.setAttribute('d', icon)
|
||||||
svgPath.setAttribute('fill', '#fff')
|
svgPath.setAttribute('fill', '#fff')
|
||||||
svg.append(svgPath)
|
svg.append(svgPath)
|
||||||
|
|
||||||
|
@ -49,6 +54,7 @@ interface BtnOptions {
|
||||||
readonly action: BtnAction;
|
readonly action: BtnAction;
|
||||||
readonly disabled?: boolean;
|
readonly disabled?: boolean;
|
||||||
readonly tooltip?: string;
|
readonly tooltip?: string;
|
||||||
|
readonly icon?: ICON;
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum BtnListMode {
|
export enum BtnListMode {
|
||||||
|
@ -62,7 +68,7 @@ export class BtnList {
|
||||||
constructor (private getBtnParent: () => HTMLDivElement = getBtnContainer) { }
|
constructor (private getBtnParent: () => HTMLDivElement = getBtnContainer) { }
|
||||||
|
|
||||||
add (options: BtnOptions): BtnElement {
|
add (options: BtnOptions): BtnElement {
|
||||||
const btnTpl = buildDownloadBtn()
|
const btnTpl = buildDownloadBtn(options.icon ?? ICON.DOWNLOAD)
|
||||||
const setText = (btn: BtnElement) => {
|
const setText = (btn: BtnElement) => {
|
||||||
const textNode = btn.querySelector('span')
|
const textNode = btn.querySelector('span')
|
||||||
return (str: string): void => {
|
return (str: string): void => {
|
||||||
|
@ -186,10 +192,13 @@ export namespace BtnAction {
|
||||||
const _url = await normalizeUrlInput(url)
|
const _url = await normalizeUrlInput(url)
|
||||||
const a = document.createElement('a')
|
const a = document.createElement('a')
|
||||||
a.href = _url
|
a.href = _url
|
||||||
|
a.target = '_blank'
|
||||||
a.dispatchEvent(new MouseEvent('click'))
|
a.dispatchEvent(new MouseEvent('click'))
|
||||||
}, fallback, timeout)
|
}, fallback, timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const openUrl = download
|
||||||
|
|
||||||
export const mscoreWindow = (scoreinfo: ScoreInfo, fn: (w: Window, score: WebMscore, processingTextEl: ChildNode) => any): BtnAction => {
|
export const mscoreWindow = (scoreinfo: ScoreInfo, fn: (w: Window, score: WebMscore, processingTextEl: ChildNode) => any): BtnAction => {
|
||||||
return async (btnName, btn, setText) => {
|
return async (btnName, btn, setText) => {
|
||||||
const _onclick = btn.onclick
|
const _onclick = btn.onclick
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { assertRes, getFetch } from './utils'
|
||||||
|
import { getMainCid } from './mscz'
|
||||||
|
import { ScoreInfo } from './scoreinfo'
|
||||||
|
|
||||||
|
const _getLink = (scorepack: string) => {
|
||||||
|
return `https://librescore.org/score/${scorepack}`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const getLibreScoreLink = async (scoreinfo: ScoreInfo, _fetch = getFetch()): Promise<string> => {
|
||||||
|
const mainCid = await getMainCid(scoreinfo, _fetch)
|
||||||
|
const ref = scoreinfo.getScorepackRef(mainCid)
|
||||||
|
const url = `https://ipfs.infura.io:5001/api/v0/dag/get?arg=${ref}`
|
||||||
|
|
||||||
|
const r0 = await _fetch(url)
|
||||||
|
if (r0.status !== 500) {
|
||||||
|
assertRes(r0)
|
||||||
|
}
|
||||||
|
const res: { Message: string } | string = await r0.json()
|
||||||
|
if (typeof res !== 'string') {
|
||||||
|
// read further error msg
|
||||||
|
throw new Error(res.Message)
|
||||||
|
}
|
||||||
|
|
||||||
|
return _getLink(res)
|
||||||
|
}
|
10
src/main.ts
10
src/main.ts
|
@ -6,7 +6,8 @@ import { downloadPDF } from './pdf'
|
||||||
import { downloadMscz } from './mscz'
|
import { downloadMscz } from './mscz'
|
||||||
import { getFileUrl } from './file'
|
import { getFileUrl } from './file'
|
||||||
import { INDV_DOWNLOADS } from './mscore'
|
import { INDV_DOWNLOADS } from './mscore'
|
||||||
import { BtnList, BtnAction, BtnListMode } from './btn'
|
import { getLibreScoreLink } from './librescore-link'
|
||||||
|
import { BtnList, BtnAction, BtnListMode, ICON } from './btn'
|
||||||
import { ScoreInfoInPage, SheetInfoInPage, getActualId } from './scoreinfo'
|
import { ScoreInfoInPage, SheetInfoInPage, getActualId } from './scoreinfo'
|
||||||
import i18n from './i18n'
|
import i18n from './i18n'
|
||||||
|
|
||||||
|
@ -131,6 +132,13 @@ const main = (): void => {
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
btnList.add({
|
||||||
|
name: 'View in LibreScore',
|
||||||
|
action: BtnAction.openUrl(() => getLibreScoreLink(scoreinfo)),
|
||||||
|
tooltip: 'BETA',
|
||||||
|
icon: ICON.LIBRESCORE,
|
||||||
|
})
|
||||||
|
|
||||||
btnList.commit(BtnListMode.InPage)
|
btnList.commit(BtnListMode.InPage)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { getMainCid } from './mscz'
|
||||||
|
|
||||||
export abstract class ScoreInfo {
|
export abstract class ScoreInfo {
|
||||||
private readonly RADIX = 20;
|
private readonly RADIX = 20;
|
||||||
|
private readonly INDEX_RADIX = 40;
|
||||||
|
|
||||||
abstract id: number;
|
abstract id: number;
|
||||||
abstract title: string;
|
abstract title: string;
|
||||||
|
@ -25,6 +26,10 @@ export abstract class ScoreInfo {
|
||||||
public getMsczCidUrl (mainCid: string): string {
|
public getMsczCidUrl (mainCid: string): string {
|
||||||
return `https://ipfs.infura.io:5001/api/v0/block/stat?arg=${this.getMsczIpfsRef(mainCid)}`
|
return `https://ipfs.infura.io:5001/api/v0/block/stat?arg=${this.getMsczIpfsRef(mainCid)}`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getScorepackRef (mainCid: string): string {
|
||||||
|
return `/ipfs/${mainCid}/index/${(+this.id) % this.INDEX_RADIX}/${this.id}/scorepack`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ScoreInfoObj extends ScoreInfo {
|
export class ScoreInfoObj extends ScoreInfo {
|
||||||
|
|
Loading…
Reference in New Issue