2023-05-28 14:31:49 -07:00
|
|
|
import { useEffect, useRef, useState } from 'react';
|
|
|
|
|
import isElectron from 'is-electron';
|
2023-05-22 17:38:31 -07:00
|
|
|
import { ErrorBoundary } from 'react-error-boundary';
|
|
|
|
|
import { ErrorFallback } from '/@/renderer/features/action-required';
|
2023-06-03 11:04:47 -07:00
|
|
|
import { getServerById, useCurrentSong } from '/@/renderer/store';
|
2023-06-02 23:54:34 -07:00
|
|
|
import { SynchronizedLyrics } from './synchronized-lyrics';
|
2023-05-22 17:38:31 -07:00
|
|
|
import { UnsynchronizedLyrics } from '/@/renderer/features/lyrics/unsynchronized-lyrics';
|
2023-05-28 14:31:49 -07:00
|
|
|
import { LyricLine } from '/@/renderer/features/lyrics/lyric-line';
|
2023-06-02 23:54:34 -07:00
|
|
|
import { Center, Group } from '@mantine/core';
|
|
|
|
|
import { RiInformationFill } from 'react-icons/ri';
|
|
|
|
|
import { TextTitle } from '/@/renderer/components';
|
2023-06-03 00:39:50 -07:00
|
|
|
import { LyricsResponse, SynchronizedLyricsArray } from '/@/renderer/api/types';
|
2023-06-02 23:54:34 -07:00
|
|
|
import { useSongLyrics } from '/@/renderer/features/lyrics/queries/lyric-query';
|
2023-05-22 17:38:31 -07:00
|
|
|
|
2023-05-28 14:31:49 -07:00
|
|
|
const lyrics = isElectron() ? window.electron.lyrics : null;
|
|
|
|
|
|
|
|
|
|
const ipc = isElectron() ? window.electron.ipc : null;
|
2023-05-22 17:38:31 -07:00
|
|
|
|
2023-05-28 14:31:49 -07:00
|
|
|
// use by https://github.com/ustbhuangyi/lyric-parser
|
2023-05-22 17:38:31 -07:00
|
|
|
const timeExp = /\[(\d{2,}):(\d{2})(?:\.(\d{2,3}))?]([^\n]+)\n/g;
|
|
|
|
|
|
|
|
|
|
export const Lyrics = () => {
|
|
|
|
|
const currentSong = useCurrentSong();
|
2023-06-03 07:15:02 -07:00
|
|
|
const currentServer = getServerById(currentSong?.serverId);
|
2023-05-22 17:38:31 -07:00
|
|
|
|
2023-05-28 14:31:49 -07:00
|
|
|
const [override, setOverride] = useState<string | null>(null);
|
|
|
|
|
const [source, setSource] = useState<string | null>(null);
|
2023-06-03 00:39:50 -07:00
|
|
|
const [songLyrics, setSongLyrics] = useState<LyricsResponse | null>(null);
|
2023-05-28 14:31:49 -07:00
|
|
|
|
2023-06-02 23:54:34 -07:00
|
|
|
const remoteLyrics = useSongLyrics({
|
2023-06-03 11:04:47 -07:00
|
|
|
options: { enabled: !!currentSong },
|
2023-06-02 23:54:34 -07:00
|
|
|
query: { songId: currentSong?.id ?? '' },
|
|
|
|
|
serverId: currentServer?.id,
|
|
|
|
|
});
|
|
|
|
|
|
2023-05-28 14:31:49 -07:00
|
|
|
const songRef = useRef<string | null>(null);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
2023-06-03 10:12:46 -07:00
|
|
|
lyrics?.remoteLyricsListener(
|
2023-06-03 07:15:02 -07:00
|
|
|
(_event: any, songName: string, lyricSource: string, lyric: string) => {
|
|
|
|
|
if (songName === songRef.current) {
|
|
|
|
|
setSource(lyricSource);
|
|
|
|
|
setOverride(lyric);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
);
|
2023-05-28 14:31:49 -07:00
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
|
ipc?.removeAllListeners('lyric-get');
|
|
|
|
|
};
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
2023-06-03 07:15:02 -07:00
|
|
|
const hasTaggedLyrics = currentSong && currentSong.lyrics;
|
|
|
|
|
const hasLyricsResponse =
|
|
|
|
|
!remoteLyrics.isLoading && remoteLyrics?.isSuccess && remoteLyrics?.data !== null;
|
|
|
|
|
|
|
|
|
|
if (!hasTaggedLyrics && !hasLyricsResponse) {
|
|
|
|
|
lyrics?.fetchRemoteLyrics(currentSong);
|
2023-05-28 14:31:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
songRef.current = currentSong?.name ?? null;
|
|
|
|
|
|
|
|
|
|
setOverride(null);
|
|
|
|
|
setSource(null);
|
2023-06-03 07:15:02 -07:00
|
|
|
}, [currentSong, remoteLyrics.isLoading, remoteLyrics?.data, remoteLyrics?.isSuccess]);
|
2023-05-28 14:31:49 -07:00
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
let lyrics: string | null = null;
|
|
|
|
|
|
2023-05-22 17:38:31 -07:00
|
|
|
if (currentSong?.lyrics) {
|
2023-05-28 14:31:49 -07:00
|
|
|
lyrics = currentSong.lyrics;
|
|
|
|
|
|
2023-06-03 07:15:02 -07:00
|
|
|
setSource(currentSong?.name ?? 'music server');
|
2023-05-28 14:31:49 -07:00
|
|
|
} else if (override) {
|
|
|
|
|
lyrics = override;
|
2023-06-03 00:39:50 -07:00
|
|
|
} else if (remoteLyrics.data) {
|
2023-06-02 23:54:34 -07:00
|
|
|
setSource(currentServer?.name ?? 'music server');
|
2023-06-03 00:39:50 -07:00
|
|
|
setSongLyrics(remoteLyrics.data);
|
2023-06-02 23:54:34 -07:00
|
|
|
return;
|
2023-05-28 14:31:49 -07:00
|
|
|
}
|
2023-05-22 17:38:31 -07:00
|
|
|
|
2023-05-28 14:31:49 -07:00
|
|
|
if (lyrics) {
|
|
|
|
|
const synchronizedLines = lyrics.matchAll(timeExp);
|
2023-05-22 17:38:31 -07:00
|
|
|
|
|
|
|
|
const synchronizedTimes: SynchronizedLyricsArray = [];
|
|
|
|
|
|
|
|
|
|
for (const line of synchronizedLines) {
|
|
|
|
|
const [, minute, sec, ms, text] = line;
|
|
|
|
|
const minutes = parseInt(minute, 10);
|
|
|
|
|
const seconds = parseInt(sec, 10);
|
|
|
|
|
const milis = ms.length === 3 ? parseInt(ms, 10) : parseInt(ms, 10) * 10;
|
|
|
|
|
|
|
|
|
|
const timeInMilis = (minutes * 60 + seconds) * 1000 + milis;
|
|
|
|
|
synchronizedTimes.push([timeInMilis, text]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (synchronizedTimes.length === 0) {
|
2023-05-28 14:31:49 -07:00
|
|
|
setSongLyrics(lyrics);
|
|
|
|
|
} else {
|
|
|
|
|
setSongLyrics(synchronizedTimes);
|
2023-05-22 17:38:31 -07:00
|
|
|
}
|
2023-05-28 14:31:49 -07:00
|
|
|
} else {
|
|
|
|
|
setSongLyrics(null);
|
2023-05-22 17:38:31 -07:00
|
|
|
}
|
2023-06-03 00:39:50 -07:00
|
|
|
}, [currentServer?.name, currentSong, override, remoteLyrics.data]);
|
2023-05-22 17:38:31 -07:00
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<ErrorBoundary FallbackComponent={ErrorFallback}>
|
2023-06-02 23:54:34 -07:00
|
|
|
{!songLyrics && (
|
|
|
|
|
<Center>
|
|
|
|
|
<Group>
|
|
|
|
|
<RiInformationFill size="2rem" />
|
|
|
|
|
<TextTitle
|
|
|
|
|
order={3}
|
|
|
|
|
weight={700}
|
|
|
|
|
>
|
|
|
|
|
No lyrics found
|
|
|
|
|
</TextTitle>
|
|
|
|
|
</Group>
|
|
|
|
|
</Center>
|
|
|
|
|
)}
|
2023-05-28 14:31:49 -07:00
|
|
|
{source && (
|
|
|
|
|
<LyricLine
|
|
|
|
|
key="provided-by"
|
|
|
|
|
className="credit"
|
|
|
|
|
text={`Provided by: ${source}`}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
2023-06-02 23:54:34 -07:00
|
|
|
{songLyrics &&
|
|
|
|
|
(Array.isArray(songLyrics) ? (
|
|
|
|
|
<SynchronizedLyrics lyrics={songLyrics} />
|
|
|
|
|
) : (
|
|
|
|
|
<UnsynchronizedLyrics lyrics={songLyrics} />
|
|
|
|
|
))}
|
2023-05-22 17:38:31 -07:00
|
|
|
</ErrorBoundary>
|
|
|
|
|
);
|
|
|
|
|
};
|