mirror of
https://github.com/antebudimir/feishin.git
synced 2026-01-02 19:01:40 +00:00
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:
parent
d12e4a1635
commit
dd34888961
4 changed files with 51 additions and 18 deletions
|
|
@ -507,7 +507,6 @@
|
||||||
"artistBackgroundBlur_description": "adjusts the amount of blur applied to the artist background image",
|
"artistBackgroundBlur_description": "adjusts the amount of blur applied to the artist background image",
|
||||||
"artistConfiguration": "album artist page configuration",
|
"artistConfiguration": "album artist page configuration",
|
||||||
"artistConfiguration_description": "configure what items are shown, and in what order, on the album artist page",
|
"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_description": "select the audio device to use for playback (web player only)",
|
||||||
"audioDevice": "audio device",
|
"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",
|
"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",
|
"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": "{{discord}} rich presence update interval",
|
||||||
"discordUpdateInterval_description": "the time in seconds between each update (minimum 15 seconds)",
|
"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_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",
|
"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_description": "enables the remote control server to allow other devices to control the application",
|
||||||
"enableRemote": "enable remote control server",
|
"enableRemote": "enable remote control server",
|
||||||
"exitToTray_description": "exit the application to the system tray",
|
"exitToTray_description": "exit the application to the system tray",
|
||||||
|
|
|
||||||
|
|
@ -32,8 +32,12 @@ import { FullLyricsMetadata, LyricSource, LyricsOverride } from '/@/shared/types
|
||||||
|
|
||||||
export const Lyrics = () => {
|
export const Lyrics = () => {
|
||||||
const currentSong = useCurrentSong();
|
const currentSong = useCurrentSong();
|
||||||
const { translationApiKey, translationApiProvider, translationTargetLanguage } =
|
const {
|
||||||
useLyricsSettings();
|
enableAutoTranslation,
|
||||||
|
translationApiKey,
|
||||||
|
translationApiProvider,
|
||||||
|
translationTargetLanguage,
|
||||||
|
} = useLyricsSettings();
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [index, setIndex] = useState(0);
|
const [index, setIndex] = useState(0);
|
||||||
const [translatedLyrics, setTranslatedLyrics] = useState<null | string>(null);
|
const [translatedLyrics, setTranslatedLyrics] = useState<null | string>(null);
|
||||||
|
|
@ -52,7 +56,7 @@ export const Lyrics = () => {
|
||||||
const [lyrics, synced] = useMemo(() => {
|
const [lyrics, synced] = useMemo(() => {
|
||||||
if (Array.isArray(data)) {
|
if (Array.isArray(data)) {
|
||||||
if (data.length > 0) {
|
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];
|
return [selectedLyric, selectedLyric.synced];
|
||||||
}
|
}
|
||||||
} else if (data?.lyrics) {
|
} else if (data?.lyrics) {
|
||||||
|
|
@ -89,11 +93,7 @@ export const Lyrics = () => {
|
||||||
);
|
);
|
||||||
}, [currentSong?.id, currentSong?.serverId]);
|
}, [currentSong?.id, currentSong?.serverId]);
|
||||||
|
|
||||||
const handleOnTranslateLyric = useCallback(async () => {
|
const fetchTranslation = useCallback(async () => {
|
||||||
if (translatedLyrics) {
|
|
||||||
setShowTranslation(!showTranslation);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!lyrics) return;
|
if (!lyrics) return;
|
||||||
const originalLyrics = Array.isArray(lyrics.lyrics)
|
const originalLyrics = Array.isArray(lyrics.lyrics)
|
||||||
? lyrics.lyrics.map(([, line]) => line).join('\n')
|
? lyrics.lyrics.map(([, line]) => line).join('\n')
|
||||||
|
|
@ -106,14 +106,15 @@ export const Lyrics = () => {
|
||||||
);
|
);
|
||||||
setTranslatedLyrics(TranslatedText);
|
setTranslatedLyrics(TranslatedText);
|
||||||
setShowTranslation(true);
|
setShowTranslation(true);
|
||||||
}, [
|
}, [lyrics, translationApiKey, translationApiProvider, translationTargetLanguage]);
|
||||||
translatedLyrics,
|
|
||||||
lyrics,
|
const handleOnTranslateLyric = useCallback(async () => {
|
||||||
translationApiKey,
|
if (translatedLyrics) {
|
||||||
translationApiProvider,
|
setShowTranslation(!showTranslation);
|
||||||
translationTargetLanguage,
|
return;
|
||||||
showTranslation,
|
}
|
||||||
]);
|
await fetchTranslation();
|
||||||
|
}, [translatedLyrics, showTranslation, fetchTranslation]);
|
||||||
|
|
||||||
const { isInitialLoading: isOverrideLoading } = useSongLyricsByRemoteId({
|
const { isInitialLoading: isOverrideLoading } = useSongLyricsByRemoteId({
|
||||||
options: {
|
options: {
|
||||||
|
|
@ -133,6 +134,8 @@ export const Lyrics = () => {
|
||||||
() => {
|
() => {
|
||||||
setOverride(undefined);
|
setOverride(undefined);
|
||||||
setIndex(0);
|
setIndex(0);
|
||||||
|
setShowTranslation(false);
|
||||||
|
setTranslatedLyrics(null);
|
||||||
},
|
},
|
||||||
{ equalityFn: (a, b) => a?.id === b?.id },
|
{ 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(() => {
|
const languages = useMemo(() => {
|
||||||
if (Array.isArray(data)) {
|
if (Array.isArray(data)) {
|
||||||
return data.map((lyric, idx) => ({ label: lyric.lang, value: idx.toString() }));
|
return data.map((lyric, idx) => ({ label: lyric.lang, value: idx.toString() }));
|
||||||
|
|
|
||||||
|
|
@ -214,6 +214,28 @@ export const LyricSettings = () => {
|
||||||
isHidden: !isElectron(),
|
isHidden: !isElectron(),
|
||||||
title: t('setting.translationApiKey', { postProcess: 'sentenceCase' }),
|
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} />;
|
return <SettingsSection divider={false} options={lyricOptions} />;
|
||||||
|
|
|
||||||
|
|
@ -225,6 +225,7 @@ const HotkeysSettingsSchema = z.object({
|
||||||
const LyricsSettingsSchema = z.object({
|
const LyricsSettingsSchema = z.object({
|
||||||
alignment: z.enum(['center', 'left', 'right']),
|
alignment: z.enum(['center', 'left', 'right']),
|
||||||
delayMs: z.number(),
|
delayMs: z.number(),
|
||||||
|
enableAutoTranslation: z.boolean(),
|
||||||
enableNeteaseTranslation: z.boolean(),
|
enableNeteaseTranslation: z.boolean(),
|
||||||
fetch: z.boolean(),
|
fetch: z.boolean(),
|
||||||
follow: z.boolean(),
|
follow: z.boolean(),
|
||||||
|
|
@ -612,6 +613,7 @@ const initialState: SettingsState = {
|
||||||
lyrics: {
|
lyrics: {
|
||||||
alignment: 'center',
|
alignment: 'center',
|
||||||
delayMs: 0,
|
delayMs: 0,
|
||||||
|
enableAutoTranslation: false,
|
||||||
enableNeteaseTranslation: false,
|
enableNeteaseTranslation: false,
|
||||||
fetch: false,
|
fetch: false,
|
||||||
follow: true,
|
follow: true,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue