initial commit
This commit is contained in:
commit
2c8b3c1360
11 changed files with 372 additions and 0 deletions
1
.eslintignore
Normal file
1
.eslintignore
Normal file
|
@ -0,0 +1 @@
|
|||
dist/*
|
35
.eslintrc
Normal file
35
.eslintrc
Normal file
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"commonjs": true,
|
||||
"es6": true,
|
||||
"node": true
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2019,
|
||||
"sourceType": "module",
|
||||
"ecmaFeatures": {
|
||||
"jsx": true
|
||||
}
|
||||
},
|
||||
"rules": {
|
||||
"indent": [
|
||||
"error",
|
||||
4
|
||||
],
|
||||
"linebreak-style": [
|
||||
"error",
|
||||
"unix"
|
||||
],
|
||||
"quotes": [
|
||||
"warn",
|
||||
"double"
|
||||
],
|
||||
"semi": [
|
||||
"warn",
|
||||
"never"
|
||||
],
|
||||
"no-console": "off"
|
||||
}
|
||||
}
|
66
.gitignore
vendored
Normal file
66
.gitignore
vendored
Normal file
|
@ -0,0 +1,66 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# TypeScript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
|
||||
# next.js build output
|
||||
.next
|
||||
|
||||
# parcel build cache
|
||||
.cache
|
||||
|
||||
package-lock.json
|
21
LICENSE
Normal file
21
LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2019 Xmader
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
53
dist/main.js
vendored
Normal file
53
dist/main.js
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
// ==UserScript==
|
||||
// @name musescore-downloader
|
||||
// @namespace https://www.xmader.com/
|
||||
// @version 0.1.0
|
||||
// @description 免登录、免 Musescore Pro,下载 musescore.com 上的曲谱
|
||||
// @author Xmader
|
||||
// @match https://musescore.com/user/*/scores/*
|
||||
// @license MIT
|
||||
// @copyright Copyright (c) 2019 Xmader
|
||||
// @grant none
|
||||
// ==/UserScript==
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
const getIndexPath = (id) => {
|
||||
const idStr = String(id);
|
||||
// 获取最后三位,倒序排列
|
||||
// "5449062" -> ["2", "6", "0"]
|
||||
const indexN = idStr.split("").reverse().slice(0, 3);
|
||||
return indexN.join("/");
|
||||
};
|
||||
|
||||
// @ts-ignore
|
||||
const scorePlayer = window.UGAPP.store.jmuse_settings.score_player;
|
||||
const { id, vid } = scorePlayer.json;
|
||||
const baseURL = scorePlayer.urls.image_path;
|
||||
const scoreHexId = baseURL.split("/").filter(Boolean).reverse()[1];
|
||||
const msczURL = `https://musescore.com/static/musescore/scoredata/score/${getIndexPath}/${id}/score_${vid}_${scoreHexId}.mscz`;
|
||||
const pdfURL = baseURL + "score_full.pdf";
|
||||
const mxlURL = baseURL + "score.mxl";
|
||||
const { midi: midiURL, mp3: mp3URL } = scorePlayer.urls;
|
||||
const btnsDiv = document.querySelectorAll("aside section > div")[3];
|
||||
const downloadBtn = btnsDiv.querySelector("button");
|
||||
downloadBtn.onclick = null;
|
||||
const downloadURLs = {
|
||||
"Musescore": msczURL,
|
||||
"PDF": pdfURL,
|
||||
"MusicXML": mxlURL,
|
||||
"MIDI": midiURL,
|
||||
"MP3": mp3URL,
|
||||
};
|
||||
const newDownloadBtns = Object.keys(downloadURLs).map((name) => {
|
||||
const url = downloadURLs[name];
|
||||
const btn = downloadBtn.cloneNode(true);
|
||||
btn.onclick = () => {
|
||||
window.open(url);
|
||||
};
|
||||
return btn;
|
||||
});
|
||||
downloadBtn.replaceWith(...newDownloadBtns);
|
||||
|
||||
}());
|
28
package.json
Normal file
28
package.json
Normal file
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "musescore-downloader",
|
||||
"version": "0.1.0",
|
||||
"description": "免登录、免 Musescore Pro,下载 musescore.com 上的曲谱",
|
||||
"main": "dist/main.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/Xmader/musescore-downloader.git"
|
||||
},
|
||||
"author": "Xmader",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/Xmader/musescore-downloader/issues"
|
||||
},
|
||||
"homepage": "https://github.com/Xmader/musescore-downloader#readme",
|
||||
"devDependencies": {
|
||||
"rollup": "^1.26.3",
|
||||
"rollup-plugin-typescript": "^1.0.1",
|
||||
"tslib": "^1.10.0",
|
||||
"typescript": "^3.6.4"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "rollup -c",
|
||||
"watch": "npm run build -- --watch",
|
||||
"bump-version:patch": "npm version patch --no-git-tag",
|
||||
"bump-version:minor": "npm version minor --no-git-tag"
|
||||
}
|
||||
}
|
24
rollup.config.js
Normal file
24
rollup.config.js
Normal file
|
@ -0,0 +1,24 @@
|
|||
import typescript from "rollup-plugin-typescript"
|
||||
import fs from "fs"
|
||||
import { version } from "./package.json"
|
||||
|
||||
let bannerText = fs.readFileSync("./src/meta.js", "utf-8")
|
||||
bannerText = bannerText.replace("%VERSION%", version)
|
||||
|
||||
export default {
|
||||
input: "src/main.ts",
|
||||
output: {
|
||||
file: "dist/main.js",
|
||||
format: "iife",
|
||||
banner: bannerText,
|
||||
},
|
||||
plugins: [
|
||||
typescript({
|
||||
target: "ES6",
|
||||
lib: [
|
||||
"ES6",
|
||||
"dom"
|
||||
],
|
||||
})
|
||||
]
|
||||
}
|
41
src/main.ts
Normal file
41
src/main.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
import "./meta"
|
||||
|
||||
import { ScorePlayerData } from "./types"
|
||||
import { getIndexPath } from "./utils"
|
||||
|
||||
// @ts-ignore
|
||||
const scorePlayer: ScorePlayerData = window.UGAPP.store.jmuse_settings.score_player
|
||||
|
||||
const { id, vid } = scorePlayer.json
|
||||
const baseURL = scorePlayer.urls.image_path
|
||||
const scoreHexId = baseURL.split("/").filter(Boolean).reverse()[1]
|
||||
|
||||
const msczURL = `https://musescore.com/static/musescore/scoredata/score/${getIndexPath}/${id}/score_${vid}_${scoreHexId}.mscz`
|
||||
const pdfURL = baseURL + "score_full.pdf"
|
||||
const mxlURL = baseURL + "score.mxl"
|
||||
const { midi: midiURL, mp3: mp3URL } = scorePlayer.urls
|
||||
|
||||
const btnsDiv = document.querySelectorAll("aside section > div")[3]
|
||||
const downloadBtn = btnsDiv.querySelector("button")
|
||||
downloadBtn.onclick = null
|
||||
|
||||
const downloadURLs = {
|
||||
"Musescore": msczURL,
|
||||
"PDF": pdfURL,
|
||||
"MusicXML": mxlURL,
|
||||
"MIDI": midiURL,
|
||||
"MP3": mp3URL,
|
||||
}
|
||||
|
||||
const newDownloadBtns = Object.keys(downloadURLs).map((name) => {
|
||||
const url = downloadURLs[name]
|
||||
|
||||
const btn = downloadBtn.cloneNode(true) as HTMLButtonElement
|
||||
btn.onclick = () => {
|
||||
window.open(url)
|
||||
}
|
||||
|
||||
return btn
|
||||
})
|
||||
|
||||
downloadBtn.replaceWith(...newDownloadBtns)
|
11
src/meta.js
Normal file
11
src/meta.js
Normal file
|
@ -0,0 +1,11 @@
|
|||
// ==UserScript==
|
||||
// @name musescore-downloader
|
||||
// @namespace https://www.xmader.com/
|
||||
// @version %VERSION%
|
||||
// @description 免登录、免 Musescore Pro,下载 musescore.com 上的曲谱
|
||||
// @author Xmader
|
||||
// @match https://musescore.com/user/*/scores/*
|
||||
// @license MIT
|
||||
// @copyright Copyright (c) 2019 Xmader
|
||||
// @grant none
|
||||
// ==/UserScript==
|
84
src/types.ts
Normal file
84
src/types.ts
Normal file
|
@ -0,0 +1,84 @@
|
|||
|
||||
interface SourceData {
|
||||
type: string; // "audio"
|
||||
title: string; // "Musescore audio"
|
||||
nid: number;
|
||||
}
|
||||
|
||||
type CommentData = any;
|
||||
|
||||
interface PartData {
|
||||
part: {
|
||||
name: string;
|
||||
program: number;
|
||||
}
|
||||
}
|
||||
|
||||
interface Metadata {
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
composer?: string;
|
||||
poet?: string;
|
||||
pages: number;
|
||||
measures: number;
|
||||
lyrics: number;
|
||||
chordnames: number;
|
||||
keysig: number;
|
||||
duration: number;
|
||||
dimensions: number;
|
||||
parts: PartData[];
|
||||
}
|
||||
|
||||
interface ScoreJson {
|
||||
id: number;
|
||||
vid: number;
|
||||
dates: {
|
||||
revised: number;
|
||||
};
|
||||
secret: string;
|
||||
permalink: string;
|
||||
custom_url: string;
|
||||
format: string; // "0"
|
||||
has_custom_audio: 0 | 1;
|
||||
metadata: Metadata;
|
||||
}
|
||||
|
||||
interface UrlsData {
|
||||
midi: string;
|
||||
mp3: string;
|
||||
space: string;
|
||||
image_path: string;
|
||||
media?: string[];
|
||||
}
|
||||
|
||||
interface AccessControlData {
|
||||
enabled: boolean;
|
||||
hasAccess: boolean;
|
||||
}
|
||||
|
||||
interface PianoKeyboardData extends AccessControlData {
|
||||
midiUrl: string;
|
||||
}
|
||||
|
||||
interface PianoRollData extends AccessControlData {
|
||||
resourcesUrl: string;
|
||||
feedbackUrl: string;
|
||||
forceShow: boolean;
|
||||
}
|
||||
|
||||
export interface ScorePlayerData {
|
||||
embed: boolean;
|
||||
sources: SourceData[];
|
||||
default_source?: SourceData;
|
||||
mixer?: string;
|
||||
secondaryMixer?: string;
|
||||
bucket?: string; // "https://musescore.com/static/musescore/scoredata"
|
||||
json: ScoreJson;
|
||||
render_vector: boolean;
|
||||
comments: CommentData[];
|
||||
score_id: number;
|
||||
urls: UrlsData;
|
||||
sendEvents?: boolean;
|
||||
pianoKeyboard: PianoKeyboardData;
|
||||
pianoRoll: PianoRollData;
|
||||
}
|
8
src/utils.ts
Normal file
8
src/utils.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
|
||||
export const getIndexPath = (id: number) => {
|
||||
const idStr = String(id)
|
||||
// 获取最后三位,倒序排列
|
||||
// "5449062" -> ["2", "6", "0"]
|
||||
const indexN = idStr.split("").reverse().slice(0, 3)
|
||||
return indexN.join("/")
|
||||
}
|
Loading…
Reference in a new issue