improve livestream mode

This commit is contained in:
SrGooglo 2023-04-03 16:22:04 +00:00
parent bb6daaa8b6
commit ebc7142769
3 changed files with 109 additions and 79 deletions

View File

@ -3,6 +3,9 @@ import * as antd from "antd"
import Slider from "@mui/material/Slider" import Slider from "@mui/material/Slider"
import classnames from "classnames" import classnames from "classnames"
import UseAnimations from "react-useanimations"
import LoadingAnimation from "react-useanimations/lib/loading"
import { Icons, createIconRender } from "components/Icons" import { Icons, createIconRender } from "components/Icons"
import "./index.less" import "./index.less"
@ -37,7 +40,6 @@ class SeekBar extends React.Component {
durationText: "00:00", durationText: "00:00",
sliderTime: 0, sliderTime: 0,
sliderLock: false, sliderLock: false,
streamMode: false,
} }
handleSeek = (value) => { handleSeek = (value) => {
@ -58,36 +60,15 @@ class SeekBar extends React.Component {
// get current audio duration // get current audio duration
const audioDuration = app.cores.player.duration() const audioDuration = app.cores.player.duration()
// if duration is infinity, set stream mode
if (audioDuration === Infinity) {
this.setState({
streamMode: true,
})
return
}
if (isNaN(audioDuration)) { if (isNaN(audioDuration)) {
return return
} }
console.log(`Audio duration: ${audioDuration}`) console.log(`Audio duration: ${audioDuration}`)
// convert duration to minutes and seconds
const minutes = Math.floor(audioDuration / 60)
// add leading zero if minutes is less than 10
const minutesString = minutes < 10 ? `0${minutes}` : minutes
// get seconds
const seconds = Math.floor(audioDuration - minutes * 60)
// add leading zero if seconds is less than 10
const secondsString = seconds < 10 ? `0${seconds}` : seconds
// set duration // set duration
this.setState({ this.setState({
durationText: `${minutesString}:${secondsString}` durationText: this.seekToTimeLabel(audioDuration)
}) })
} }
@ -95,22 +76,26 @@ class SeekBar extends React.Component {
// get current audio seek // get current audio seek
const seek = app.cores.player.seek() const seek = app.cores.player.seek()
// set time
this.setState({
timeText: this.seekToTimeLabel(seek)
})
}
seekToTimeLabel = (value) => {
// convert seek to minutes and seconds // convert seek to minutes and seconds
const minutes = Math.floor(seek / 60) const minutes = Math.floor(value / 60)
// add leading zero if minutes is less than 10 // add leading zero if minutes is less than 10
const minutesString = minutes < 10 ? `0${minutes}` : minutes const minutesString = minutes < 10 ? `0${minutes}` : minutes
// get seconds // get seconds
const seconds = Math.floor(seek - minutes * 60) const seconds = Math.floor(value - minutes * 60)
// add leading zero if seconds is less than 10 // add leading zero if seconds is less than 10
const secondsString = seconds < 10 ? `0${seconds}` : seconds const secondsString = seconds < 10 ? `0${seconds}` : seconds
// set time return `${minutesString}:${secondsString}`
this.setState({
timeText: `${minutesString}:${secondsString}`
})
} }
updateProgressBar = () => { updateProgressBar = () => {
@ -163,7 +148,6 @@ class SeekBar extends React.Component {
this.setState({ this.setState({
timeText: "00:00", timeText: "00:00",
sliderTime: 0, sliderTime: 0,
streamMode: false,
}) })
this.calculateDuration() this.calculateDuration()
@ -182,7 +166,7 @@ class SeekBar extends React.Component {
} }
tick = () => { tick = () => {
if (this.props.playing || this.state.streamMode) { if (this.props.playing || this.props.streamMode) {
this.interval = setInterval(() => { this.interval = setInterval(() => {
this.updateAll() this.updateAll()
}, 1000) }, 1000)
@ -218,23 +202,20 @@ class SeekBar extends React.Component {
return <div return <div
className={classnames( className={classnames(
"status", "status",
{
["hidden"]: !this.props.initialLoad,
}
)} )}
> >
<div <div
className={classnames( className={classnames(
"progress", "progress",
{ {
["hidden"]: this.state.streamMode, ["hidden"]: this.props.streamMode,
} }
)} )}
> >
<Slider <Slider
size="small" size="small"
value={this.state.sliderTime} value={this.state.sliderTime}
disabled={this.props.stopped || this.state.streamMode} disabled={this.props.stopped || this.props.streamMode}
min={0} min={0}
max={100} max={100}
step={0.1} step={0.1}
@ -255,6 +236,10 @@ class SeekBar extends React.Component {
app.cores.player.playback.play() app.cores.player.playback.play()
} }
}} }}
valueLabelDisplay="auto"
valueLabelFormat={(value) => {
return this.seekToTimeLabel((value / 100) * app.cores.player.duration())
}}
/> />
</div> </div>
<div className="timers"> <div className="timers">
@ -263,7 +248,7 @@ class SeekBar extends React.Component {
</div> </div>
<div> <div>
{ {
this.state.streamMode ? <antd.Tag>Live</antd.Tag> : <span>{this.state.durationText}</span> this.props.streamMode ? <antd.Tag>Live</antd.Tag> : <span>{this.state.durationText}</span>
} }
</div> </div>
</div> </div>
@ -307,21 +292,18 @@ export default class AudioPlayer extends React.Component {
bpm: app.cores.player.getState("trackBPM") ?? 0, bpm: app.cores.player.getState("trackBPM") ?? 0,
showControls: false, showControls: false,
minimized: false, minimized: false,
initialLoad: false, streamMode: false,
} }
events = { events = {
"player.livestream.update": (data) => {
this.setState({ streamMode: data })
},
"player.bpm.update": (data) => { "player.bpm.update": (data) => {
this.setState({ bpm: data }) this.setState({ bpm: data })
}, },
"player.loading.update": (data) => { "player.loading.update": (data) => {
this.setState({ loading: data }) this.setState({ loading: data })
if (!data && !this.state.initialLoad) {
this.setState({
initialLoad: true
})
}
}, },
"player.status.update": (data) => { "player.status.update": (data) => {
this.setState({ playbackStatus: data }) this.setState({ playbackStatus: data })
@ -374,11 +356,15 @@ export default class AudioPlayer extends React.Component {
app.cores.player.volume(value) app.cores.player.volume(value)
} }
toogleMute = (to) => { toogleMute = () => {
app.cores.player.toogleMute(to) app.cores.player.toogleMute()
} }
onClickPlayButton = () => { onClickPlayButton = () => {
if (this.state.streamMode) {
return app.cores.player.playback.stop()
}
app.cores.player.playback.toogle() app.cores.player.playback.toogle()
} }
@ -445,11 +431,6 @@ export default class AudioPlayer extends React.Component {
} }
</div> </div>
</div> </div>
<div className="indicators">
{
loading && <antd.Spin />
}
</div>
</div> </div>
<div className="controls"> <div className="controls">
@ -463,9 +444,19 @@ export default class AudioPlayer extends React.Component {
<antd.Button <antd.Button
type="primary" type="primary"
shape="circle" shape="circle"
icon={playbackStatus === "playing" ? <Icons.Pause /> : <Icons.Play />} icon={this.state.streamMode ? <Icons.MdStop /> : playbackStatus === "playing" ? <Icons.Pause /> : <Icons.Play />}
onClick={this.onClickPlayButton} onClick={this.onClickPlayButton}
/> className="playButton"
>
{
loading && <div className="loadCircle">
<UseAnimations
animation={LoadingAnimation}
size="100%"
/>
</div>
}
</antd.Button>
<antd.Button <antd.Button
type="ghost" type="ghost"
shape="round" shape="round"
@ -495,7 +486,7 @@ export default class AudioPlayer extends React.Component {
<SeekBar <SeekBar
stopped={playbackStatus === "stopped"} stopped={playbackStatus === "stopped"}
playing={playbackStatus === "playing"} playing={playbackStatus === "playing"}
initialLoad={this.state.initialLoad} streamMode={this.state.streamMode}
/> />
</div> </div>
</div> </div>

View File

@ -140,6 +140,8 @@
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.2); box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.2);
.cover { .cover {
position: relative;
z-index: 320; z-index: 320;
width: 100%; width: 100%;
@ -164,6 +166,8 @@
} }
.header { .header {
position: relative;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@ -203,25 +207,6 @@
color: var(--text-color); color: var(--text-color);
} }
} }
.indicators {
position: fixed;
right: 0;
display: inline-flex;
flex-direction: row;
padding: 10px;
justify-content: space-evenly;
svg {
width: 20px;
height: 20px;
color: var(--text-color);
}
}
} }
.controls { .controls {
@ -237,6 +222,44 @@
margin: 0 !important; margin: 0 !important;
} }
.playButton {
position: relative;
display: flex;
align-items: center;
justify-content: center;
.loadCircle {
position: absolute;
z-index: 330;
top: 0;
right: 0;
left: 0;
width: 100%;
height: 100%;
margin: auto;
align-self: center;
justify-self: center;
transform: scale(1.5);
svg {
width: 100%;
height: 100%;
path {
stroke: var(--text-color);
stroke-width: 1;
}
}
}
}
.muteButton { .muteButton {
padding: 10px; padding: 10px;

View File

@ -61,6 +61,7 @@ export default class Player extends Core {
playbackStatus: "stopped", playbackStatus: "stopped",
crossfading: false, crossfading: false,
trackBPM: 0, trackBPM: 0,
livestream: false,
}) })
public = { public = {
@ -149,6 +150,11 @@ export default class Player extends Core {
changes.forEach((change) => { changes.forEach((change) => {
if (change.type === "update") { if (change.type === "update") {
switch (change.path[0]) { switch (change.path[0]) {
case "livestream": {
app.eventBus.emit("player.livestream.update", change.object.livestream)
break
}
case "trackBPM": { case "trackBPM": {
app.eventBus.emit("player.bpm.update", change.object.trackBPM) app.eventBus.emit("player.bpm.update", change.object.trackBPM)
@ -477,6 +483,10 @@ export default class Player extends Core {
this.audioContext.resume() this.audioContext.resume()
} }
if (!this.currentDomWindow) {
this.attachPlayerComponent()
}
this.currentAudioInstance = instance this.currentAudioInstance = instance
this.state.currentAudioManifest = instance.manifest this.state.currentAudioManifest = instance.manifest
@ -503,12 +513,16 @@ export default class Player extends Core {
instance.audioElement.play() instance.audioElement.play()
if (!this.currentDomWindow) { // check if the audio is a live stream when metadata is loaded
// FIXME: i gonna attach the player component after 500ms to avoid error calculating the player position and duration on the first play instance.audioElement.addEventListener("loadedmetadata", () => {
setTimeout(() => { console.log("loadedmetadata", instance.audioElement.duration)
this.attachPlayerComponent()
}, 300) if (instance.audioElement.duration === Infinity) {
} instance.manifest.stream = true
this.state.livestream = true
}
}, { once: true })
} }
async startPlaylist(playlist, startIndex = 0) { async startPlaylist(playlist, startIndex = 0) {
@ -645,6 +659,8 @@ export default class Player extends Core {
this.state.playbackStatus = "stopped" this.state.playbackStatus = "stopped"
this.state.currentAudioManifest = null this.state.currentAudioManifest = null
this.state.livestream = false
this.audioQueue = [] this.audioQueue = []
} }