add option to set local lyric priority

This commit is contained in:
jeffvli 2025-06-25 21:25:29 -07:00
parent 64866c59bd
commit 620b810191
4 changed files with 47 additions and 8 deletions

View file

@ -536,6 +536,8 @@
"floatingQueueArea_description": "display a hover icon on the right side of the screen to view the play queue", "floatingQueueArea_description": "display a hover icon on the right side of the screen to view the play queue",
"followLyric": "follow current lyric", "followLyric": "follow current lyric",
"followLyric_description": "scroll the lyric to the current playing position", "followLyric_description": "scroll the lyric to the current playing position",
"preferLocalLyrics": "prefer local lyrics",
"preferLocalLyrics_description": "prefer local lyrics over remote lyrics when available",
"font": "font", "font": "font",
"font_description": "sets the font to use for the application", "font_description": "sets the font to use for the application",
"fontType": "font type", "fontType": "font type",

View file

@ -86,7 +86,7 @@ export const useSongLyricsBySong = (
song: QueueSong | undefined, song: QueueSong | undefined,
): UseQueryResult<FullLyricsMetadata | StructuredLyric[]> => { ): UseQueryResult<FullLyricsMetadata | StructuredLyric[]> => {
const { query } = args; const { query } = args;
const { fetch } = useLyricsSettings(); const { fetch, preferLocalLyrics } = useLyricsSettings();
const server = getServerById(song?.serverId); const server = getServerById(song?.serverId);
return useQuery({ return useQuery({
@ -97,6 +97,9 @@ export const useSongLyricsBySong = (
if (!server) throw new Error('Server not found'); if (!server) throw new Error('Server not found');
if (!song) return null; if (!song) return null;
let localLyrics: FullLyricsMetadata | null | StructuredLyric[] = null;
let remoteLyrics: FullLyricsMetadata | null | StructuredLyric[] = null;
if (hasFeature(server, ServerFeature.LYRICS_MULTIPLE_STRUCTURED)) { if (hasFeature(server, ServerFeature.LYRICS_MULTIPLE_STRUCTURED)) {
const subsonicLyrics = await api.controller const subsonicLyrics = await api.controller
.getStructuredLyrics({ .getStructuredLyrics({
@ -106,7 +109,7 @@ export const useSongLyricsBySong = (
.catch(console.error); .catch(console.error);
if (subsonicLyrics?.length) { if (subsonicLyrics?.length) {
return subsonicLyrics; localLyrics = subsonicLyrics;
} }
} else if (hasFeature(server, ServerFeature.LYRICS_SINGLE_STRUCTURED)) { } else if (hasFeature(server, ServerFeature.LYRICS_SINGLE_STRUCTURED)) {
const jfLyrics = await api.controller const jfLyrics = await api.controller
@ -117,7 +120,7 @@ export const useSongLyricsBySong = (
.catch((err) => console.log(err)); .catch((err) => console.log(err));
if (jfLyrics) { if (jfLyrics) {
return { localLyrics = {
artist: song.artists?.[0]?.name, artist: song.artists?.[0]?.name,
lyrics: jfLyrics, lyrics: jfLyrics,
name: song.name, name: song.name,
@ -126,7 +129,7 @@ export const useSongLyricsBySong = (
}; };
} }
} else if (song.lyrics) { } else if (song.lyrics) {
return { localLyrics = {
artist: song.artists?.[0]?.name, artist: song.artists?.[0]?.name,
lyrics: formatLyrics(song.lyrics), lyrics: formatLyrics(song.lyrics),
name: song.name, name: song.name,
@ -135,12 +138,16 @@ export const useSongLyricsBySong = (
}; };
} }
if (preferLocalLyrics && localLyrics) {
return localLyrics;
}
if (fetch) { if (fetch) {
const remoteLyricsResult: InternetProviderLyricResponse | null = const remoteLyricsResult: InternetProviderLyricResponse | null =
await lyricsIpc?.getRemoteLyricsBySong(song); await lyricsIpc?.getRemoteLyricsBySong(song);
if (remoteLyricsResult) { if (remoteLyricsResult) {
return { remoteLyrics = {
...remoteLyricsResult, ...remoteLyricsResult,
lyrics: formatLyrics(remoteLyricsResult.lyrics), lyrics: formatLyrics(remoteLyricsResult.lyrics),
remote: true, remote: true,
@ -148,6 +155,14 @@ export const useSongLyricsBySong = (
} }
} }
if (remoteLyrics) {
return remoteLyrics;
}
if (localLyrics) {
return localLyrics;
}
return null; return null;
}, },
queryKey: queryKeys.songs.lyrics(server?.id || '', query), queryKey: queryKeys.songs.lyrics(server?.id || '', query),
@ -183,9 +198,7 @@ export const useSongLyricsByRemoteId = (
); );
}, },
queryFn: async () => { queryFn: async () => {
const remoteLyricsResult = await lyricsIpc?.getRemoteLyricsByRemoteId( const remoteLyricsResult = await lyricsIpc?.getRemoteLyricsByRemoteId(query as any);
query as LyricGetQuery,
);
if (remoteLyricsResult) { if (remoteLyricsResult) {
return formatLyrics(remoteLyricsResult); return formatLyrics(remoteLyricsResult);

View file

@ -43,6 +43,28 @@ export const LyricSettings = () => {
}), }),
title: t('setting.followLyric', { postProcess: 'sentenceCase' }), title: t('setting.followLyric', { postProcess: 'sentenceCase' }),
}, },
{
control: (
<Switch
aria-label="Prefer local lyrics"
defaultChecked={settings.preferLocalLyrics}
onChange={(e) => {
setSettings({
lyrics: {
...settings,
preferLocalLyrics: e.currentTarget.checked,
},
});
}}
/>
),
description: t('setting.preferLocalLyrics', {
context: 'description',
postProcess: 'sentenceCase',
}),
isHidden: !isElectron(),
title: t('setting.preferLocalLyrics', { postProcess: 'sentenceCase' }),
},
{ {
control: ( control: (
<Switch <Switch

View file

@ -266,6 +266,7 @@ export interface SettingsState {
fontSizeUnsync: number; fontSizeUnsync: number;
gap: number; gap: number;
gapUnsync: number; gapUnsync: number;
preferLocalLyrics: boolean;
showMatch: boolean; showMatch: boolean;
showProvider: boolean; showProvider: boolean;
sources: LyricSource[]; sources: LyricSource[];
@ -448,6 +449,7 @@ const initialState: SettingsState = {
fontSizeUnsync: 24, fontSizeUnsync: 24,
gap: 24, gap: 24,
gapUnsync: 24, gapUnsync: 24,
preferLocalLyrics: true,
showMatch: true, showMatch: true,
showProvider: true, showProvider: true,
sources: [LyricSource.NETEASE, LyricSource.LRCLIB], sources: [LyricSource.NETEASE, LyricSource.LRCLIB],