From 39b427dea7e4b168408b57e165bcfe20bbde0565 Mon Sep 17 00:00:00 2001 From: SrGooglo Date: Wed, 5 Feb 2025 02:45:14 +0000 Subject: [PATCH] improve lyrics to use new manifest functions --- .../lyrics/components/controller/index.jsx | 10 +- .../pages/lyrics/components/text/index.jsx | 54 ++-- .../pages/lyrics/components/video/index.jsx | 9 +- packages/app/src/pages/lyrics/index.jsx | 249 +++++++++++------- packages/app/src/pages/lyrics/index.less | 2 +- 5 files changed, 195 insertions(+), 129 deletions(-) diff --git a/packages/app/src/pages/lyrics/components/controller/index.jsx b/packages/app/src/pages/lyrics/components/controller/index.jsx index 6b9bad65..a788b9e5 100644 --- a/packages/app/src/pages/lyrics/components/controller/index.jsx +++ b/packages/app/src/pages/lyrics/components/controller/index.jsx @@ -160,11 +160,13 @@ const PlayerController = React.forwardRef((props, ref) => {
{ playerState.track_manifest?.metadata.lossless && } + icon={} bordered={false} - > - Lossless - + /> } { playerState.track_manifest?.explicit && { const [visible, setVisible] = React.useState(false) function syncPlayback() { - if (!lyrics) { - return false - } - const currentTrackTime = app.cores.player.controls.seek() * 1000 const lineIndex = lyrics.synced_lyrics.findIndex((line) => { @@ -46,9 +42,28 @@ const LyricsText = React.forwardRef((props, textRef) => { } function startSyncInterval() { + if (!lyrics || !lyrics.synced_lyrics) { + stopSyncInterval() + return false + } + + if (playerState.playback_status !== "playing") { + stopSyncInterval() + return false + } + + if (syncInterval) { + stopSyncInterval() + } + setSyncInterval(setInterval(syncPlayback, 100)) } + function stopSyncInterval() { + clearInterval(syncInterval) + setSyncInterval(null) + } + //* Handle when current line index change React.useEffect(() => { if (currentLineIndex === 0) { @@ -74,38 +89,19 @@ const LyricsText = React.forwardRef((props, textRef) => { //* Handle when playback status change React.useEffect(() => { - if (typeof lyrics?.synced_lyrics !== "undefined") { - if (playerState.playback_status === "playing") { - startSyncInterval() - } else { - if (syncInterval) { - clearInterval(syncInterval) - } - } - } else { - clearInterval(syncInterval) - } + startSyncInterval() }, [playerState.playback_status]) - //* Handle when lyrics object change - React.useEffect(() => { - clearInterval(syncInterval) - - if (lyrics) { - if (typeof lyrics?.synced_lyrics !== "undefined") { - if (playerState.playback_status === "playing") { - startSyncInterval() - } - } - } - }, [lyrics]) - + //* Handle when manifest object change, reset... React.useEffect(() => { setVisible(false) - clearInterval(syncInterval) setCurrentLineIndex(0) }, [playerState.track_manifest]) + React.useEffect(() => { + startSyncInterval() + }, [lyrics]) + React.useEffect(() => { return () => { clearInterval(syncInterval) diff --git a/packages/app/src/pages/lyrics/components/video/index.jsx b/packages/app/src/pages/lyrics/components/video/index.jsx index 40a73f94..023a94f0 100644 --- a/packages/app/src/pages/lyrics/components/video/index.jsx +++ b/packages/app/src/pages/lyrics/components/video/index.jsx @@ -109,7 +109,12 @@ const LyricsVideo = React.forwardRef((props, videoRef) => { if (lyrics) { if (lyrics.video_source) { console.log("Loading video source >", lyrics.video_source) - hls.current.loadSource(lyrics.video_source) + + if (lyrics.video_source.endsWith(".mp4")) { + videoRef.current.src = lyrics.video_source + } else { + hls.current.loadSource(lyrics.video_source) + } if (typeof lyrics.sync_audio_at_ms !== "undefined") { videoRef.current.loop = false @@ -121,7 +126,7 @@ const LyricsVideo = React.forwardRef((props, videoRef) => { videoRef.current.currentTime = 0 } - if (playerState.playback_status === "playing"){ + if (playerState.playback_status === "playing") { videoRef.current.play() } } diff --git a/packages/app/src/pages/lyrics/index.jsx b/packages/app/src/pages/lyrics/index.jsx index 6b43d79d..985cc929 100644 --- a/packages/app/src/pages/lyrics/index.jsx +++ b/packages/app/src/pages/lyrics/index.jsx @@ -4,124 +4,187 @@ import classnames from "classnames" import useMaxScreen from "@hooks/useMaxScreen" import { usePlayerStateContext } from "@contexts/WithPlayerContext" -import MusicService from "@models/music" - import PlayerController from "./components/controller" import LyricsVideo from "./components/video" import LyricsText from "./components/text" import "./index.less" -function getDominantColorStr(track_manifest) { - if (!track_manifest) { - return `0,0,0` - } +function getDominantColorStr(analysis) { + if (!analysis) { + return `0,0,0` + } - const values = track_manifest.cover_analysis?.value ?? [0, 0, 0] + const values = analysis?.value ?? [0, 0, 0] - return `${values[0]}, ${values[1]}, ${values[2]}` + return `${values[0]}, ${values[1]}, ${values[2]}` +} + +function toggleFullScreen(to) { + to = to ?? !document.fullscreenElement + + if (to === true) { + document.documentElement.requestFullscreen().catch((err) => { + console.log(`Failed to set to fullscreen: ${err.message}`) + }) + } else { + try { + document.exitFullscreen() + } catch (error) { + // xd + } + } } const EnchancedLyricsPage = () => { - const [playerState] = usePlayerStateContext() + const [playerState] = usePlayerStateContext() + const [trackManifest, setTrackManifest] = React.useState(null) - const [initialized, setInitialized] = React.useState(false) - const [lyrics, setLyrics] = React.useState(null) - const [translationEnabled, setTranslationEnabled] = React.useState(false) + const [initialized, setInitialized] = React.useState(false) + const [lyrics, setLyrics] = React.useState(null) + const [translationEnabled, setTranslationEnabled] = React.useState(false) + const [coverAnalysis, setCoverAnalysis] = React.useState(null) - const videoRef = React.useRef() - const textRef = React.useRef() + const videoRef = React.useRef() + const textRef = React.useRef() - async function loadLyrics(track_id) { - const result = await MusicService.getTrackLyrics(track_id, { - preferTranslation: translationEnabled, - }).catch((err) => { - return null - }) + function listenFullScreenChange() { + if (!document.fullscreenElement) { + if (app.location.last) { + app.location.back() + } else { + app.navigation.goMain() + } + } + } - if (result) { - setLyrics(result) - } else { - setLyrics(false) - } - } + async function loadCurrentTrackLyrics() { + // get current track instance + const instance = app.cores.player.track() - async function toggleTranslationEnabled(to) { - setTranslationEnabled((prev) => { - return to ?? !prev - }) - } + const result = await instance.manifest.serviceOperations + .fetchLyrics({ + preferTranslation: translationEnabled, + }) + .catch((err) => { + console.error("Failed to fetch lyrics", err) + return null + }) - useMaxScreen() + console.log("Fetched Lyrics >", result) - React.useEffect((prev) => { - if (initialized) { - loadLyrics(playerState.track_manifest._id) - } - }, [translationEnabled]) + if (result) { + setLyrics(result) + } else { + setLyrics(false) + } + } - //* Handle when context change track_manifest - React.useEffect(() => { - if (playerState.track_manifest) { - if (!lyrics || (lyrics.track_id !== playerState.track_manifest._id)) { - loadLyrics(playerState.track_manifest._id) - } - } else { - setLyrics(null) - } - }, [playerState.track_manifest]) + async function toggleTranslationEnabled(to) { + setTranslationEnabled((prev) => { + return to ?? !prev + }) + } - React.useEffect(() => { - setInitialized(true) - }, []) + useMaxScreen() - return
-
+ // React.useEffect((prev) => { + // if (initialized) { + // loadLyrics(playerState.track_manifest) + // } + // }, [translationEnabled]) - { - playerState.track_manifest && !lyrics?.video_source &&
+ //* Handle when context change track_manifest + React.useEffect(() => { + if (trackManifest && playerState.track_manifest) { + if (!lyrics || lyrics.track_id !== playerState.track_manifest._id) { + loadCurrentTrackLyrics() + } + } else { + setLyrics(null) + } + }, [trackManifest]) -
- -
-
- } + React.useEffect(() => { + if (!playerState.track_manifest) { + return + } - + const currentPlayerTrackManifest = + playerState.track_manifest.toSeriableObject() - + // check if track manifest is the same + if (trackManifest === currentPlayerTrackManifest) { + return + } - -
+ setTrackManifest(currentPlayerTrackManifest) + }, [playerState]) + + React.useEffect(() => { + const trackInstance = app.cores.player.track() + + if (playerState.track_manifest && trackInstance) { + if ( + typeof trackInstance.manifest.analyzeCoverColor === "function" + ) { + trackInstance.manifest + .analyzeCoverColor() + .then((analysis) => { + setCoverAnalysis(analysis) + }) + .catch((err) => { + console.error("Failed to get cover analysis", err) + }) + } + } + }, [playerState.track_manifest]) + + React.useEffect(() => { + setInitialized(true) + toggleFullScreen(true) + + document.addEventListener("fullscreenchange", listenFullScreenChange) + + return () => { + toggleFullScreen(false) + document.removeEventListener( + "fullscreenchange", + listenFullScreenChange, + ) + } + }, []) + + return ( +
+
+ + {playerState.track_manifest && !lyrics?.video_source && ( +
+
+ +
+
+ )} + + + + + + +
+ ) } -export default EnchancedLyricsPage \ No newline at end of file +export default EnchancedLyricsPage diff --git a/packages/app/src/pages/lyrics/index.less b/packages/app/src/pages/lyrics/index.less index 495db078..0e03ac83 100644 --- a/packages/app/src/pages/lyrics/index.less +++ b/packages/app/src/pages/lyrics/index.less @@ -58,7 +58,7 @@ width: 40vw; height: 40vw; - object-fit: contain; + object-fit: cover; border-radius: 24px; }