From f9d9205d788cc64506bf5ecd0b2ca1791aa6e624 Mon Sep 17 00:00:00 2001 From: Volodymyr Tymchenko Date: Thu, 7 May 2026 10:13:02 +0300 Subject: [PATCH 1/2] Make YTM proxy optional in synced-lyrics-plugin --- src/i18n/resources/en.json | 4 ++++ src/plugins/synced-lyrics/index.ts | 1 + src/plugins/synced-lyrics/menu.ts | 15 ++++++++++++ .../synced-lyrics/providers/YTMusic.ts | 24 ++++++++++++++++++- src/plugins/synced-lyrics/types.ts | 1 + 5 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/i18n/resources/en.json b/src/i18n/resources/en.json index 763e854b82..a2aa2f9236 100644 --- a/src/i18n/resources/en.json +++ b/src/i18n/resources/en.json @@ -892,6 +892,10 @@ "label": "Show time codes", "tooltip": "Show the time codes next to the lyrics" }, + "use-ytm-lyrics-without-proxy": { + "label": "Use YTM lyrics with no proxy", + "tooltip": "Skip the YTM browse proxy and call YouTube Music directly using the app's authenticated session. Useful if you trust your network/region to allow direct browse calls." + }, "convert-chinese-character": { "label": "Convert Chinese character", "submenu": { diff --git a/src/plugins/synced-lyrics/index.ts b/src/plugins/synced-lyrics/index.ts index 533f05bfb1..ce3a953f49 100644 --- a/src/plugins/synced-lyrics/index.ts +++ b/src/plugins/synced-lyrics/index.ts @@ -22,6 +22,7 @@ export default createPlugin({ defaultTextString: '♪', lineEffect: 'fancy', romanization: true, + useYTMLyricsWithoutProxy: false, } satisfies SyncedLyricsPluginConfig as SyncedLyricsPluginConfig, menu, diff --git a/src/plugins/synced-lyrics/menu.ts b/src/plugins/synced-lyrics/menu.ts index 9f4fcc6d93..d0f61b4d31 100644 --- a/src/plugins/synced-lyrics/menu.ts +++ b/src/plugins/synced-lyrics/menu.ts @@ -233,5 +233,20 @@ export const menu = async ( }); }, }, + { + label: t( + 'plugins.synced-lyrics.menu.use-ytm-lyrics-without-proxy.label', + ), + toolTip: t( + 'plugins.synced-lyrics.menu.use-ytm-lyrics-without-proxy.tooltip', + ), + type: 'checkbox', + checked: config.useYTMLyricsWithoutProxy, + click(item) { + ctx.setConfig({ + useYTMLyricsWithoutProxy: item.checked, + }); + }, + }, ]; }; diff --git a/src/plugins/synced-lyrics/providers/YTMusic.ts b/src/plugins/synced-lyrics/providers/YTMusic.ts index 1888724fd8..0cc1ff7ed9 100644 --- a/src/plugins/synced-lyrics/providers/YTMusic.ts +++ b/src/plugins/synced-lyrics/providers/YTMusic.ts @@ -1,3 +1,5 @@ +import { config } from '../renderer/renderer'; + import type { LyricProvider, LyricResult, SearchSongInfo } from '../types'; import type { MusicPlayerAppElement } from '@/types/music-player-app-element'; @@ -122,7 +124,11 @@ export class YTMusic implements LyricProvider { }); } - private fetchBrowse(browseId: string) { + private fetchBrowse(browseId: string): Promise { + if (config()?.useYTMLyricsWithoutProxy) { + return this.fetchBrowseDirect(browseId); + } + return fetch(this.PROXIED_ENDPOINT + 'browse?prettyPrint=false', { headers, method: 'POST', @@ -132,6 +138,22 @@ export class YTMusic implements LyricProvider { }), }).then((res) => res.json()) as Promise; } + + // Calls YouTube Music's browse endpoint directly via the app's authenticated + // network manager, which injects the visitor/auth tokens that the request + // would otherwise be missing when called from regions where the unauthenticated + // call is geo-restricted. + private async fetchBrowseDirect(browseId: string): Promise { + const app = document.querySelector('ytmusic-app'); + if (!app) { + throw new Error('ytmusic-app element not found'); + } + + return await app.networkManager.fetch( + '/browse?prettyPrint=false', + { browseId }, + ); + } } interface NextData { diff --git a/src/plugins/synced-lyrics/types.ts b/src/plugins/synced-lyrics/types.ts index a429364406..59982cceed 100644 --- a/src/plugins/synced-lyrics/types.ts +++ b/src/plugins/synced-lyrics/types.ts @@ -10,6 +10,7 @@ export type SyncedLyricsPluginConfig = { showLyricsEvenIfInexact: boolean; lineEffect: LineEffect; romanization: boolean; + useYTMLyricsWithoutProxy: boolean; convertChineseCharacter?: | 'simplifiedToTraditional' | 'traditionalToSimplified' From 5a1bc9d75d8552e7e6f1d2f3428af12a20fe5acc Mon Sep 17 00:00:00 2001 From: Volodymyr Tymchenko Date: Thu, 7 May 2026 10:39:03 +0300 Subject: [PATCH 2/2] PR comments fix --- src/plugins/synced-lyrics/providers/YTMusic.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/plugins/synced-lyrics/providers/YTMusic.ts b/src/plugins/synced-lyrics/providers/YTMusic.ts index 0cc1ff7ed9..6ab21652a2 100644 --- a/src/plugins/synced-lyrics/providers/YTMusic.ts +++ b/src/plugins/synced-lyrics/providers/YTMusic.ts @@ -41,7 +41,9 @@ export class YTMusic implements LyricProvider { const { browseId } = lyricsTab?.tabRenderer?.endpoint?.browseEndpoint ?? {}; if (!browseId) return null; - const { contents } = await this.fetchBrowse(browseId); + const browseData = await this.fetchBrowse(browseId); + if (!browseData) return null; + const { contents } = browseData; if (!contents) return null; /* @@ -124,7 +126,7 @@ export class YTMusic implements LyricProvider { }); } - private fetchBrowse(browseId: string): Promise { + private fetchBrowse(browseId: string): Promise { if (config()?.useYTMLyricsWithoutProxy) { return this.fetchBrowseDirect(browseId); } @@ -143,10 +145,10 @@ export class YTMusic implements LyricProvider { // network manager, which injects the visitor/auth tokens that the request // would otherwise be missing when called from regions where the unauthenticated // call is geo-restricted. - private async fetchBrowseDirect(browseId: string): Promise { + private async fetchBrowseDirect(browseId: string): Promise { const app = document.querySelector('ytmusic-app'); if (!app) { - throw new Error('ytmusic-app element not found'); + return null; } return await app.networkManager.fetch(