mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-09 18:44:16 +00:00
refactor & improve
This commit is contained in:
parent
37b920b5ab
commit
0589a11371
@ -1,8 +1,7 @@
|
|||||||
import React from "react"
|
import React, { useCallback, useEffect, useMemo, useRef } from "react"
|
||||||
import classnames from "classnames"
|
import classnames from "classnames"
|
||||||
|
|
||||||
import parseTimeToMs from "@utils/parseTimeToMs"
|
import parseTimeToMs from "@utils/parseTimeToMs"
|
||||||
|
|
||||||
import useMaxScreen from "@hooks/useMaxScreen"
|
import useMaxScreen from "@hooks/useMaxScreen"
|
||||||
import { usePlayerStateContext } from "@contexts/WithPlayerContext"
|
import { usePlayerStateContext } from "@contexts/WithPlayerContext"
|
||||||
|
|
||||||
@ -12,185 +11,180 @@ import LyricsText from "./components/text"
|
|||||||
|
|
||||||
import "./index.less"
|
import "./index.less"
|
||||||
|
|
||||||
function getDominantColorStr(analysis) {
|
const getDominantColorStr = (analysis) => {
|
||||||
if (!analysis) {
|
if (!analysis) return "0,0,0"
|
||||||
return `0,0,0`
|
return analysis.value?.join(", ") || "0,0,0"
|
||||||
}
|
|
||||||
|
|
||||||
const values = analysis?.value ?? [0, 0, 0]
|
|
||||||
|
|
||||||
return `${values[0]}, ${values[1]}, ${values[2]}`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleFullScreen(to) {
|
const toggleFullScreen = (to) => {
|
||||||
to = to ?? !document.fullscreenElement
|
const targetState = to ?? !document.fullscreenElement
|
||||||
|
|
||||||
if (to === true) {
|
try {
|
||||||
document.documentElement.requestFullscreen().catch((err) => {
|
if (targetState) {
|
||||||
console.log(`Failed to set to fullscreen: ${err.message}`)
|
document.documentElement.requestFullscreen()
|
||||||
})
|
} else if (document.fullscreenElement) {
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
document.exitFullscreen()
|
document.exitFullscreen()
|
||||||
} catch (error) {
|
|
||||||
// xd
|
|
||||||
}
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Fullscreen toggle failed:", error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const EnchancedLyricsPage = () => {
|
const EnhancedLyricsPage = () => {
|
||||||
|
useMaxScreen()
|
||||||
|
|
||||||
const [playerState] = usePlayerStateContext()
|
const [playerState] = usePlayerStateContext()
|
||||||
const [trackManifest, setTrackManifest] = React.useState(null)
|
const [trackManifest, setTrackManifest] = React.useState(null)
|
||||||
|
|
||||||
const [initialized, setInitialized] = React.useState(false)
|
|
||||||
const [lyrics, setLyrics] = React.useState(null)
|
const [lyrics, setLyrics] = React.useState(null)
|
||||||
const [translationEnabled, setTranslationEnabled] = React.useState(false)
|
const [translationEnabled, setTranslationEnabled] = React.useState(false)
|
||||||
const [coverAnalysis, setCoverAnalysis] = React.useState(null)
|
const [coverAnalysis, setCoverAnalysis] = React.useState(null)
|
||||||
|
|
||||||
const videoRef = React.useRef()
|
const videoRef = useRef()
|
||||||
const textRef = React.useRef()
|
const textRef = useRef()
|
||||||
|
const isMounted = useRef(true)
|
||||||
|
const currentTrackId = useRef(null)
|
||||||
|
|
||||||
function listenFullScreenChange() {
|
const dominantColor = useMemo(
|
||||||
if (!document.fullscreenElement) {
|
() => ({ "--dominant-color": getDominantColorStr(coverAnalysis) }),
|
||||||
if (app.location.last) {
|
[coverAnalysis],
|
||||||
app.location.back()
|
)
|
||||||
} else {
|
|
||||||
app.navigation.goMain()
|
const handleFullScreenChange = useCallback(() => {
|
||||||
}
|
if (!document.fullscreenElement && app?.location?.last) {
|
||||||
|
app.location.back()
|
||||||
}
|
}
|
||||||
}
|
}, [])
|
||||||
|
|
||||||
|
const loadCurrentTrackLyrics = useCallback(async () => {
|
||||||
|
if (!playerState.track_manifest) return
|
||||||
|
|
||||||
async function loadCurrentTrackLyrics() {
|
|
||||||
// get current track instance
|
|
||||||
const instance = app.cores.player.track()
|
const instance = app.cores.player.track()
|
||||||
|
if (!instance) return
|
||||||
|
|
||||||
let result = await instance.manifest.serviceOperations
|
try {
|
||||||
.fetchLyrics({
|
const result =
|
||||||
preferTranslation: translationEnabled,
|
await instance.manifest.serviceOperations.fetchLyrics({
|
||||||
})
|
preferTranslation: translationEnabled,
|
||||||
.catch((err) => {
|
})
|
||||||
console.error("Failed to fetch lyrics", err)
|
|
||||||
return null
|
|
||||||
})
|
|
||||||
|
|
||||||
if (result.sync_audio_at && !result.sync_audio_at_ms) {
|
if (!isMounted.current) return
|
||||||
result.sync_audio_at_ms = parseTimeToMs(result.sync_audio_at)
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("Fetched Lyrics >", result)
|
const processedLyrics =
|
||||||
|
result.sync_audio_at && !result.sync_audio_at_ms
|
||||||
|
? {
|
||||||
|
...result,
|
||||||
|
sync_audio_at_ms: parseTimeToMs(
|
||||||
|
result.sync_audio_at,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
: result
|
||||||
|
|
||||||
if (result) {
|
console.log("Fetched Lyrics >", processedLyrics)
|
||||||
setLyrics(result)
|
setLyrics(processedLyrics || false)
|
||||||
} else {
|
} catch (error) {
|
||||||
|
console.error("Failed to fetch lyrics", error)
|
||||||
setLyrics(false)
|
setLyrics(false)
|
||||||
}
|
}
|
||||||
}
|
}, [translationEnabled, playerState.track_manifest])
|
||||||
|
|
||||||
async function toggleTranslationEnabled(to) {
|
// Track manifest comparison
|
||||||
setTranslationEnabled((prev) => {
|
useEffect(() => {
|
||||||
return to ?? !prev
|
const newManifest = playerState.track_manifest?.toSeriableObject()
|
||||||
})
|
if (JSON.stringify(newManifest) !== JSON.stringify(trackManifest)) {
|
||||||
}
|
setTrackManifest(newManifest)
|
||||||
|
|
||||||
useMaxScreen()
|
|
||||||
|
|
||||||
// React.useEffect((prev) => {
|
|
||||||
// if (initialized) {
|
|
||||||
// loadLyrics(playerState.track_manifest)
|
|
||||||
// }
|
|
||||||
// }, [translationEnabled])
|
|
||||||
|
|
||||||
//* 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])
|
}, [playerState.track_manifest])
|
||||||
|
|
||||||
React.useEffect(() => {
|
// Lyrics loading trigger
|
||||||
setInitialized(true)
|
useEffect(() => {
|
||||||
toggleFullScreen(true)
|
if (!trackManifest) {
|
||||||
|
setLyrics(null)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
document.addEventListener("fullscreenchange", listenFullScreenChange)
|
if (!lyrics || lyrics.track_id !== trackManifest._id) {
|
||||||
|
loadCurrentTrackLyrics()
|
||||||
|
}
|
||||||
|
}, [trackManifest, lyrics?.track_id])
|
||||||
|
|
||||||
|
// Cover analysis
|
||||||
|
useEffect(() => {
|
||||||
|
const getCoverAnalysis = async () => {
|
||||||
|
const trackInstance = app.cores.player.track()
|
||||||
|
if (!trackInstance?.manifest.analyzeCoverColor) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
const analysis =
|
||||||
|
await trackInstance.manifest.analyzeCoverColor()
|
||||||
|
if (isMounted.current) setCoverAnalysis(analysis)
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to get cover analysis", error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (playerState.track_manifest) {
|
||||||
|
getCoverAnalysis()
|
||||||
|
}
|
||||||
|
}, [playerState.track_manifest])
|
||||||
|
|
||||||
|
// Initialization and cleanup
|
||||||
|
useEffect(() => {
|
||||||
|
isMounted.current = true
|
||||||
|
toggleFullScreen(true)
|
||||||
|
document.addEventListener("fullscreenchange", handleFullScreenChange)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
isMounted.current = false
|
||||||
toggleFullScreen(false)
|
toggleFullScreen(false)
|
||||||
document.removeEventListener(
|
document.removeEventListener(
|
||||||
"fullscreenchange",
|
"fullscreenchange",
|
||||||
listenFullScreenChange,
|
handleFullScreenChange,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
// Translation toggler
|
||||||
|
const handleTranslationToggle = useCallback(
|
||||||
|
(to) => setTranslationEnabled((prev) => to ?? !prev),
|
||||||
|
[],
|
||||||
|
)
|
||||||
|
|
||||||
|
// Memoized background component
|
||||||
|
const renderBackground = useMemo(() => {
|
||||||
|
if (!playerState.track_manifest || lyrics?.video_source) return null
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="lyrics-background-wrapper">
|
||||||
|
<div className="lyrics-background-cover">
|
||||||
|
<img
|
||||||
|
src={playerState.track_manifest.cover}
|
||||||
|
alt="Album cover"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}, [playerState.track_manifest, lyrics?.video_source])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classnames("lyrics", {
|
className={classnames("lyrics", {
|
||||||
["stopped"]: playerState.playback_status !== "playing",
|
stopped: playerState.playback_status !== "playing",
|
||||||
})}
|
})}
|
||||||
style={{
|
style={dominantColor}
|
||||||
"--dominant-color": getDominantColorStr(coverAnalysis),
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<div className="lyrics-background-color" />
|
<div className="lyrics-background-color" />
|
||||||
|
|
||||||
{playerState.track_manifest && !lyrics?.video_source && (
|
{renderBackground}
|
||||||
<div className="lyrics-background-wrapper">
|
|
||||||
<div className="lyrics-background-cover">
|
|
||||||
<img src={playerState.track_manifest.cover} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<LyricsVideo ref={videoRef} lyrics={lyrics} />
|
<LyricsVideo ref={videoRef} lyrics={lyrics} />
|
||||||
|
|
||||||
<LyricsText ref={textRef} lyrics={lyrics} />
|
<LyricsText ref={textRef} lyrics={lyrics} />
|
||||||
|
|
||||||
<PlayerController
|
<PlayerController
|
||||||
lyrics={lyrics}
|
lyrics={lyrics}
|
||||||
translationEnabled={translationEnabled}
|
translationEnabled={translationEnabled}
|
||||||
toggleTranslationEnabled={toggleTranslationEnabled}
|
toggleTranslationEnabled={handleTranslationToggle}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default EnchancedLyricsPage
|
export default EnhancedLyricsPage
|
||||||
|
Loading…
x
Reference in New Issue
Block a user