191 lines
4.9 KiB
JavaScript
191 lines
4.9 KiB
JavaScript
const ProviderMusixmatch = (() => {
|
|
const headers = {
|
|
authority: "apic-desktop.musixmatch.com",
|
|
cookie: "x-mxm-token-guid="
|
|
};
|
|
|
|
async function findLyrics(info) {
|
|
const baseURL =
|
|
"https://apic-desktop.musixmatch.com/ws/1.1/macro.subtitles.get?format=json&namespace=lyrics_richsynched&subtitle_format=mxm&app_id=web-desktop-app-v1.0&";
|
|
|
|
const durr = info.duration / 1000;
|
|
|
|
const params = {
|
|
q_album: info.album,
|
|
q_artist: info.artist,
|
|
q_artists: info.artist,
|
|
q_track: info.title,
|
|
track_spotify_id: info.uri,
|
|
q_duration: durr,
|
|
f_subtitle_length: Math.floor(durr),
|
|
usertoken: CONFIG.providers.musixmatch.token
|
|
};
|
|
|
|
const finalURL =
|
|
baseURL +
|
|
Object.keys(params)
|
|
.map(key => `${key}=${encodeURIComponent(params[key])}`)
|
|
.join("&");
|
|
|
|
let body = await Spicetify.CosmosAsync.get(finalURL, null, headers);
|
|
|
|
body = body.message.body.macro_calls;
|
|
|
|
if (body["matcher.track.get"].message.header.status_code !== 200) {
|
|
return {
|
|
error: `Requested error: ${body["matcher.track.get"].message.header.mode}`,
|
|
uri: info.uri
|
|
};
|
|
}
|
|
if (body["track.lyrics.get"]?.message?.body?.lyrics?.restricted) {
|
|
return {
|
|
error: "Unfortunately we're not authorized to show these lyrics.",
|
|
uri: info.uri
|
|
};
|
|
}
|
|
|
|
return body;
|
|
}
|
|
|
|
async function getKaraoke(body) {
|
|
const meta = body?.["matcher.track.get"]?.message?.body;
|
|
if (!meta) {
|
|
return null;
|
|
}
|
|
|
|
if (!meta.track.has_richsync || meta.track.instrumental) {
|
|
return null;
|
|
}
|
|
|
|
const baseURL = "https://apic-desktop.musixmatch.com/ws/1.1/track.richsync.get?format=json&subtitle_format=mxm&app_id=web-desktop-app-v1.0&";
|
|
|
|
const params = {
|
|
f_subtitle_length: meta.track.track_length,
|
|
q_duration: meta.track.track_length,
|
|
commontrack_id: meta.track.commontrack_id,
|
|
usertoken: CONFIG.providers.musixmatch.token
|
|
};
|
|
|
|
const finalURL =
|
|
baseURL +
|
|
Object.keys(params)
|
|
.map(key => `${key}=${encodeURIComponent(params[key])}`)
|
|
.join("&");
|
|
|
|
let result = await Spicetify.CosmosAsync.get(finalURL, null, headers);
|
|
|
|
if (result.message.header.status_code !== 200) {
|
|
return null;
|
|
}
|
|
|
|
result = result.message.body;
|
|
|
|
const parsedKaraoke = JSON.parse(result.richsync.richsync_body).map(line => {
|
|
const startTime = line.ts * 1000;
|
|
const endTime = line.te * 1000;
|
|
const words = line.l;
|
|
|
|
const text = words.map((word, index, words) => {
|
|
const wordText = word.c;
|
|
const wordStartTime = word.o * 1000;
|
|
const nextWordStartTime = words[index + 1]?.o * 1000;
|
|
|
|
const time = !Number.isNaN(nextWordStartTime) ? nextWordStartTime - wordStartTime : endTime - (wordStartTime + startTime);
|
|
|
|
return {
|
|
word: wordText,
|
|
time
|
|
};
|
|
});
|
|
return {
|
|
startTime,
|
|
text
|
|
};
|
|
});
|
|
|
|
return parsedKaraoke;
|
|
}
|
|
|
|
function getSynced(body) {
|
|
const meta = body?.["matcher.track.get"]?.message?.body;
|
|
if (!meta) {
|
|
return null;
|
|
}
|
|
|
|
const hasSynced = meta?.track?.has_subtitles;
|
|
|
|
const isInstrumental = meta?.track?.instrumental;
|
|
|
|
if (isInstrumental) {
|
|
return [{ text: "♪ Instrumental ♪", startTime: "0000" }];
|
|
}
|
|
if (hasSynced) {
|
|
const subtitle = body["track.subtitles.get"]?.message?.body?.subtitle_list?.[0]?.subtitle;
|
|
if (!subtitle) {
|
|
return null;
|
|
}
|
|
|
|
return JSON.parse(subtitle.subtitle_body).map(line => ({
|
|
text: line.text || "♪",
|
|
startTime: line.time.total * 1000
|
|
}));
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
function getUnsynced(body) {
|
|
const meta = body?.["matcher.track.get"]?.message?.body;
|
|
if (!meta) {
|
|
return null;
|
|
}
|
|
|
|
const hasUnSynced = meta.track.has_lyrics || meta.track.has_lyrics_crowd;
|
|
|
|
const isInstrumental = meta?.track?.instrumental;
|
|
|
|
if (isInstrumental) {
|
|
return [{ text: "♪ Instrumental ♪" }];
|
|
}
|
|
if (hasUnSynced) {
|
|
const lyrics = body["track.lyrics.get"]?.message?.body?.lyrics?.lyrics_body;
|
|
if (!lyrics) {
|
|
return null;
|
|
}
|
|
return lyrics.split("\n").map(text => ({ text }));
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
async function getTranslation(body) {
|
|
const track_id = body?.["matcher.track.get"]?.message?.body?.track?.track_id;
|
|
if (!track_id) return null;
|
|
|
|
const baseURL =
|
|
"https://apic-desktop.musixmatch.com/ws/1.1/crowd.track.translations.get?translation_fields_set=minimal&selected_language=en&comment_format=text&format=json&app_id=web-desktop-app-v1.0&";
|
|
|
|
const params = {
|
|
track_id,
|
|
usertoken: CONFIG.providers.musixmatch.token
|
|
};
|
|
|
|
const finalURL =
|
|
baseURL +
|
|
Object.keys(params)
|
|
.map(key => `${key}=${encodeURIComponent(params[key])}`)
|
|
.join("&");
|
|
|
|
let result = await Spicetify.CosmosAsync.get(finalURL, null, headers);
|
|
|
|
if (result.message.header.status_code !== 200) return null;
|
|
|
|
result = result.message.body;
|
|
|
|
if (!result.translations_list?.length) return null;
|
|
|
|
return result.translations_list.map(({ translation }) => ({ translation: translation.description, matchedLine: translation.matched_line }));
|
|
}
|
|
|
|
return { findLyrics, getKaraoke, getSynced, getUnsynced, getTranslation };
|
|
})();
|