feat: support s.musescore.com urls

This commit is contained in:
Xmader 2020-11-29 17:47:39 -05:00
parent 7485d884bf
commit 7fc1a5fb6a
No known key found for this signature in database
GPG Key ID: A20B97FB9EB730E4
5 changed files with 49 additions and 8 deletions

View File

@ -25,7 +25,7 @@
"content_scripts": [
{
"matches": [
"*://musescore.com/*/*"
"*://*.musescore.com/*/*"
],
"js": [
"src/web-ext.js"

View File

@ -6,7 +6,7 @@ import fs from 'fs'
import path from 'path'
import { fetchMscz, setMscz, MSCZ_URL_SYM } from './mscz'
import { loadMscore, INDV_DOWNLOADS, WebMscore } from './mscore'
import { ScoreInfo, ScoreInfoHtml, ScoreInfoObj } from './scoreinfo'
import { ScoreInfo, ScoreInfoHtml, ScoreInfoObj, getActualId } from './scoreinfo'
import { escapeFilename } from './utils'
import i18n from './i18n'
@ -14,7 +14,8 @@ const inquirer: typeof import('inquirer') = require('inquirer')
const ora: typeof import('ora') = require('ora')
const chalk: typeof import('chalk') = require('chalk')
const SCORE_URL_PREFIX = 'https://musescore.com/'
const SCORE_URL_PREFIX = 'https://(s.)?musescore.com/'
const SCORE_URL_REG = /https:\/\/(s\.)?musescore\.com\//
const EXT = '.mscz'
interface Params {
@ -36,7 +37,7 @@ void (async () => {
validate (input: string) {
return input &&
(
input.startsWith(SCORE_URL_PREFIX) ||
!!input.match(SCORE_URL_REG) ||
(input.endsWith(EXT) && fs.statSync(input).isFile())
)
},
@ -47,6 +48,7 @@ void (async () => {
if (!isLocalFile) {
// request scoreinfo
scoreinfo = await ScoreInfoHtml.request(fileInit)
await getActualId(scoreinfo as any)
// confirmation
const { confirmed } = await inquirer.prompt<Params>({

View File

@ -7,7 +7,7 @@ import { downloadMscz } from './mscz'
import { getFileUrl } from './file'
import { INDV_DOWNLOADS } from './mscore'
import { BtnList, BtnAction, BtnListMode } from './btn'
import { ScoreInfoInPage, SheetInfoInPage } from './scoreinfo'
import { ScoreInfoInPage, SheetInfoInPage, getActualId } from './scoreinfo'
import i18n from './i18n'
const { saveAs } = FileSaver
@ -15,7 +15,10 @@ const { saveAs } = FileSaver
const main = (): void => {
const btnList = new BtnList()
const scoreinfo = new ScoreInfoInPage(document)
const { fileName, id } = scoreinfo
const { fileName } = scoreinfo
// eslint-disable-next-line no-void
void getActualId(scoreinfo)
let indvPartBtn: HTMLButtonElement | null = null
const fallback = () => {
@ -45,12 +48,12 @@ const main = (): void => {
btnList.add({
name: i18n('DOWNLOAD')('MIDI'),
action: BtnAction.download(() => getFileUrl(id, 'midi'), fallback, 30 * 1000 /* 30s */),
action: BtnAction.download(() => getFileUrl(scoreinfo.id, 'midi'), fallback, 30 * 1000 /* 30s */),
})
btnList.add({
name: i18n('DOWNLOAD')('MP3'),
action: BtnAction.download(() => getFileUrl(id, 'mp3'), fallback, 30 * 1000 /* 30s */),
action: BtnAction.download(() => getFileUrl(scoreinfo.id, 'mp3'), fallback, 30 * 1000 /* 30s */),
})
indvPartBtn = btnList.add({

View File

@ -9,6 +9,7 @@
// @description download sheet music from musescore.com for free, no login or Musescore Pro required | 免登录、免 Musescore Pro免费下载 musescore.com 上的曲谱
// @author Xmader
// @match https://musescore.com/*/*
// @match https://s.musescore.com/*/*
// @license MIT
// @copyright Copyright (c) 2019-2020 Xmader
// @grant unsafeWindow

View File

@ -43,11 +43,18 @@ export class ScoreInfoInPage extends ScoreInfo {
const el = this.document.querySelector("meta[property='og:title']") as HTMLMetaElement
return el.content
}
get baseUrl (): string {
const el = this.document.querySelector("meta[property='og:image']") as HTMLMetaElement
const m = el.content.match(/^(.+\/)score_/) as RegExpMatchArray
return m[1]
}
}
export class ScoreInfoHtml extends ScoreInfo {
private readonly ID_REG = /<meta property="al:ios:url" content="musescore:\/\/score\/(\d+)">/
private readonly TITLE_REG = /<meta property="og:title" content="(.*)">/
private readonly BASEURL_REG = /<meta property="og:image" content="(.+\/)score_.*">/
constructor (private html: string) { super() }
@ -63,6 +70,12 @@ export class ScoreInfoHtml extends ScoreInfo {
return m[1]
}
get baseUrl (): string {
const m = this.html.match(this.BASEURL_REG)
if (!m) return ''
return m[1]
}
static async request (url: string, _fetch = getFetch()): Promise<ScoreInfoHtml> {
const r = await _fetch(url)
if (!r.ok) return new ScoreInfoHtml('')
@ -97,3 +110,25 @@ export class SheetInfoInPage extends SheetInfo {
return url.split('@')[0]
}
}
export const getActualId = async (scoreinfo: ScoreInfoInPage | ScoreInfoHtml, _fetch = getFetch()): Promise<number> => {
if (scoreinfo.id <= 1000000000000) {
// actual id already
return scoreinfo.id
}
const jsonPUrl = new URL(`${scoreinfo.baseUrl}space.jsonp`)
jsonPUrl.hostname = 's.musescore.com'
const r = await _fetch(jsonPUrl.href)
const text = await r.text()
const m = text.match(/^jsonp(\d+)/) as RegExpMatchArray
const id = +m[1]
Object.defineProperty(scoreinfo, 'id', {
get () { return id },
})
return id
}