MidiShow免积分下载
// ==UserScript==
// @name MidiShowDownload
// @namespace https://lgc2333.top/
// @version 0.2.0
// @description MidiShow免积分下载
// @author LgCookie
// @homepage https://github.com/lgc2333/GM/blob/main/packages/MidiShowDownload
// @match https://www.midishow.com/midi/*
// @match https://www.midishow.com/zh-tw/midi/*
// @match https://www.midishow.com/en/midi/*
// @license MIT
// @grant GM_addStyle
// ==/UserScript==
/* global $ JZZ PNotify */
;(function () {
'use strict'
const NAME = 'MidiShowDownload'
/** @type {string | null} */
let cachedDataURL = null
/**
* @param {string} str
* @returns {Uint8Array}
*/
function transformData(str) {
const arr = new Uint8Array(str.length)
for (let i = 0; i < str.length; i++) arr[i] = str.charCodeAt(i)
return arr
}
const originalSMF = JZZ.MIDI.SMF
const patchedSMF = /** @type {JZZ.MIDI.SMFConstructor} */ (
/** @this {JZZ.MIDI.SMF} */
function (data) {
const blob = new Blob([transformData(data)], { type: 'audio/midi' })
const url = URL.createObjectURL(blob)
if (cachedDataURL) URL.revokeObjectURL(cachedDataURL)
cachedDataURL = url
PNotify.success(`[${NAME}] 成功截获文件`)
return originalSMF.apply(this, [data])
}
)
JZZ.MIDI.SMF = patchedSMF
/**
* @param {string} url
* @param {string} filename
*/
function openSaveDialog(url, filename) {
const el = document.createElement('a')
el.href = url
el.download = filename
el.target = '_blank'
el.click()
}
async function download() {
const e = $('.ms-player-container')
const player = /** @type {JZZ.gui.Player | undefined} */ (
e.JzzPlayer().data('plugin_JzzPlayer')
)
if (!player) {
PNotify.error(`[${NAME}] 无法获取播放器实例`)
return
}
if (!cachedDataURL) {
await player.loadUrl()
}
if (!cachedDataURL) {
PNotify.error(`[${NAME}] 截获文件失败`)
return
}
const id = /** @type {string} */ (e.data('id'))
const title = e.find('h1.pl-md-player').text().trim()
openSaveDialog(cachedDataURL, `${id} - ${title}.mid`)
}
function setup() {
const downloadArea = /** @type {HTMLDivElement | null} */ (
document.getElementById('download')
)
const originalDownBtn = downloadArea?.firstElementChild
if (!originalDownBtn) {
PNotify.error(`[${NAME}] 添加下载按钮失败:定位不到目标元素`)
return
}
GM_addStyle(`a.btn.btn-primary.disabled { filter: grayscale(1); }`)
const btnHtml =
`<a class="btn btn-primary btn-sm mb-3 mr-2" href="javascript:void">` +
`<span class="fa fa-download"></span> ${NAME}` +
`</a>`
originalDownBtn.insertAdjacentHTML('afterend', btnHtml)
const btn = /** @type {HTMLAnchorElement} */ (originalDownBtn.nextElementSibling)
btn.addEventListener('click', async () => {
if (btn.classList.contains('disabled')) return
btn.classList.add('disabled')
try {
await download()
} catch (e) {
PNotify.error(`[${NAME}] 出现意外错误\n${/** @type {any} */ (e).toString()}`)
}
btn.classList.remove('disabled')
})
}
window.addEventListener('load', setup)
})()