├── LICENSE ├── README.md └── originalCode.js /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 PharaohsVizier 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Musescore Printer 2 | 3 | Print and download sheet music from Musescore. No downloads - just a single command in your browser. 4 | 5 | ## Usage 6 | 7 | 1. Open a Musescore song (i.e. https://musescore.com/user/8877016/scores/1974706). 8 | 2. Open Inspect Element (Ctrl+Shift+I on Chrome). **Important:** Make sure your screen is large enough so that the sheet music scrolls vertically (rather than horizontally) 9 | 3. Copy and paste the following line of code into the console (second tab on Chrome) (see ./originalCode.js for the actual code) 10 | ```js 11 | eval(await (await fetch("https://raw.githubusercontent.com/AnsonLai/MuseScore-Printer/master/originalCode.js")).text()) 12 | ``` 13 | 4. Enjoy! (it may take a couple of seconds if the score is very long.) 14 | 15 | Please note that you can print as PDF if you want to just download and save your music. There are options in the print dialog to remove the unsightly URL and date headers/footers as well. 16 | 17 | ## Purpose 18 | 19 | Musescore houses a lot of the sheet music on the internet. They recently went the paid subscription route so lots and lots of public domain and user generated sheet music suddenly went behind a paywall. You can still view it on your computer, but you can't print or download. 20 | 21 | There seem to be some solutions with Greasemonkey but for anyone who wants to just print one song without downloading a bunch of plugins, this is the way to go. **Just paste it into your browser and you can print right off the page (or print as PDF). No fuss, no downloads, and you can get straight back into playing some music.** 22 | 23 | ## Troubleshooting 24 | 25 | Chances are, Musescore will not use the class name I search for indefinitely. For anyone who knows anything about HTML DOM, this will be a 10 second fix. There is little they can do as long as they continue to display sheet music on their page. Feel free to send me a message and I'm more than happy to update this project if it breaks. 26 | -------------------------------------------------------------------------------- /originalCode.js: -------------------------------------------------------------------------------- 1 | //self invoked function (so it doesn't pollute the global scope) 2 | (async function () { 3 | const fetchLoadedImages = (querySelector, expectedNumberOfImages) => { 4 | console.log("Waiting for images to load..."); 5 | return new Promise((resolve) => { 6 | const intervalId = setInterval(() => { 7 | const images = [...document.querySelectorAll(querySelector)]; //arrays are easier to work with 8 | if (images.length === expectedNumberOfImages && images.every(image => image.src && image.complete)) { //Musescore sometimes initializes the image without a src 9 | clearInterval(intervalId); 10 | resolve(images); 11 | } 12 | }, 500); 13 | }) 14 | } 15 | 16 | const scrollViewSelector = "#jmuse-scroller-component"; 17 | const pageElementSelector = `${scrollViewSelector}>.F16e6`; 18 | const imageElementSelector = `${pageElementSelector}>img`; 19 | 20 | const pageContainer = document.querySelector(scrollViewSelector); 21 | const allChildren = document.querySelectorAll(scrollViewSelector + ">*"); 22 | const pages = document.querySelectorAll(pageElementSelector); 23 | 24 | const SCROLL_HEIGHT_PX = 10000; 25 | const VIEWPORT_HEIGHT_PX = 9999; 26 | 27 | //so all images are "visible" on the page 28 | for (const el of allChildren) { 29 | el.style.display = "none"; 30 | } 31 | 32 | pageContainer.insertAdjacentHTML("beforeend", `
`); 33 | pageContainer.style.height = VIEWPORT_HEIGHT_PX + "px"; 34 | pageContainer.scrollTo(0, 0); //just to reset scroll real quick 35 | pageContainer.scrollTo(0, 1); 36 | 37 | 38 | const images = await fetchLoadedImages(imageElementSelector, pages.length); 39 | 40 | document.getElementsByTagName("html")[0].innerHTML = ""; 41 | 42 | const style = document.createElement("style"); 43 | style.textContent = ` 44 | body{ 45 | margin:0; 46 | } 47 | img{ 48 | height:296mm; /* sometimes it overflows to the next page if it's 297mm */ 49 | } 50 | @page { 51 | size: A4; 52 | margin: 0; 53 | } 54 | @media print { 55 | html, body { 56 | width: 210mm; 57 | height: 297mm; 58 | } 59 | } 60 | `; 61 | document.head.appendChild(style); 62 | for (const image of images) { 63 | const imageClone = document.createElement("img"); 64 | imageClone.src = image.src; 65 | document.body.appendChild(imageClone); 66 | } 67 | 68 | fetchLoadedImages("img", pages.length).then(() => window.print()); 69 | 70 | })(); 71 | --------------------------------------------------------------------------------