support for live mode

This commit is contained in:
SrGooglo 2025-02-20 02:42:03 +00:00
parent 05428959ff
commit 37b920b5ab

View File

@ -7,193 +7,210 @@ import useHideOnMouseStop from "@hooks/useHideOnMouseStop"
import { Icons } from "@components/Icons"
import Controls from "@components/Player/Controls"
import LiveInfo from "@components/Player/LiveInfo"
import { usePlayerStateContext } from "@contexts/WithPlayerContext"
function isOverflown(element) {
if (!element) {
return false
}
if (!element) {
return false
}
return element.scrollHeight > element.clientHeight || element.scrollWidth > element.clientWidth;
return (
element.scrollHeight > element.clientHeight ||
element.scrollWidth > element.clientWidth
)
}
const PlayerController = React.forwardRef((props, ref) => {
const [playerState] = usePlayerStateContext()
const [playerState] = usePlayerStateContext()
const titleRef = React.useRef()
const titleRef = React.useRef()
const [hide, onMouseEnter, onMouseLeave] = useHideOnMouseStop({ delay: 3000, hideCursor: true })
const [titleIsOverflown, setTitleIsOverflown] = React.useState(false)
const [hide, onMouseEnter, onMouseLeave] = useHideOnMouseStop({
delay: 3000,
hideCursor: true,
})
const [titleIsOverflown, setTitleIsOverflown] = React.useState(false)
const [currentTime, setCurrentTime] = React.useState(0)
const [trackDuration, setTrackDuration] = React.useState(0)
const [draggingTime, setDraggingTime] = React.useState(false)
const [currentDragWidth, setCurrentDragWidth] = React.useState(0)
const [syncInterval, setSyncInterval] = React.useState(null)
const [currentTime, setCurrentTime] = React.useState(0)
const [trackDuration, setTrackDuration] = React.useState(0)
const [draggingTime, setDraggingTime] = React.useState(false)
const [currentDragWidth, setCurrentDragWidth] = React.useState(0)
const [syncInterval, setSyncInterval] = React.useState(null)
async function onDragEnd(seekTime) {
setDraggingTime(false)
async function onDragEnd(seekTime) {
setDraggingTime(false)
app.cores.player.controls.seek(seekTime)
app.cores.player.controls.seek(seekTime)
syncPlayback()
}
syncPlayback()
}
async function syncPlayback() {
if (!playerState.track_manifest) {
return false
}
async function syncPlayback() {
if (!playerState.track_manifest) {
return false
}
const currentTrackTime = app.cores.player.controls.seek()
const currentTrackTime = app.cores.player.controls.seek()
setCurrentTime(currentTrackTime)
}
setCurrentTime(currentTrackTime)
}
//* Handle when playback status change
React.useEffect(() => {
if (playerState.playback_status === "playing") {
setSyncInterval(setInterval(syncPlayback, 1000))
} else {
if (syncInterval) {
clearInterval(syncInterval)
}
}
}, [playerState.playback_status])
//* Handle when playback status change
React.useEffect(() => {
if (playerState.playback_status === "playing") {
setSyncInterval(setInterval(syncPlayback, 1000))
} else {
if (syncInterval) {
clearInterval(syncInterval)
}
}
}, [playerState.playback_status])
React.useEffect(() => {
setTitleIsOverflown(isOverflown(titleRef.current))
setTrackDuration(app.cores.player.controls.duration())
}, [playerState.track_manifest])
React.useEffect(() => {
setTitleIsOverflown(isOverflown(titleRef.current))
setTrackDuration(app.cores.player.controls.duration())
}, [playerState.track_manifest])
React.useEffect(() => {
syncPlayback()
}, [])
React.useEffect(() => {
syncPlayback()
}, [])
const isStopped = playerState.playback_status === "stopped"
const isStopped = playerState.playback_status === "stopped"
return <div
className={classnames(
"lyrics-player-controller-wrapper",
{
["hidden"]: props.lyrics?.video_source && hide,
}
)}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
>
<div className="lyrics-player-controller">
<div className="lyrics-player-controller-info">
<div className="lyrics-player-controller-info-title">
{
<h4
ref={titleRef}
className={classnames(
"lyrics-player-controller-info-title-text",
{
["overflown"]: titleIsOverflown,
}
)}
>
{
playerState.playback_status === "stopped" ? "Nothing is playing" : <>
{playerState.track_manifest?.title ?? "Nothing is playing"}
</>
}
</h4>
}
return (
<div
className={classnames("lyrics-player-controller-wrapper", {
["hidden"]: props.lyrics?.video_source && hide,
})}
onMouseEnter={onMouseEnter}
onMouseLeave={onMouseLeave}
>
<div className="lyrics-player-controller">
<div className="lyrics-player-controller-info">
<div className="lyrics-player-controller-info-title">
{
<h4
ref={titleRef}
className={classnames(
"lyrics-player-controller-info-title-text",
{
["overflown"]: titleIsOverflown,
},
)}
>
{playerState.playback_status === "stopped" ||
(!playerState.track_manifest?.title &&
"Nothing is playing")}
{
titleIsOverflown && <Marquee
//gradient
//gradientColor={bgColor}
//gradientWidth={20}
play={!isStopped}
>
<h4>
{
isStopped ?
"Nothing is playing" :
<>
{playerState.track_manifest?.title ?? "Untitled"}
</>
}
</h4>
</Marquee>
}
</div>
{playerState.playback_status !== "stopped" &&
playerState.track_manifest?.title}
</h4>
}
<div className="lyrics-player-controller-info-details">
<span>{playerState.track_manifest?.artistStr}</span>
</div>
</div>
{titleIsOverflown && (
<Marquee
//gradient
//gradientColor={bgColor}
//gradientWidth={20}
play={!isStopped}
>
<h4>
{isStopped ? (
"Nothing is playing"
) : (
<>
{playerState.track_manifest
?.title ?? "Untitled"}
</>
)}
</h4>
</Marquee>
)}
</div>
<Controls />
<div className="lyrics-player-controller-info-details">
<span>{playerState.track_manifest?.artistStr}</span>
</div>
<div className="lyrics-player-controller-progress-wrapper">
<div
className="lyrics-player-controller-progress"
onMouseDown={(e) => {
setDraggingTime(true)
}}
onMouseUp={(e) => {
const rect = e.currentTarget.getBoundingClientRect()
const seekTime = trackDuration * (e.clientX - rect.left) / rect.width
{playerState.live && (
<LiveInfo radioId={playerState.radioId} />
)}
</div>
onDragEnd(seekTime)
}}
onMouseMove={(e) => {
const rect = e.currentTarget.getBoundingClientRect()
const atWidth = (e.clientX - rect.left) / rect.width * 100
<Controls streamMode={playerState.live} />
setCurrentDragWidth(atWidth)
}}
>
<div className="lyrics-player-controller-progress-bar"
style={{
width: `${draggingTime ? currentDragWidth : ((currentTime / trackDuration) * 100)}%`
}}
/>
</div>
</div>
{!playerState.live && (
<div className="lyrics-player-controller-progress-wrapper">
<div
className="lyrics-player-controller-progress"
onMouseDown={(e) => {
setDraggingTime(true)
}}
onMouseUp={(e) => {
const rect =
e.currentTarget.getBoundingClientRect()
const seekTime =
(trackDuration * (e.clientX - rect.left)) /
rect.width
<div className="lyrics-player-controller-tags">
{
playerState.track_manifest?.metadata.lossless && <Tag
icon={<Icons.Lossless
style={{
margin:0,
}}
/>}
bordered={false}
/>
}
{
playerState.track_manifest?.explicit && <Tag
bordered={false}
>
Explicit
</Tag>
}
{
props.lyrics?.sync_audio_at && <Tag
bordered={false}
icon={<Icons.TbMovie />}
>
Video
</Tag>
}
{
props.lyrics?.available_langs?.length > 1 && <Button
icon={<Icons.MdTranslate />}
type={props.translationEnabled ? "primary" : "default"}
onClick={() => props.toggleTranslationEnabled()}
size="small"
/>
}
</div>
</div>
</div>
onDragEnd(seekTime)
}}
onMouseMove={(e) => {
const rect =
e.currentTarget.getBoundingClientRect()
const atWidth =
((e.clientX - rect.left) / rect.width) * 100
setCurrentDragWidth(atWidth)
}}
>
<div
className="lyrics-player-controller-progress-bar"
style={{
width: `${draggingTime ? currentDragWidth : (currentTime / trackDuration) * 100}%`,
}}
/>
</div>
</div>
)}
<div className="lyrics-player-controller-tags">
{playerState.track_manifest?.metadata.lossless && (
<Tag
icon={
<Icons.Lossless
style={{
margin: 0,
}}
/>
}
bordered={false}
/>
)}
{playerState.track_manifest?.explicit && (
<Tag bordered={false}>Explicit</Tag>
)}
{props.lyrics?.sync_audio_at && (
<Tag bordered={false} icon={<Icons.TbMovie />}>
Video
</Tag>
)}
{props.lyrics?.available_langs?.length > 1 && (
<Button
icon={<Icons.MdTranslate />}
type={
props.translationEnabled ? "primary" : "default"
}
onClick={() => props.toggleTranslationEnabled()}
size="small"
/>
)}
</div>
</div>
</div>
)
})
export default PlayerController
export default PlayerController