Skip to content

Commit

Permalink
adapted to new musescore auth upgrade
Browse files Browse the repository at this point in the history
  • Loading branch information
ingui-n committed Feb 1, 2024
1 parent 25d716e commit 0ad810a
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 173 deletions.
28 changes: 14 additions & 14 deletions src/background/background.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,28 @@
import browser from 'webextension-polyfill';
import {getTokens, resetPageStorage, setTokens} from '../modules/utils';
import {updateCurrentTab} from "../modules/utils";

browser.runtime.onInstalled.addListener(async () => {
await resetPageStorage('tokens', {img: '', mp3: '', midi: ''});
});

/** store tokens */
browser.webRequest.onSendHeaders.addListener(
async ({url, requestHeaders}) => {
const matchMediaType = url.match(/^https:\/\/musescore\.com\/api\/jmuse\?id=\d+&index=[01]&type=(\w+)&v2=1$/);
const matchMedia = url.match(/^https:\/\/musescore\.com\/api\/jmuse\?id=(\d+)&index=(\d+)&type=(\w+)$/);

if (matchMediaType) {
if (matchMedia) {
const authHeader = requestHeaders.find(e => e.name === 'Authorization');

const id = matchMedia[1];
const index = matchMedia[2];
const type = matchMedia[3];

if (authHeader) {
const token = authHeader.value;
const tokens = await getTokens();

if (tokens[matchMediaType[1]] !== token) {
tokens[matchMediaType[1]] = token;
await setTokens(tokens);
}
const tab = await updateCurrentTab();
try {
await browser.tabs.sendMessage(tab.id, {scoreData: [`${id}_${type}_${index}`, token]}).catch(() => null);
} catch (e) {}
}
}
},
{urls: ['https://musescore.com/api/jmuse?id=*&index=*&type=*&v2=1']}, ['requestHeaders']
{
urls: ['https://musescore.com/api/jmuse?id=*&index=*&type=*']
}, ['requestHeaders']
);
177 changes: 72 additions & 105 deletions src/content/content.js
Original file line number Diff line number Diff line change
@@ -1,75 +1,21 @@
import browser from 'webextension-polyfill';
import {fetchApiUrl, fetchImageUrl, getTokens, isScoreUrl, setTokens} from '../modules/utils';
import Printer from "pdfmake";

const findTokensInJSFile = async () => {
const sortTokens = async tokens => {
const sortedTokens = {};
const types = ['img', 'mp3', 'midi'];
const allTokens = {};

for (const type of types) {
for (const token of tokens) {
const url = await fetchApiUrl(getScoreId(), type, 0, token);
const getFirstImgUrl = () => {
const pngHref = document.querySelector('link[type="image/png"]')?.href;
const svgHref = document.querySelector('link[type="image/svg+xml"]')?.href;

if (url) {
sortedTokens[type] = token;
break;
}
}
}

return sortedTokens;
};

let authScriptLink = document.querySelector('link[href^="https://musescore.com/static/public/build/musescore_es6/2"]')?.href;

if (authScriptLink) {
await fetch(authScriptLink)
.then(async res => {
if (res.ok) {
const text = await res.text();

const match = [...text.matchAll(/"(\w{40})"/g)];
const tokensFound = [];

if (match) {
for (const token of match) {
tokensFound.push(token[1]);
}
}

const sortedTokens = await sortTokens(tokensFound);
const tokens = await getTokens();

if (Object.entries(sortedTokens).length > 0) {
for (const [type, token] of Object.entries(sortedTokens)) {
tokens[type] = token;
}

await setTokens(tokens);
}
}
})
.catch(() => null);
}
return pngHref || svgHref;
};

const checkTokens = async () => {
const tokens = await getTokens();

for (const token of Object.entries(tokens)) {
if (token[1] === '') {
const url = document.querySelector('meta[property="og:url"]')?.content;

if (isScoreUrl(url)) {
loadIframe();
break;
}
}
browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (typeof request === 'object' && request.scoreData) {
allTokens[request.scoreData[0]] = request.scoreData[1];
return;
}
};

browser.runtime.onMessage.addListener((request, sender, sendResponse) => {
const scoreId = getScoreId();

if (request === 'isScorePage') {
Expand Down Expand Up @@ -160,41 +106,50 @@ const sendMessageToPopup = async type => {
};

const downloadSheetPages = async (scoreId, pagesNumber, round = 1) => {
const images = [];
let unknownPagesNumber = pagesNumber < 1;
if (pagesNumber < 1)
pagesNumber = 200;

if (unknownPagesNumber)
pagesNumber = 100;

for (let i = 0; i < pagesNumber; i++) {
const url = await fetchApiUrl(scoreId, 'img', i);

if (!url) {
if (i === 0 && round < 2) {
loadIframe();
await findTokensInJSFile();
return downloadSheetPages(scoreId, pagesNumber, 2);
}
const targetTokens = [];

await sendMessageToPopup('downloadError');
return;
}
for (let i = 1; i < pagesNumber; i++) {
targetTokens.push(allTokens[`${scoreId}_img_${i}`]);
}

let image = await fetchImageUrl(url);

if (!image) {
if (unknownPagesNumber) {
break;
} else {
await sendMessageToPopup('downloadError');
return;
const imgUrls = await Promise.all([...targetTokens.map((token, i) =>
fetch(
`https://musescore.com/api/jmuse?id=${scoreId}&index=${i + 1}&type=img`,
{headers: {authorization: token}}
)
.then(res => res.json())
.then(res => res.info.url)
)]);

imgUrls.unshift(getFirstImgUrl());

return await Promise.all([...imgUrls.map(url => {
try {
return fetch(url)
.then(async res => {
if (res.ok) {
let data = await res.blob();

if (data.type === 'image/svg+xml') {
return data.text();
} else {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onloadend = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsDataURL(data);
});
}
}
});
} catch (e) {
return null;
}
}

images.push(image);
}

return images;
)]);
};

const generatePdf = async (pages = [], composer, title) => {
Expand All @@ -214,9 +169,9 @@ const generatePdf = async (pages = [], composer, title) => {
if (/^<svg/.test(page)) {
let svg = new DOMParser().parseFromString(page, "image/svg+xml");
let {width, height} = await getImageSize(page);

svg.firstChild.setAttribute('viewBox', `0 0 ${width} ${height}`);

let svgString = new XMLSerializer().serializeToString(svg);

docContent.push({svg: svgString, ...size, alignment: 'center'});
Expand All @@ -225,7 +180,7 @@ const generatePdf = async (pages = [], composer, title) => {
}
}
}

const docDefinition = {
content: docContent,
pageMargins: 0,
Expand All @@ -244,33 +199,45 @@ const generatePdf = async (pages = [], composer, title) => {
const getImageSize = async image => {
if (/^<svg/.test(image)) {
let svg = new DOMParser().parseFromString(image, "image/svg+xml");

const width = Math.round(svg.firstChild.width.baseVal.value * 10) / 10;
const height = Math.round(svg.firstChild.height.baseVal.value * 10) / 10;

return {width, height};
} else {
return new Promise (resolve => {
return new Promise(resolve => {
let i = new Image();
i.onload = () => resolve({width: i.width, height: i.height});
i.src = image;
});
}
};

const fetchApiUrl = async (id, type, index = 0, token) => {
token = allTokens[`${id}_${type}_${index}`];

return fetch(
`https://musescore.com/api/jmuse?id=${id}&index=${index}&type=${type}`,
{headers: {authorization: token}}
)
.then(async res =>
res.ok ? (await res.json()).info.url : null
);
};

const downloadFile = url => {
//window.open(url);
window.location.assign(url);
};

const loadIframe = () => {
const ifr = document.createElement('iframe');

ifr.src = window.location.href + '/piano-tutorial';
ifr.style.width = '1000px';
ifr.style.height = '9000px';
ifr.style.height = '200000px';
ifr.style.position = 'fixed';
document.body.appendChild(ifr);
};

const downloadFile = url => {
//window.open(url);
window.location.assign(url);
};

checkTokens().catch();
loadIframe();
2 changes: 1 addition & 1 deletion src/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"manifest_version": 3,
"name": "Music Score Downloader",
"description": "This extension allows you to download sheets, audio and midi files",
"version": "0.5.0",
"version": "0.5.2",
"icons": {
"16": "icon-16.png",
"32": "icon-32.png",
Expand Down
53 changes: 0 additions & 53 deletions src/modules/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,6 @@ export const messages = {
downloadingUrl: {message: 'Downloading media', loading: true},
};

export const resetPageStorage = async (name, value = {}, type = 'local') => {
await browser.storage[type].set({[name]: value});
};

export const getTokens = async (type = 'local') => {
return (await browser.storage[type].get('tokens')).tokens;
};

export const setTokens = async (tokens, type = 'local') => {
await browser.storage[type].set({tokens});
};

export const updateCurrentTab = async () => {
const [tab] = await browser.tabs.query({active: true, lastFocusedWindow: true});
return tab;
Expand Down Expand Up @@ -89,44 +77,3 @@ export const resetBgColorAnimation = () => {
html.style.setProperty('--color-animation', 'background-migration 3s ease alternate infinite');
}, 10);
};

export const fetchApiUrl = async (id, type, index = 0, token) => {
if (!token)
token = (await getTokens())[type];

return fetch(
`https://musescore.com/api/jmuse?id=${id}&index=${index}&type=${type}&v2=1`,
{headers: {authorization: token}}
)
.then(async res => {
if (res.ok) {
return (await res.json()).info.url;
} else {
return null;
}
});
};

export const fetchImageUrl = async url => {
try {
return await fetch(url)
.then(async res => {
if (res.ok) {
let data = await res.blob();

if (data.type === 'image/svg+xml') {
return data.text();
} else {
return new Promise((resolve, reject) => {
const reader = new FileReader()
reader.onloadend = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsDataURL(data);
});
}
}
});
} catch (e) {
return null;
}
};

0 comments on commit 0ad810a

Please sign in to comment.