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-05-28 14:31:49 -07:00
|
|
|
import { useCurrentServer, useCurrentSong } from '/@/renderer/store';
|
2023-05-22 17:38:31 -07:00
|
|
|
import { SynchronizedLyricsArray, SynchronizedLyrics } from './synchronized-lyrics';
|
|
|
|
|
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-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 = () => {
|
2023-05-28 14:31:49 -07:00
|
|
|
const currentServer = useCurrentServer();
|
2023-05-22 17:38:31 -07:00
|
|
|
const currentSong = useCurrentSong();
|
|
|
|
|
|
2023-05-28 14:31:49 -07:00
|
|
|
const [override, setOverride] = useState<string | null>(null);
|
|
|
|
|
const [source, setSource] = useState<string | null>(null);
|
|
|
|
|
const [songLyrics, setSongLyrics] = useState<SynchronizedLyricsArray | string | null>(null);
|
|
|
|
|
|
|
|
|
|
const songRef = useRef<string | null>(null);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
lyrics?.getLyrics((_event: any, songName: string, lyricSource: string, lyric: string) => {
|
|
|
|
|
if (songName === songRef.current) {
|
|
|
|
|
setSource(lyricSource);
|
|
|
|
|
setOverride(lyric);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
return () => {
|
|
|
|
|
ipc?.removeAllListeners('lyric-get');
|
|
|
|
|
};
|
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
if (currentSong && !currentSong.lyrics) {
|
|
|
|
|
lyrics?.fetchLyrics(currentSong);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
songRef.current = currentSong?.name ?? null;
|
|
|
|
|
|
|
|
|
|
setOverride(null);
|
|
|
|
|
setSource(null);
|
|
|
|
|
}, [currentSong]);
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
setSource(currentServer?.name ?? 'music server');
|
|
|
|
|
} else if (override) {
|
|
|
|
|
lyrics = override;
|
|
|
|
|
}
|
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-05-28 14:31:49 -07:00
|
|
|
}, [currentServer?.name, currentSong, override]);
|
2023-05-22 17:38:31 -07:00
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<ErrorBoundary FallbackComponent={ErrorFallback}>
|
2023-05-28 14:31:49 -07:00
|
|
|
{songLyrics &&
|
|
|
|
|
(Array.isArray(songLyrics) ? (
|
|
|
|
|
<SynchronizedLyrics lyrics={songLyrics} />
|
2023-05-22 17:38:31 -07:00
|
|
|
) : (
|
2023-05-28 14:31:49 -07:00
|
|
|
<UnsynchronizedLyrics lyrics={songLyrics} />
|
2023-05-22 17:38:31 -07:00
|
|
|
))}
|
2023-05-28 14:31:49 -07:00
|
|
|
{source && (
|
|
|
|
|
<LyricLine
|
|
|
|
|
key="provided-by"
|
|
|
|
|
className="credit"
|
|
|
|
|
text={`Provided by: ${source}`}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
2023-05-22 17:38:31 -07:00
|
|
|
</ErrorBoundary>
|
|
|
|
|
);
|
|
|
|
|
};
|