diff --git a/CustomApps/lyrics-plus/OptionsMenu.js b/CustomApps/lyrics-plus/OptionsMenu.js index 3bd13c6a9a..409cd7b0fb 100644 --- a/CustomApps/lyrics-plus/OptionsMenu.js +++ b/CustomApps/lyrics-plus/OptionsMenu.js @@ -96,6 +96,30 @@ function getMusixmatchTranslationPrefix() { const TranslationMenu = react.memo(({ friendlyLanguage, hasTranslation, musixmatchLanguages, musixmatchSelectedLanguage }) => { const musixmatchTranslationPrefix = getMusixmatchTranslationPrefix(); + + const [languageMap, setLanguageMap] = react.useState({}); + + react.useEffect(() => { + let cancelled = false; + + if (typeof ProviderMusixmatch !== "undefined" && ProviderMusixmatch && typeof ProviderMusixmatch.getLanguages === "function") { + (async () => { + try { + const languages = await ProviderMusixmatch.getLanguages(); + if (!cancelled) { + setLanguageMap(languages); + } + } catch (error) { + console.error("Failed to fetch Musixmatch languages:", error); + } + })(); + } + + return () => { + cancelled = true; + }; + }, []); + const items = useMemo(() => { let sourceOptions = { none: "None", @@ -126,14 +150,27 @@ const TranslationMenu = react.memo(({ friendlyLanguage, hasTranslation, musixmat } if (availableMusixmatchLanguages.length) { - const musixmatchOptions = availableMusixmatchLanguages.reduce((acc, code) => { + const musixmatchOptionsArray = availableMusixmatchLanguages.map((code) => { let label = ""; try { - label = musixmatchDisplay.of(code) ?? code.toUpperCase(); + if (languageMap && languageMap[code]) { + label = languageMap[code]; + } else { + label = musixmatchDisplay.of(code) ?? code.toUpperCase(); + } } catch (e) { label = code.toUpperCase(); } - acc[`${musixmatchTranslationPrefix}${code}`] = `${label} (Musixmatch)`; + return { + key: `${musixmatchTranslationPrefix}${code}`, + label: `${label} (Musixmatch)`, + }; + }); + + musixmatchOptionsArray.sort((a, b) => a.label.localeCompare(b.label)); + + const musixmatchOptions = musixmatchOptionsArray.reduce((acc, { key, label }) => { + acc[key] = label; return acc; }, {}); sourceOptions = { ...sourceOptions, ...musixmatchOptions }; @@ -225,6 +262,7 @@ const TranslationMenu = react.memo(({ friendlyLanguage, hasTranslation, musixmat Array.isArray(musixmatchLanguages) ? musixmatchLanguages.join(",") : "", musixmatchSelectedLanguage || "", musixmatchTranslationPrefix, + languageMap, ]); useEffect(() => { diff --git a/CustomApps/lyrics-plus/PlaybarButton.js b/CustomApps/lyrics-plus/PlaybarButton.js index c1bbcd4373..034d502198 100644 --- a/CustomApps/lyrics-plus/PlaybarButton.js +++ b/CustomApps/lyrics-plus/PlaybarButton.js @@ -18,7 +18,7 @@ const style = document.createElement("style"); style.innerHTML = ` - .main-nowPlayingBar-lyricsButton { + .main-nowPlayingBar-lyricsButton[data-testid="lyrics-button"] { display: none !important; } li[data-id="/lyrics-plus"] { diff --git a/CustomApps/lyrics-plus/ProviderMusixmatch.js b/CustomApps/lyrics-plus/ProviderMusixmatch.js index b82f844906..98c75d3d26 100644 --- a/CustomApps/lyrics-plus/ProviderMusixmatch.js +++ b/CustomApps/lyrics-plus/ProviderMusixmatch.js @@ -237,5 +237,57 @@ const ProviderMusixmatch = (() => { })); } - return { findLyrics, getKaraoke, getSynced, getUnsynced, getTranslation }; + let languageMap = null; + async function getLanguages() { + if (languageMap) return languageMap; + + try { + const cached = localStorage.getItem("lyrics-plus:musixmatch-languages"); + if (cached) { + const tempMap = JSON.parse(cached); + // Check cache version + if (tempMap.__version === 1) { + delete tempMap.__version; + languageMap = tempMap; + return languageMap; + } + } + } catch (e) { + console.warn("Failed to parse cached languages", e); + } + + const baseURL = "https://apic-desktop.musixmatch.com/ws/1.1/languages.get?app_id=web-desktop-app-v1.0&get_romanized_info=1&"; + + const params = { + usertoken: CONFIG.providers.musixmatch.token, + }; + + const finalURL = + baseURL + + Object.keys(params) + .map((key) => `${key}=${encodeURIComponent(params[key])}`) + .join("&"); + + try { + let body = await Spicetify.CosmosAsync.get(finalURL, null, headers); + if (body?.message?.body?.language_list) { + languageMap = {}; + body.message.body.language_list.forEach((item) => { + const lang = item.language; + if (lang.language_name) { + const name = lang.language_name.charAt(0).toUpperCase() + lang.language_name.slice(1); + if (lang.language_iso_code_1) languageMap[lang.language_iso_code_1] = name; + if (lang.language_iso_code_3) languageMap[lang.language_iso_code_3] = name; + } + }); + localStorage.setItem("lyrics-plus:musixmatch-languages", JSON.stringify({ ...languageMap, __version: 1 })); + return languageMap; + } + } catch (e) { + console.error("Failed to fetch languages", e); + } + return {}; + } + + return { findLyrics, getKaraoke, getSynced, getUnsynced, getTranslation, getLanguages }; })(); diff --git a/CustomApps/lyrics-plus/TabBar.js b/CustomApps/lyrics-plus/TabBar.js index 0f4746e5a6..952df7c9ac 100644 --- a/CustomApps/lyrics-plus/TabBar.js +++ b/CustomApps/lyrics-plus/TabBar.js @@ -93,7 +93,7 @@ const TopBarContent = ({ links, activeLink, lockLink, switchCallback, lockCallba }; const TabBarContext = ({ children }) => { - return reactDOM.createPortal( + return Spicetify.ReactDOM.createPortal( react.createElement( "div", { diff --git a/CustomApps/lyrics-plus/index.js b/CustomApps/lyrics-plus/index.js index d2ff66e312..b5840b33de 100644 --- a/CustomApps/lyrics-plus/index.js +++ b/CustomApps/lyrics-plus/index.js @@ -6,7 +6,6 @@ const react = Spicetify.React; const { useState, useEffect, useCallback, useMemo, useRef } = react; /** @type {import("react").ReactDOM} */ -const reactDOM = Spicetify.ReactDOM; const spotifyVersion = Spicetify.Platform.version; // Define a function called "render" to specify app entry point @@ -1264,8 +1263,8 @@ class LyricsContainer extends react.Component { }) ); - if (this.state.isFullscreen) return reactDOM.createPortal(out, this.fullscreenContainer); - if (fadLyricsContainer) return reactDOM.createPortal(out, fadLyricsContainer); + if (this.state.isFullscreen) return Spicetify.ReactDOM.createPortal(out, this.fullscreenContainer); + if (fadLyricsContainer) return Spicetify.ReactDOM.createPortal(out, fadLyricsContainer); return out; } } diff --git a/CustomApps/reddit/TabBar.js b/CustomApps/reddit/TabBar.js index 7eaf636327..3729899829 100644 --- a/CustomApps/reddit/TabBar.js +++ b/CustomApps/reddit/TabBar.js @@ -76,7 +76,7 @@ const TopBarContent = ({ links, activeLink, switchCallback }) => { }; const TabBarContext = ({ children }) => { - return reactDOM.createPortal( + return Spicetify.ReactDOM.createPortal( react.createElement( "div", { diff --git a/go.mod b/go.mod index bbd85baf27..4664640c72 100644 --- a/go.mod +++ b/go.mod @@ -6,8 +6,8 @@ require ( github.com/go-ini/ini v1.67.0 github.com/mattn/go-colorable v0.1.14 github.com/pterm/pterm v0.12.82 - golang.org/x/net v0.48.0 - golang.org/x/sys v0.39.0 + golang.org/x/net v0.49.0 + golang.org/x/sys v0.40.0 ) require ( @@ -22,6 +22,6 @@ require ( github.com/rivo/uniseg v0.4.7 // indirect github.com/stretchr/testify v1.9.0 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect - golang.org/x/term v0.38.0 // indirect - golang.org/x/text v0.32.0 // indirect + golang.org/x/term v0.39.0 // indirect + golang.org/x/text v0.33.0 // indirect ) diff --git a/go.sum b/go.sum index 48bcfa8c99..b704e55efd 100644 --- a/go.sum +++ b/go.sum @@ -81,8 +81,8 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= -golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/net v0.49.0 h1:eeHFmOGUTtaaPSGNmjBKpbng9MulQsJURQUAfUwY++o= +golang.org/x/net v0.49.0/go.mod h1:/ysNB2EvaqvesRkuLAyjI1ycPZlQHM3q01F02UY/MV8= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -98,22 +98,22 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= -golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.40.0 h1:DBZZqJ2Rkml6QMQsZywtnjnnGvHza6BTfYFWY9kjEWQ= +golang.org/x/sys v0.40.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= -golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= -golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= +golang.org/x/term v0.39.0 h1:RclSuaJf32jOqZz74CkPA9qFuVTX7vhLlpfj/IGWlqY= +golang.org/x/term v0.39.0/go.mod h1:yxzUCTP/U+FzoxfdKmLaA0RV1WgE0VY7hXBwKtY/4ww= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= -golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= diff --git a/src/cmd/restart.go b/src/cmd/restart.go index b55023e355..b04bd34d0e 100644 --- a/src/cmd/restart.go +++ b/src/cmd/restart.go @@ -18,16 +18,16 @@ func SpotifyKill() { exec.Command("taskkill", "/F", "/IM", "spotify.exe").Run() } case "linux": - isRunning := exec.Command("pgrep", "spotify") + isRunning := exec.Command("pgrep", "-x", "spotify") _, err := isRunning.Output() if err == nil { - exec.Command("pkill", "spotify").Run() + exec.Command("pkill", "-x", "spotify").Run() } case "darwin": isRunning := exec.Command("sh", "-c", "ps aux | grep 'Spotify' | grep -v grep") _, err := isRunning.CombinedOutput() if err == nil { - exec.Command("pkill", "Spotify").Run() + exec.Command("pkill", "-x", "Spotify").Run() } } } diff --git a/src/preprocess/preprocess.go b/src/preprocess/preprocess.go index 433d14add1..7703e8fed4 100644 --- a/src/preprocess/preprocess.go +++ b/src/preprocess/preprocess.go @@ -254,8 +254,8 @@ func Start(version string, spotifyBasePath string, extractedAppsPath string, fla } if fileName == "dwp-top-bar.js" || fileName == "dwp-now-playing-bar.js" || fileName == "dwp-home-chips-row.js" { - utils.ReplaceOnce(&content, `(\w+\.pathname)\.startsWith\((\w+)\)`, func(submatches ...string) string { - return fmt.Sprintf("%s === %s", submatches[1], submatches[2]) + utils.ReplaceOnce(&content, `e\.state\.cinemaState`, func(submatches ...string) string { + return "e.state?.cinemaState" }) }