Musescore Downloader

download pdf or print any sheets!

目前为 2022-10-19 提交的版本。查看 最新版本

// ==UserScript==
// @name         Musescore Downloader
// @version      1.0
// @description  download pdf or print any sheets!
// @author       Charlie
// @match        https://musescore.com/*
// @namespace https://gf.qytechs.cn/users/890174
// ==/UserScript==

setTimeout(() => {
    "use strict"

    async function download(autoPrint) {
        const Window = window.open()
        const id = location.pathname.match(/\/[^\/]*$/)[0].slice(1)
        const length = document.getElementsByClassName("BmIOX").length
        Window.document.write(`
<!DOCTYPE html>
<head>
<title>${document.getElementsByTagName('h1')[0].innerText}</title>
<style>
    body {
        margin: 0;
        display: flex;
        min-height: 100vh;
        flex-direction: column;
        place-items: center;
        justify-content: center;
        color: rgb(49, 63, 78);
        background-color: rgb(237, 242, 247);
        transform-origin: top;
        transition: background-color ease .3s;
        will-change: background-color;
        overflow-x: scroll;
    }

    svg {
        width: 100vw;
        height: auto;
        display: block;
        margin: auto;
    }

    .card {
        display: flex;
        text-align: center;
        place-items: center;
        font-size: 1.2em;
        width: 320px;
        box-shadow: 10px 10px 8px rgba(0, 0, 0, 0.07);
        padding: 1.5em 2em;
        background-color: rgb(255, 255, 255);
        border-radius: 8px;
        transition: all ease-out .3s;
        animation: card-intro .8s ease-out;
        overflow: hidden;
        white-space: nowrap;
    }

    @keyframes card-intro {
        from {
            box-shadow: 10px 10px 2px rgba(0, 0, 0, 0.03);
            width: 0;
            opacity: 0.6;
        }
        to {
            box-shadow: 10px 10px 8px rgba(0, 0, 0, 0.07);
            width: 320px;
            opacity: 1;
        }
    }

    .card-icon {
        display: flex;
        flex-direction: column;
        place-items: center;
        margin-right: 3em;
        font-weight: bold;
    }

    .card-text {
        flex: 1;
    }

    b {
        color: rgb(49, 140, 252);
    }

    .spinner, .spinner * { box-sizing: border-box; }
    .spinner {
      height: 40px;
      width: 40px;
      top: calc( -10px * 2 / 3);
      margin-left: calc(10px / 3);
      margin-bottom: calc(10px / 3);
    }
    .spinner .sq {
      height: 10px;
      width: 10px;
      top: calc( -10px * 2 / 3);
      margin-right: calc(10px / 3);
      margin-top: calc(10px / 3);
      background: rgb(49, 140, 252);
      float: left;
      position: relative;
      opacity: 0;
      animation: spinner 6s infinite;
    }
    .spinner .sq:nth-child(1) { animation-delay: calc(300ms * 6); }
    .spinner .sq:nth-child(2) { animation-delay: calc(300ms * 7); }
    .spinner .sq:nth-child(3) { animation-delay: calc(300ms * 8); }
    .spinner .sq:nth-child(4) { animation-delay: calc(300ms * 3); }
    .spinner .sq:nth-child(5) { animation-delay: calc(300ms * 4); }
    .spinner .sq:nth-child(6) { animation-delay: calc(300ms * 5); }
    .spinner .sq:nth-child(7) { animation-delay: calc(300ms * 0); }
    .spinner .sq:nth-child(8) { animation-delay: calc(300ms * 1); }
    .spinner .sq:nth-child(9) { animation-delay: calc(300ms * 2); }
    .spinner .clear { clear: both; }
    @keyframes spinner {
      0% { opacity: 0; }
      5% { opacity: 1; top: 0; }
      50.9% { opacity: 1; top: 0; }
      55.9% { opacity: 0; top: inherit; }
    }

    @media print {
        @page {
            margin: 0;
        }
        button {
            display: none;
        }
        svg {
            width: 21cm;
            height: 29.7cm;
        }
    }

    .btn-group {
        position: fixed;
        left: 32px;
        top: 24px;
    }
    button {
        font-size: 1.4em;
        font-weight: bold;
        box-shadow: 1px 2px 8px rgba(0, 0, 0, 0.1);
        padding: .4em 1.6em;
        margin-right: 1.2em;
        background-color: rgb(255, 255, 255);
        color: rgb(49, 63, 78);
        border-radius: 4px;
        cursor: pointer;
        outline: 1.5px solid rgb(49, 63, 78);
        border: none;
        transition: all ease-out .2s;
    }
    button:hover {
        background-color: rgb(235, 235, 235);
    }
    button:active {
        outline-color: black;
        transform: scale(0.97);
    }
</style>
</head>
<body>
<div class="card">
    <div class="card-icon">
        <div class="spinner">
          <div class="sq"></div>
          <div class="sq"></div>
          <div class="sq"></div>
          <div class="sq clear"></div>
          <div class="sq"></div>
          <div class="sq"></div>
          <div class="sq clear"></div>
          <div class="sq"></div>
          <div class="sq"></div>
        </div>
        <div class="card-icon-text">下载中</div>
    </div>
    <div class="card-text">
    第 <b id="download-status">0</b> 页,共 <b>${length}</b> 页
    </div>
</div>
</body>`)
        let dataString = ""
        for (let i = 0; i < length; i++) {
            let url = await fetch(`https://musescore.com/api/jmuse?id=${id}&type=img&v2=1&index=${i}`, {
                headers: {
                    authorization: "8c022bdef45341074ce876ae57a48f64b86cdcf5"
                }
            }).then(e => e.json())
            .then(e => e.info.url)
            dataString += await fetch(url).then(e => e.text())
            Window.document.getElementById("download-status").innerText = i + 1
        }
        setTimeout(() => {
            Window.document.getElementsByClassName("card-icon-text")[0].innerText = "完成!"
            setTimeout(() => {
                Window.document.body.style.background = "white"
                Window.document.body.innerHTML = dataString + `<div class="btn-group"><button onclick="print()">打印</button>`
                const svgs = [...Window.document.getElementsByTagName("svg")]
                svgs.forEach((e) => e.setAttribute("viewBox", `0 0 ${e.width.baseVal.value} ${e.height.baseVal.value}`))
                Window.scrollTo(0, 0)
                if(autoPrint) Window.print()
            }, 400)
        }, 800)
    }

    const btns = [...document.getElementsByTagName("button")]
    btns.filter(el => {
        const val = el.attributes.getNamedItem("name")?.value
        return val == "download" || val == "print"
    }).forEach(el => {
        const type = el.attributes.getNamedItem("name").value
        const fakeEl = el.cloneNode(true)
        fakeEl.style.border = "2px #0dbc79 solid"
        if(type == "download") fakeEl.style.background = "#0dbc79"
        fakeEl.onclick = () => download(type == 'print')
        el.parentNode.replaceChild(fakeEl, el)
    })
}, 500)

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址