Fix Lyric Translation Not Resetting (#1208)

* Refactor lyrics translation and index handling

* Add auto translation toggle to lyric settings

* Add enableAutoTranslation setting to lyrics
This commit is contained in:
Xudong Zhou 2025-11-01 08:08:10 +08:00 committed by GitHub
parent d12e4a1635
commit dd34888961
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 51 additions and 18 deletions

View file

@ -507,7 +507,6 @@
"artistBackgroundBlur_description": "adjusts the amount of blur applied to the artist background image",
"artistConfiguration": "album artist page configuration",
"artistConfiguration_description": "configure what items are shown, and in what order, on the album artist page",
"artistConfiguration": "album artist page configuration",
"audioDevice_description": "select the audio device to use for playback (web player only)",
"audioDevice": "audio device",
"audioExclusiveMode_description": "enable exclusive output mode. In this mode, the system is usually locked out, and only mpv will be able to output audio",
@ -560,9 +559,10 @@
"discordServeImage_description": "share cover art for {{discord}} rich presence from server itself, only available for Jellyfin and Navidrome. {{discord}} uses a bot to fetch images, so your server must be reachable from the public internet",
"discordUpdateInterval": "{{discord}} rich presence update interval",
"discordUpdateInterval_description": "the time in seconds between each update (minimum 15 seconds)",
"discordUpdateInterval": "{{discord}} rich presence update interval",
"doubleClickBehavior_description": "if true, all matching tracks in a track search will be queued. otherwise, only the clicked one will be queued",
"doubleClickBehavior": "queue all searched tracks when double clicking",
"enableAutoTranslation_description": "enable translation automatically when lyrics are loaded",
"enableAutoTranslation": "enable auto translation",
"enableRemote_description": "enables the remote control server to allow other devices to control the application",
"enableRemote": "enable remote control server",
"exitToTray_description": "exit the application to the system tray",

View file

@ -32,8 +32,12 @@ import { FullLyricsMetadata, LyricSource, LyricsOverride } from '/@/shared/types
export const Lyrics = () => {
const currentSong = useCurrentSong();
const { translationApiKey, translationApiProvider, translationTargetLanguage } =
useLyricsSettings();
const {
enableAutoTranslation,
translationApiKey,
translationApiProvider,
translationTargetLanguage,
} = useLyricsSettings();
const { t } = useTranslation();
const [index, setIndex] = useState(0);
const [translatedLyrics, setTranslatedLyrics] = useState<null | string>(null);
@ -52,7 +56,7 @@ export const Lyrics = () => {
const [lyrics, synced] = useMemo(() => {
if (Array.isArray(data)) {
if (data.length > 0) {
const selectedLyric = data[Math.min(index, data.length)];
const selectedLyric = data[Math.min(index, data.length - 1)];
return [selectedLyric, selectedLyric.synced];
}
} else if (data?.lyrics) {
@ -89,11 +93,7 @@ export const Lyrics = () => {
);
}, [currentSong?.id, currentSong?.serverId]);
const handleOnTranslateLyric = useCallback(async () => {
if (translatedLyrics) {
setShowTranslation(!showTranslation);
return;
}
const fetchTranslation = useCallback(async () => {
if (!lyrics) return;
const originalLyrics = Array.isArray(lyrics.lyrics)
? lyrics.lyrics.map(([, line]) => line).join('\n')
@ -106,14 +106,15 @@ export const Lyrics = () => {
);
setTranslatedLyrics(TranslatedText);
setShowTranslation(true);
}, [
translatedLyrics,
lyrics,
translationApiKey,
translationApiProvider,
translationTargetLanguage,
showTranslation,
]);
}, [lyrics, translationApiKey, translationApiProvider, translationTargetLanguage]);
const handleOnTranslateLyric = useCallback(async () => {
if (translatedLyrics) {
setShowTranslation(!showTranslation);
return;
}
await fetchTranslation();
}, [translatedLyrics, showTranslation, fetchTranslation]);
const { isInitialLoading: isOverrideLoading } = useSongLyricsByRemoteId({
options: {
@ -133,6 +134,8 @@ export const Lyrics = () => {
() => {
setOverride(undefined);
setIndex(0);
setShowTranslation(false);
setTranslatedLyrics(null);
},
{ equalityFn: (a, b) => a?.id === b?.id },
);
@ -142,6 +145,12 @@ export const Lyrics = () => {
};
}, []);
useEffect(() => {
if (lyrics && !translatedLyrics && enableAutoTranslation) {
fetchTranslation();
}
}, [lyrics, translatedLyrics, enableAutoTranslation, fetchTranslation]);
const languages = useMemo(() => {
if (Array.isArray(data)) {
return data.map((lyric, idx) => ({ label: lyric.lang, value: idx.toString() }));

View file

@ -214,6 +214,28 @@ export const LyricSettings = () => {
isHidden: !isElectron(),
title: t('setting.translationApiKey', { postProcess: 'sentenceCase' }),
},
{
control: (
<Switch
aria-label="Enable auto translation"
defaultChecked={settings.enableAutoTranslation}
onChange={(e) => {
setSettings({
lyrics: {
...settings,
enableAutoTranslation: e.currentTarget.checked,
},
});
}}
/>
),
description: t('setting.enableAutoTranslation', {
context: 'description',
postProcess: 'sentenceCase',
}),
isHidden: !isElectron(),
title: t('setting.enableAutoTranslation', { postProcess: 'sentenceCase' }),
},
];
return <SettingsSection divider={false} options={lyricOptions} />;

View file

@ -225,6 +225,7 @@ const HotkeysSettingsSchema = z.object({
const LyricsSettingsSchema = z.object({
alignment: z.enum(['center', 'left', 'right']),
delayMs: z.number(),
enableAutoTranslation: z.boolean(),
enableNeteaseTranslation: z.boolean(),
fetch: z.boolean(),
follow: z.boolean(),
@ -612,6 +613,7 @@ const initialState: SettingsState = {
lyrics: {
alignment: 'center',
delayMs: 0,
enableAutoTranslation: false,
enableNeteaseTranslation: false,
fetch: false,
follow: true,