// ==UserScript==
// @name Musescore Free PDF Downloader
// @namespace http://tampermonkey.net/
// @version 1.0
// @author malatia
// @match https://musescore.com/*/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=musescore.com
// @grant GM_addStyle
// @require https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/pdf-lib/1.16.0/pdf-lib.min.js
// @description An automatic and free score downloader for musescore
// @license MIT
// ==/UserScript==
// Idea from MuseScore Download By flancast90
let DEBUG = true
GM_addStyle(`.glowbutton {
--glow-color: rgb(176, 252, 255);
--glow-spread-color: rgba(123, 251, 255, 0.781);
--enhanced-glow-color: rgb(206, 255, 255);
--btn-color: rgb(61, 127, 136);
border: 0.25em solid var(--glow-color);
padding: 1em 1em;
color: var(--glow-color);
font-size: 15px;
font-weight: bold;
background-color: var(--btn-color);
border-radius: 1em;
outline: none;
box-shadow: 0 0 1em 0.25em var(--glow-color),
0 0 4em 1em var(--glow-spread-color),
inset 0 0 0.75em 0.25em var(--glow-color);
text-shadow: 0 0 0.5em var(--glow-color);
position: relative;
transition: all 0.3s;
}
.glowbutton::after {
pointer-events: none;
content: "";
position: absolute;
top: 120%;
left: 0;
height: 100%;
width: 100%;
background-color: var(--glow-spread-color);
filter: blur(2em);
opacity: 0.7;
transform: perspective(1.5em) rotateX(35deg) scale(1, 0.6);
}
.glowbutton:hover {
color: var(--btn-color);
background-color: var(--glow-color);
box-shadow: 0 0 1em 0.25em var(--glow-color),
0 0 4em 2em var(--glow-spread-color),
inset 0 0 0.75em 0.25em var(--glow-color);
}
.glowbutton:active {
box-shadow: 0 0 0.6em 0.25em var(--glow-color),
0 0 2.5em 2em var(--glow-spread-color),
inset 0 0 0.5em 0.25em var(--glow-color);
}
`)
async function img_to_canvas_to_bytes(img) {
return new Promise((resolve, reject) => {
// Création d'un canvas pour dessiner l'image
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
// Chargement de l'image dans le canvas
img.crossOrigin = 'Anonymous'; // Permet d'accéder à l'image cross-origin
img.onload = () => {
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
// Conversion du contenu du canvas en données PNG
const pngBytes = canvas.toDataURL('image/png').split(',')[1];
resolve(pngBytes);
};
img.onerror = () => {
reject(new Error('Échec du chargement de l\'image.'));
};
img.src = img.src; // Déclenche le chargement de l'image
});
}
async function fetchAndAssemblePDF(urls) {
// Création d'un nouveau document PDF
const pdfDoc = await PDFLib.PDFDocument.create();
// Tableau pour stocker les documents PNG générés
const pngDocs = [];
// Parcours de chaque URL de fichier img
console.log("Avant boucle urls")
for (const url of urls) {
console.log("url = " + url)
// Récupération du fichier img à partir de l'URL
const response = await fetch(url);
console.log(response)
const imgText = await response.text();
if (url.includes(".svg")) {
const img = new Image();
const imgLoaded = new Promise((resolve, reject) => {
img.onload = resolve;
img.onerror = reject;
});
// Création d'un blob à partir du texte SVG
const svgBlob = new Blob([imgText], { type: 'image/svg+xml' });
// Création d'une image à partir du blob SVG
img.src = URL.createObjectURL(svgBlob);
// Attente du chargement complet de l'image
try {
// Attendre le chargement complet de l'image
await imgLoaded;
console.log("Image SVG chargée avec succès");
} catch (error) {
console.error("Erreur lors du chargement de l'image SVG:", error);
continue; // Passe à l'itération suivante dans la boucle
}
// Création d'un canvas pour dessiner l'image SVG
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
// Conversion du canvas en format PNG
const pngBytes = canvas.toDataURL('image/png').split(',')[1];
// Incorporation du PNG dans le document PDF
const pngDoc = await pdfDoc.embedPng(pngBytes);
pngDocs.push(pngDoc); // Ajout du document PNG au tableau
}
else if (url.includes(".png")) {
console.log("Dans la partie PNG");
const img = new Image();
const imgLoaded = new Promise((resolve, reject) => {
img.onload = resolve;
img.onerror = reject;
});
// Chargement de l'image à partir de l'URL
img.src = url;
// Promesse basée sur le chargement complet de l'image
try {
// Attendre le chargement complet de l'image
await imgLoaded;
console.log("Image PNG chargée avec succès");
} catch (error) {
console.error("Erreur lors du chargement de l'image PNG:", error);
continue; // Passe à l'itération suivante dans la boucle
}
const pngBytes = await img_to_canvas_to_bytes(img)
// Incorporation de l'image PNG dans le document PDF
const pngDoc = await pdfDoc.embedPng(pngBytes);
pngDocs.push(pngDoc);
}
}
// Parcours des documents PNG pour les ajouter au document PDF
for (const pngDoc of pngDocs) {
const page = pdfDoc.addPage([pngDoc.width, pngDoc.height]);
page.drawImage(pngDoc, {
x: 0,
y: 0,
width: pngDoc.width,
height: pngDoc.height,
});
}
// Enregistrement du document PDF
const pdfBytes = await pdfDoc.save();
// Téléchargement du PDF
const blob = new Blob([pdfBytes], { type: 'application/pdf' });
const link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
let title = document.title.replace(" ", "_") + ".pdf"
link.download = title;
link.click();
}
let scrolled = 0;
let urls = [];
let height;
let scrollHeight;
let scrollContainer
$(document).ready(async function () {
setTimeout(() => {
// ICI ON PARLE DU CONTENANT AVEC SCROLL
scrollContainer = parseInt(document.getElementById('jmuse-scroller-component').scrollHeight);
// ICI ON PARLE DES IMAGES
height = parseInt(document.getElementsByClassName('KfFlO')[0].height);
scrollHeight = (scrollContainer - (scrollContainer % height));
// On cherche le bouton downlad de base pour le remplacer par le nôtre
const btns = [...document.getElementsByTagName("button")]
btns.filter(el => {
const val = el.attributes.getNamedItem("name")?.value
return val == "download"
}).forEach(el => {
const type = el.attributes.getNamedItem("name").value
const fakeEl = el.cloneNode(true)
// fakeEl.style.border = "2px #0dbc79 solid"
fakeEl.value = "Download Free PDF"
fakeEl.classList.add("glowbutton")
// fakeEl.style.webkitBoxShadow = "0px 0px 127px 65px rgba(45,255,196,0.8);"
// fakeEl.style.mozBoxShadow = "0px 0px 127px 65px rgba(45,255,196,0.8);;"
// fakeEl.style.BoxShadow = "0px 0px 127px 65px rgba(45,255,196,0.8);"
fakeEl.class =
fakeEl.onclick = download_pdf
el.parentNode.replaceChild(fakeEl, el)
})
}, 2000)
// function get_lazy_imgs() {
// // Fonction récursive pour récupérer les images
// while (scrolled < scrollHeight) {
// // Attendre un peu avant de récupérer les images
// setTimeout(() => {
// // Faire défiler la fenêtre
// console.log("Scrolled : " + scrolled)
// console.log("scrollHeight : " + scrollHeight)
// scrollContainer.scrollTop = scrolled;
// scrolled += height;
// if (DEBUG) console.log("Get_lazy")
// // Récupérer les images
// let images = document.getElementsByClassName('KfFlO');
// if (images.length > 0) {
// urls.push(images[images.length - 1].src);
// }
// }, 1000);
// }
// }
function get_lazy_imgs() {
console.log("Début get_lazy_images");
return new Promise((resolve, reject) => {
// Fonction récursive pour récupérer les images
function fetchImages() {
scrollContainer = document.getElementById('jmuse-scroller-component');
scrollHeight = scrollContainer.scrollHeight;
if (scrolled < scrollHeight) {
// Faire défiler la fenêtre
scrollContainer.scrollTop = scrolled;
scrolled += height;
// Attendre un peu avant de récupérer les images
setTimeout(() => {
// Récupérer les images
const images = document.getElementsByClassName('KfFlO');
if (images.length > 0) {
// Ajouter les URLs des images au tableau
urls.push(images[images.length - 1].src);
}
// Rappel récursif jusqu'à ce que le scroll atteigne la fin
fetchImages();
}, 1000);
} else {
// Résoudre la promesse avec les URLs des images
resolve(urls);
console.log("Fin get_lazy_images");
}
}
// Début de la récupération des images
fetchImages();
});
}
async function download_pdf() {
console.log("Avant get_lazy_images");
await get_lazy_imgs(); // Attendre la récupération de toutes les URLs d'images
console.log("Après get_lazy_images");
console.log("Avant fetchAndAssemble");
await fetchAndAssemblePDF(urls); // Utiliser les URLs pour générer le PDF
console.log("Après fetchAndAssemble");
scrolled = 0; // Réinitialiser le défilement
}
});