mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-10 02:54:15 +00:00
improve livestream
mode
This commit is contained in:
parent
bb6daaa8b6
commit
ebc7142769
@ -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>
|
||||||
|
@ -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;
|
||||||
|
@ -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 = []
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user