Musescore Downloader

download pdf or print any sheets!

当前为 2022-10-19 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Musescore Downloader
  3. // @version 1.0
  4. // @description download pdf or print any sheets!
  5. // @author Charlie
  6. // @match https://musescore.com/*
  7. // @namespace https://greasyfork.org/users/890174
  8. // ==/UserScript==
  9.  
  10. setTimeout(() => {
  11. "use strict"
  12.  
  13. async function download(autoPrint) {
  14. const Window = window.open()
  15. const id = location.pathname.match(/\/[^\/]*$/)[0].slice(1)
  16. const length = document.getElementsByClassName("BmIOX").length
  17. Window.document.write(`
  18. <!DOCTYPE html>
  19. <head>
  20. <title>${document.getElementsByTagName('h1')[0].innerText}</title>
  21. <style>
  22. body {
  23. margin: 0;
  24. display: flex;
  25. min-height: 100vh;
  26. flex-direction: column;
  27. place-items: center;
  28. justify-content: center;
  29. color: rgb(49, 63, 78);
  30. background-color: rgb(237, 242, 247);
  31. transform-origin: top;
  32. transition: background-color ease .3s;
  33. will-change: background-color;
  34. overflow-x: scroll;
  35. }
  36.  
  37. svg {
  38. width: 100vw;
  39. height: auto;
  40. display: block;
  41. margin: auto;
  42. }
  43.  
  44. .card {
  45. display: flex;
  46. text-align: center;
  47. place-items: center;
  48. font-size: 1.2em;
  49. width: 320px;
  50. box-shadow: 10px 10px 8px rgba(0, 0, 0, 0.07);
  51. padding: 1.5em 2em;
  52. background-color: rgb(255, 255, 255);
  53. border-radius: 8px;
  54. transition: all ease-out .3s;
  55. animation: card-intro .8s ease-out;
  56. overflow: hidden;
  57. white-space: nowrap;
  58. }
  59.  
  60. @keyframes card-intro {
  61. from {
  62. box-shadow: 10px 10px 2px rgba(0, 0, 0, 0.03);
  63. width: 0;
  64. opacity: 0.6;
  65. }
  66. to {
  67. box-shadow: 10px 10px 8px rgba(0, 0, 0, 0.07);
  68. width: 320px;
  69. opacity: 1;
  70. }
  71. }
  72.  
  73. .card-icon {
  74. display: flex;
  75. flex-direction: column;
  76. place-items: center;
  77. margin-right: 3em;
  78. font-weight: bold;
  79. }
  80.  
  81. .card-text {
  82. flex: 1;
  83. }
  84.  
  85. b {
  86. color: rgb(49, 140, 252);
  87. }
  88.  
  89. .spinner, .spinner * { box-sizing: border-box; }
  90. .spinner {
  91. height: 40px;
  92. width: 40px;
  93. top: calc( -10px * 2 / 3);
  94. margin-left: calc(10px / 3);
  95. margin-bottom: calc(10px / 3);
  96. }
  97. .spinner .sq {
  98. height: 10px;
  99. width: 10px;
  100. top: calc( -10px * 2 / 3);
  101. margin-right: calc(10px / 3);
  102. margin-top: calc(10px / 3);
  103. background: rgb(49, 140, 252);
  104. float: left;
  105. position: relative;
  106. opacity: 0;
  107. animation: spinner 6s infinite;
  108. }
  109. .spinner .sq:nth-child(1) { animation-delay: calc(300ms * 6); }
  110. .spinner .sq:nth-child(2) { animation-delay: calc(300ms * 7); }
  111. .spinner .sq:nth-child(3) { animation-delay: calc(300ms * 8); }
  112. .spinner .sq:nth-child(4) { animation-delay: calc(300ms * 3); }
  113. .spinner .sq:nth-child(5) { animation-delay: calc(300ms * 4); }
  114. .spinner .sq:nth-child(6) { animation-delay: calc(300ms * 5); }
  115. .spinner .sq:nth-child(7) { animation-delay: calc(300ms * 0); }
  116. .spinner .sq:nth-child(8) { animation-delay: calc(300ms * 1); }
  117. .spinner .sq:nth-child(9) { animation-delay: calc(300ms * 2); }
  118. .spinner .clear { clear: both; }
  119. @keyframes spinner {
  120. 0% { opacity: 0; }
  121. 5% { opacity: 1; top: 0; }
  122. 50.9% { opacity: 1; top: 0; }
  123. 55.9% { opacity: 0; top: inherit; }
  124. }
  125.  
  126. @media print {
  127. @page {
  128. margin: 0;
  129. }
  130. button {
  131. display: none;
  132. }
  133. svg {
  134. width: 21cm;
  135. height: 29.7cm;
  136. }
  137. }
  138.  
  139. .btn-group {
  140. position: fixed;
  141. left: 32px;
  142. top: 24px;
  143. }
  144. button {
  145. font-size: 1.4em;
  146. font-weight: bold;
  147. box-shadow: 1px 2px 8px rgba(0, 0, 0, 0.1);
  148. padding: .4em 1.6em;
  149. margin-right: 1.2em;
  150. background-color: rgb(255, 255, 255);
  151. color: rgb(49, 63, 78);
  152. border-radius: 4px;
  153. cursor: pointer;
  154. outline: 1.5px solid rgb(49, 63, 78);
  155. border: none;
  156. transition: all ease-out .2s;
  157. }
  158. button:hover {
  159. background-color: rgb(235, 235, 235);
  160. }
  161. button:active {
  162. outline-color: black;
  163. transform: scale(0.97);
  164. }
  165. </style>
  166. </head>
  167. <body>
  168. <div class="card">
  169. <div class="card-icon">
  170. <div class="spinner">
  171. <div class="sq"></div>
  172. <div class="sq"></div>
  173. <div class="sq"></div>
  174. <div class="sq clear"></div>
  175. <div class="sq"></div>
  176. <div class="sq"></div>
  177. <div class="sq clear"></div>
  178. <div class="sq"></div>
  179. <div class="sq"></div>
  180. </div>
  181. <div class="card-icon-text">下载中</div>
  182. </div>
  183. <div class="card-text">
  184. <b id="download-status">0</b> 页,共 <b>${length}</b>
  185. </div>
  186. </div>
  187. </body>`)
  188. let dataString = ""
  189. for (let i = 0; i < length; i++) {
  190. let url = await fetch(`https://musescore.com/api/jmuse?id=${id}&type=img&v2=1&index=${i}`, {
  191. headers: {
  192. authorization: "8c022bdef45341074ce876ae57a48f64b86cdcf5"
  193. }
  194. }).then(e => e.json())
  195. .then(e => e.info.url)
  196. dataString += await fetch(url).then(e => e.text())
  197. Window.document.getElementById("download-status").innerText = i + 1
  198. }
  199. setTimeout(() => {
  200. Window.document.getElementsByClassName("card-icon-text")[0].innerText = "完成!"
  201. setTimeout(() => {
  202. Window.document.body.style.background = "white"
  203. Window.document.body.innerHTML = dataString + `<div class="btn-group"><button onclick="print()">打印</button>`
  204. const svgs = [...Window.document.getElementsByTagName("svg")]
  205. svgs.forEach((e) => e.setAttribute("viewBox", `0 0 ${e.width.baseVal.value} ${e.height.baseVal.value}`))
  206. Window.scrollTo(0, 0)
  207. if(autoPrint) Window.print()
  208. }, 400)
  209. }, 800)
  210. }
  211.  
  212. const btns = [...document.getElementsByTagName("button")]
  213. btns.filter(el => {
  214. const val = el.attributes.getNamedItem("name")?.value
  215. return val == "download" || val == "print"
  216. }).forEach(el => {
  217. const type = el.attributes.getNamedItem("name").value
  218. const fakeEl = el.cloneNode(true)
  219. fakeEl.style.border = "2px #0dbc79 solid"
  220. if(type == "download") fakeEl.style.background = "#0dbc79"
  221. fakeEl.onclick = () => download(type == 'print')
  222. el.parentNode.replaceChild(fakeEl, el)
  223. })
  224. }, 500)