mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-09 18:44:16 +00:00
support for live mode
This commit is contained in:
parent
05428959ff
commit
37b920b5ab
@ -7,193 +7,210 @@ import useHideOnMouseStop from "@hooks/useHideOnMouseStop"
|
|||||||
|
|
||||||
import { Icons } from "@components/Icons"
|
import { Icons } from "@components/Icons"
|
||||||
import Controls from "@components/Player/Controls"
|
import Controls from "@components/Player/Controls"
|
||||||
|
import LiveInfo from "@components/Player/LiveInfo"
|
||||||
|
|
||||||
import { usePlayerStateContext } from "@contexts/WithPlayerContext"
|
import { usePlayerStateContext } from "@contexts/WithPlayerContext"
|
||||||
|
|
||||||
function isOverflown(element) {
|
function isOverflown(element) {
|
||||||
if (!element) {
|
if (!element) {
|
||||||
return false
|
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 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 [hide, onMouseEnter, onMouseLeave] = useHideOnMouseStop({
|
||||||
const [titleIsOverflown, setTitleIsOverflown] = React.useState(false)
|
delay: 3000,
|
||||||
|
hideCursor: true,
|
||||||
|
})
|
||||||
|
const [titleIsOverflown, setTitleIsOverflown] = React.useState(false)
|
||||||
|
|
||||||
const [currentTime, setCurrentTime] = React.useState(0)
|
const [currentTime, setCurrentTime] = React.useState(0)
|
||||||
const [trackDuration, setTrackDuration] = React.useState(0)
|
const [trackDuration, setTrackDuration] = React.useState(0)
|
||||||
const [draggingTime, setDraggingTime] = React.useState(false)
|
const [draggingTime, setDraggingTime] = React.useState(false)
|
||||||
const [currentDragWidth, setCurrentDragWidth] = React.useState(0)
|
const [currentDragWidth, setCurrentDragWidth] = React.useState(0)
|
||||||
const [syncInterval, setSyncInterval] = React.useState(null)
|
const [syncInterval, setSyncInterval] = React.useState(null)
|
||||||
|
|
||||||
async function onDragEnd(seekTime) {
|
async function onDragEnd(seekTime) {
|
||||||
setDraggingTime(false)
|
setDraggingTime(false)
|
||||||
|
|
||||||
app.cores.player.controls.seek(seekTime)
|
app.cores.player.controls.seek(seekTime)
|
||||||
|
|
||||||
syncPlayback()
|
syncPlayback()
|
||||||
}
|
}
|
||||||
|
|
||||||
async function syncPlayback() {
|
async function syncPlayback() {
|
||||||
if (!playerState.track_manifest) {
|
if (!playerState.track_manifest) {
|
||||||
return false
|
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
|
//* Handle when playback status change
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (playerState.playback_status === "playing") {
|
if (playerState.playback_status === "playing") {
|
||||||
setSyncInterval(setInterval(syncPlayback, 1000))
|
setSyncInterval(setInterval(syncPlayback, 1000))
|
||||||
} else {
|
} else {
|
||||||
if (syncInterval) {
|
if (syncInterval) {
|
||||||
clearInterval(syncInterval)
|
clearInterval(syncInterval)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, [playerState.playback_status])
|
}, [playerState.playback_status])
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
setTitleIsOverflown(isOverflown(titleRef.current))
|
setTitleIsOverflown(isOverflown(titleRef.current))
|
||||||
setTrackDuration(app.cores.player.controls.duration())
|
setTrackDuration(app.cores.player.controls.duration())
|
||||||
}, [playerState.track_manifest])
|
}, [playerState.track_manifest])
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
syncPlayback()
|
syncPlayback()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const isStopped = playerState.playback_status === "stopped"
|
const isStopped = playerState.playback_status === "stopped"
|
||||||
|
|
||||||
return <div
|
return (
|
||||||
className={classnames(
|
<div
|
||||||
"lyrics-player-controller-wrapper",
|
className={classnames("lyrics-player-controller-wrapper", {
|
||||||
{
|
["hidden"]: props.lyrics?.video_source && hide,
|
||||||
["hidden"]: props.lyrics?.video_source && hide,
|
})}
|
||||||
}
|
onMouseEnter={onMouseEnter}
|
||||||
)}
|
onMouseLeave={onMouseLeave}
|
||||||
onMouseEnter={onMouseEnter}
|
>
|
||||||
onMouseLeave={onMouseLeave}
|
<div className="lyrics-player-controller">
|
||||||
>
|
<div className="lyrics-player-controller-info">
|
||||||
<div className="lyrics-player-controller">
|
<div className="lyrics-player-controller-info-title">
|
||||||
<div className="lyrics-player-controller-info">
|
{
|
||||||
<div className="lyrics-player-controller-info-title">
|
<h4
|
||||||
{
|
ref={titleRef}
|
||||||
<h4
|
className={classnames(
|
||||||
ref={titleRef}
|
"lyrics-player-controller-info-title-text",
|
||||||
className={classnames(
|
{
|
||||||
"lyrics-player-controller-info-title-text",
|
["overflown"]: titleIsOverflown,
|
||||||
{
|
},
|
||||||
["overflown"]: titleIsOverflown,
|
)}
|
||||||
}
|
>
|
||||||
)}
|
{playerState.playback_status === "stopped" ||
|
||||||
>
|
(!playerState.track_manifest?.title &&
|
||||||
{
|
"Nothing is playing")}
|
||||||
playerState.playback_status === "stopped" ? "Nothing is playing" : <>
|
|
||||||
{playerState.track_manifest?.title ?? "Nothing is playing"}
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
</h4>
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
{playerState.playback_status !== "stopped" &&
|
||||||
titleIsOverflown && <Marquee
|
playerState.track_manifest?.title}
|
||||||
//gradient
|
</h4>
|
||||||
//gradientColor={bgColor}
|
}
|
||||||
//gradientWidth={20}
|
|
||||||
play={!isStopped}
|
|
||||||
>
|
|
||||||
<h4>
|
|
||||||
{
|
|
||||||
isStopped ?
|
|
||||||
"Nothing is playing" :
|
|
||||||
<>
|
|
||||||
{playerState.track_manifest?.title ?? "Untitled"}
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
</h4>
|
|
||||||
</Marquee>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="lyrics-player-controller-info-details">
|
{titleIsOverflown && (
|
||||||
<span>{playerState.track_manifest?.artistStr}</span>
|
<Marquee
|
||||||
</div>
|
//gradient
|
||||||
</div>
|
//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">
|
{playerState.live && (
|
||||||
<div
|
<LiveInfo radioId={playerState.radioId} />
|
||||||
className="lyrics-player-controller-progress"
|
)}
|
||||||
onMouseDown={(e) => {
|
</div>
|
||||||
setDraggingTime(true)
|
|
||||||
}}
|
|
||||||
onMouseUp={(e) => {
|
|
||||||
const rect = e.currentTarget.getBoundingClientRect()
|
|
||||||
const seekTime = trackDuration * (e.clientX - rect.left) / rect.width
|
|
||||||
|
|
||||||
onDragEnd(seekTime)
|
<Controls streamMode={playerState.live} />
|
||||||
}}
|
|
||||||
onMouseMove={(e) => {
|
|
||||||
const rect = e.currentTarget.getBoundingClientRect()
|
|
||||||
const atWidth = (e.clientX - rect.left) / rect.width * 100
|
|
||||||
|
|
||||||
setCurrentDragWidth(atWidth)
|
{!playerState.live && (
|
||||||
}}
|
<div className="lyrics-player-controller-progress-wrapper">
|
||||||
>
|
<div
|
||||||
<div className="lyrics-player-controller-progress-bar"
|
className="lyrics-player-controller-progress"
|
||||||
style={{
|
onMouseDown={(e) => {
|
||||||
width: `${draggingTime ? currentDragWidth : ((currentTime / trackDuration) * 100)}%`
|
setDraggingTime(true)
|
||||||
}}
|
}}
|
||||||
/>
|
onMouseUp={(e) => {
|
||||||
</div>
|
const rect =
|
||||||
</div>
|
e.currentTarget.getBoundingClientRect()
|
||||||
|
const seekTime =
|
||||||
|
(trackDuration * (e.clientX - rect.left)) /
|
||||||
|
rect.width
|
||||||
|
|
||||||
<div className="lyrics-player-controller-tags">
|
onDragEnd(seekTime)
|
||||||
{
|
}}
|
||||||
playerState.track_manifest?.metadata.lossless && <Tag
|
onMouseMove={(e) => {
|
||||||
icon={<Icons.Lossless
|
const rect =
|
||||||
style={{
|
e.currentTarget.getBoundingClientRect()
|
||||||
margin:0,
|
const atWidth =
|
||||||
}}
|
((e.clientX - rect.left) / rect.width) * 100
|
||||||
/>}
|
|
||||||
bordered={false}
|
setCurrentDragWidth(atWidth)
|
||||||
/>
|
}}
|
||||||
}
|
>
|
||||||
{
|
<div
|
||||||
playerState.track_manifest?.explicit && <Tag
|
className="lyrics-player-controller-progress-bar"
|
||||||
bordered={false}
|
style={{
|
||||||
>
|
width: `${draggingTime ? currentDragWidth : (currentTime / trackDuration) * 100}%`,
|
||||||
Explicit
|
}}
|
||||||
</Tag>
|
/>
|
||||||
}
|
</div>
|
||||||
{
|
</div>
|
||||||
props.lyrics?.sync_audio_at && <Tag
|
)}
|
||||||
bordered={false}
|
|
||||||
icon={<Icons.TbMovie />}
|
<div className="lyrics-player-controller-tags">
|
||||||
>
|
{playerState.track_manifest?.metadata.lossless && (
|
||||||
Video
|
<Tag
|
||||||
</Tag>
|
icon={
|
||||||
}
|
<Icons.Lossless
|
||||||
{
|
style={{
|
||||||
props.lyrics?.available_langs?.length > 1 && <Button
|
margin: 0,
|
||||||
icon={<Icons.MdTranslate />}
|
}}
|
||||||
type={props.translationEnabled ? "primary" : "default"}
|
/>
|
||||||
onClick={() => props.toggleTranslationEnabled()}
|
}
|
||||||
size="small"
|
bordered={false}
|
||||||
/>
|
/>
|
||||||
}
|
)}
|
||||||
</div>
|
{playerState.track_manifest?.explicit && (
|
||||||
</div>
|
<Tag bordered={false}>Explicit</Tag>
|
||||||
</div>
|
)}
|
||||||
|
{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
|
Loading…
x
Reference in New Issue
Block a user