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