mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-09 18:44:16 +00:00
improve lyrics to use new manifest functions
This commit is contained in:
parent
840d994480
commit
39b427dea7
@ -160,11 +160,13 @@ const PlayerController = React.forwardRef((props, ref) => {
|
|||||||
<div className="lyrics-player-controller-tags">
|
<div className="lyrics-player-controller-tags">
|
||||||
{
|
{
|
||||||
playerState.track_manifest?.metadata.lossless && <Tag
|
playerState.track_manifest?.metadata.lossless && <Tag
|
||||||
icon={<Icons.TbWaveSine />}
|
icon={<Icons.Lossless
|
||||||
|
style={{
|
||||||
|
margin:0,
|
||||||
|
}}
|
||||||
|
/>}
|
||||||
bordered={false}
|
bordered={false}
|
||||||
>
|
/>
|
||||||
Lossless
|
|
||||||
</Tag>
|
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
playerState.track_manifest?.explicit && <Tag
|
playerState.track_manifest?.explicit && <Tag
|
||||||
|
@ -14,10 +14,6 @@ const LyricsText = React.forwardRef((props, textRef) => {
|
|||||||
const [visible, setVisible] = React.useState(false)
|
const [visible, setVisible] = React.useState(false)
|
||||||
|
|
||||||
function syncPlayback() {
|
function syncPlayback() {
|
||||||
if (!lyrics) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
const currentTrackTime = app.cores.player.controls.seek() * 1000
|
const currentTrackTime = app.cores.player.controls.seek() * 1000
|
||||||
|
|
||||||
const lineIndex = lyrics.synced_lyrics.findIndex((line) => {
|
const lineIndex = lyrics.synced_lyrics.findIndex((line) => {
|
||||||
@ -46,9 +42,28 @@ const LyricsText = React.forwardRef((props, textRef) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function startSyncInterval() {
|
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))
|
setSyncInterval(setInterval(syncPlayback, 100))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function stopSyncInterval() {
|
||||||
|
clearInterval(syncInterval)
|
||||||
|
setSyncInterval(null)
|
||||||
|
}
|
||||||
|
|
||||||
//* Handle when current line index change
|
//* Handle when current line index change
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (currentLineIndex === 0) {
|
if (currentLineIndex === 0) {
|
||||||
@ -74,38 +89,19 @@ const LyricsText = React.forwardRef((props, textRef) => {
|
|||||||
|
|
||||||
//* Handle when playback status change
|
//* Handle when playback status change
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (typeof lyrics?.synced_lyrics !== "undefined") {
|
startSyncInterval()
|
||||||
if (playerState.playback_status === "playing") {
|
|
||||||
startSyncInterval()
|
|
||||||
} else {
|
|
||||||
if (syncInterval) {
|
|
||||||
clearInterval(syncInterval)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
clearInterval(syncInterval)
|
|
||||||
}
|
|
||||||
}, [playerState.playback_status])
|
}, [playerState.playback_status])
|
||||||
|
|
||||||
//* Handle when lyrics object change
|
//* Handle when manifest object change, reset...
|
||||||
React.useEffect(() => {
|
|
||||||
clearInterval(syncInterval)
|
|
||||||
|
|
||||||
if (lyrics) {
|
|
||||||
if (typeof lyrics?.synced_lyrics !== "undefined") {
|
|
||||||
if (playerState.playback_status === "playing") {
|
|
||||||
startSyncInterval()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, [lyrics])
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
setVisible(false)
|
setVisible(false)
|
||||||
clearInterval(syncInterval)
|
|
||||||
setCurrentLineIndex(0)
|
setCurrentLineIndex(0)
|
||||||
}, [playerState.track_manifest])
|
}, [playerState.track_manifest])
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
startSyncInterval()
|
||||||
|
}, [lyrics])
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
clearInterval(syncInterval)
|
clearInterval(syncInterval)
|
||||||
|
@ -109,7 +109,12 @@ const LyricsVideo = React.forwardRef((props, videoRef) => {
|
|||||||
if (lyrics) {
|
if (lyrics) {
|
||||||
if (lyrics.video_source) {
|
if (lyrics.video_source) {
|
||||||
console.log("Loading video source >", 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") {
|
if (typeof lyrics.sync_audio_at_ms !== "undefined") {
|
||||||
videoRef.current.loop = false
|
videoRef.current.loop = false
|
||||||
@ -121,7 +126,7 @@ const LyricsVideo = React.forwardRef((props, videoRef) => {
|
|||||||
videoRef.current.currentTime = 0
|
videoRef.current.currentTime = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if (playerState.playback_status === "playing"){
|
if (playerState.playback_status === "playing") {
|
||||||
videoRef.current.play()
|
videoRef.current.play()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,124 +4,187 @@ import classnames from "classnames"
|
|||||||
import useMaxScreen from "@hooks/useMaxScreen"
|
import useMaxScreen from "@hooks/useMaxScreen"
|
||||||
import { usePlayerStateContext } from "@contexts/WithPlayerContext"
|
import { usePlayerStateContext } from "@contexts/WithPlayerContext"
|
||||||
|
|
||||||
import MusicService from "@models/music"
|
|
||||||
|
|
||||||
import PlayerController from "./components/controller"
|
import PlayerController from "./components/controller"
|
||||||
import LyricsVideo from "./components/video"
|
import LyricsVideo from "./components/video"
|
||||||
import LyricsText from "./components/text"
|
import LyricsText from "./components/text"
|
||||||
|
|
||||||
import "./index.less"
|
import "./index.less"
|
||||||
|
|
||||||
function getDominantColorStr(track_manifest) {
|
function getDominantColorStr(analysis) {
|
||||||
if (!track_manifest) {
|
if (!analysis) {
|
||||||
return `0,0,0`
|
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 EnchancedLyricsPage = () => {
|
||||||
const [playerState] = usePlayerStateContext()
|
const [playerState] = usePlayerStateContext()
|
||||||
|
const [trackManifest, setTrackManifest] = React.useState(null)
|
||||||
|
|
||||||
const [initialized, setInitialized] = React.useState(false)
|
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 videoRef = React.useRef()
|
const videoRef = React.useRef()
|
||||||
const textRef = React.useRef()
|
const textRef = React.useRef()
|
||||||
|
|
||||||
async function loadLyrics(track_id) {
|
function listenFullScreenChange() {
|
||||||
const result = await MusicService.getTrackLyrics(track_id, {
|
if (!document.fullscreenElement) {
|
||||||
preferTranslation: translationEnabled,
|
if (app.location.last) {
|
||||||
}).catch((err) => {
|
app.location.back()
|
||||||
return null
|
} else {
|
||||||
})
|
app.navigation.goMain()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (result) {
|
async function loadCurrentTrackLyrics() {
|
||||||
setLyrics(result)
|
// get current track instance
|
||||||
} else {
|
const instance = app.cores.player.track()
|
||||||
setLyrics(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function toggleTranslationEnabled(to) {
|
const result = await instance.manifest.serviceOperations
|
||||||
setTranslationEnabled((prev) => {
|
.fetchLyrics({
|
||||||
return to ?? !prev
|
preferTranslation: translationEnabled,
|
||||||
})
|
})
|
||||||
}
|
.catch((err) => {
|
||||||
|
console.error("Failed to fetch lyrics", err)
|
||||||
|
return null
|
||||||
|
})
|
||||||
|
|
||||||
useMaxScreen()
|
console.log("Fetched Lyrics >", result)
|
||||||
|
|
||||||
React.useEffect((prev) => {
|
if (result) {
|
||||||
if (initialized) {
|
setLyrics(result)
|
||||||
loadLyrics(playerState.track_manifest._id)
|
} else {
|
||||||
}
|
setLyrics(false)
|
||||||
}, [translationEnabled])
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//* Handle when context change track_manifest
|
async function toggleTranslationEnabled(to) {
|
||||||
React.useEffect(() => {
|
setTranslationEnabled((prev) => {
|
||||||
if (playerState.track_manifest) {
|
return to ?? !prev
|
||||||
if (!lyrics || (lyrics.track_id !== playerState.track_manifest._id)) {
|
})
|
||||||
loadLyrics(playerState.track_manifest._id)
|
}
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setLyrics(null)
|
|
||||||
}
|
|
||||||
}, [playerState.track_manifest])
|
|
||||||
|
|
||||||
React.useEffect(() => {
|
useMaxScreen()
|
||||||
setInitialized(true)
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
return <div
|
// React.useEffect((prev) => {
|
||||||
className={classnames(
|
// if (initialized) {
|
||||||
"lyrics",
|
// loadLyrics(playerState.track_manifest)
|
||||||
{
|
// }
|
||||||
["stopped"]: playerState.playback_status !== "playing",
|
// }, [translationEnabled])
|
||||||
}
|
|
||||||
)}
|
|
||||||
style={{
|
|
||||||
"--dominant-color": getDominantColorStr(playerState.track_manifest)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="lyrics-background-color"
|
|
||||||
/>
|
|
||||||
|
|
||||||
{
|
//* Handle when context change track_manifest
|
||||||
playerState.track_manifest && !lyrics?.video_source && <div
|
React.useEffect(() => {
|
||||||
className="lyrics-background-wrapper"
|
if (trackManifest && playerState.track_manifest) {
|
||||||
>
|
if (!lyrics || lyrics.track_id !== playerState.track_manifest._id) {
|
||||||
|
loadCurrentTrackLyrics()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setLyrics(null)
|
||||||
|
}
|
||||||
|
}, [trackManifest])
|
||||||
|
|
||||||
<div
|
React.useEffect(() => {
|
||||||
className="lyrics-background-cover"
|
if (!playerState.track_manifest) {
|
||||||
>
|
return
|
||||||
<img
|
}
|
||||||
src={playerState.track_manifest.cover}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
<LyricsVideo
|
const currentPlayerTrackManifest =
|
||||||
ref={videoRef}
|
playerState.track_manifest.toSeriableObject()
|
||||||
lyrics={lyrics}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<LyricsText
|
// check if track manifest is the same
|
||||||
ref={textRef}
|
if (trackManifest === currentPlayerTrackManifest) {
|
||||||
lyrics={lyrics}
|
return
|
||||||
translationEnabled={translationEnabled}
|
}
|
||||||
/>
|
|
||||||
|
|
||||||
<PlayerController
|
setTrackManifest(currentPlayerTrackManifest)
|
||||||
lyrics={lyrics}
|
}, [playerState])
|
||||||
translationEnabled={translationEnabled}
|
|
||||||
toggleTranslationEnabled={toggleTranslationEnabled}
|
React.useEffect(() => {
|
||||||
/>
|
const trackInstance = app.cores.player.track()
|
||||||
</div>
|
|
||||||
|
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 (
|
||||||
|
<div
|
||||||
|
className={classnames("lyrics", {
|
||||||
|
["stopped"]: playerState.playback_status !== "playing",
|
||||||
|
})}
|
||||||
|
style={{
|
||||||
|
"--dominant-color": getDominantColorStr(coverAnalysis),
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="lyrics-background-color" />
|
||||||
|
|
||||||
|
{playerState.track_manifest && !lyrics?.video_source && (
|
||||||
|
<div className="lyrics-background-wrapper">
|
||||||
|
<div className="lyrics-background-cover">
|
||||||
|
<img src={playerState.track_manifest.cover} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<LyricsVideo ref={videoRef} lyrics={lyrics} />
|
||||||
|
|
||||||
|
<LyricsText ref={textRef} lyrics={lyrics} />
|
||||||
|
|
||||||
|
<PlayerController
|
||||||
|
lyrics={lyrics}
|
||||||
|
translationEnabled={translationEnabled}
|
||||||
|
toggleTranslationEnabled={toggleTranslationEnabled}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default EnchancedLyricsPage
|
export default EnchancedLyricsPage
|
@ -58,7 +58,7 @@
|
|||||||
width: 40vw;
|
width: 40vw;
|
||||||
height: 40vw;
|
height: 40vw;
|
||||||
|
|
||||||
object-fit: contain;
|
object-fit: cover;
|
||||||
|
|
||||||
border-radius: 24px;
|
border-radius: 24px;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user