feat: support s.musescore.com urls
This commit is contained in:
parent
7485d884bf
commit
7fc1a5fb6a
5 changed files with 49 additions and 8 deletions
|
@ -25,7 +25,7 @@
|
|||
"content_scripts": [
|
||||
{
|
||||
"matches": [
|
||||
"*://musescore.com/*/*"
|
||||
"*://*.musescore.com/*/*"
|
||||
],
|
||||
"js": [
|
||||
"src/web-ext.js"
|
||||
|
|
|
@ -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>({
|
||||
|
|
11
src/main.ts
11
src/main.ts
|
@ -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({
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue