diff --git a/packages/app/src/components/EmbbededMediaPlayer/index.jsx b/packages/app/src/components/EmbbededMediaPlayer/index.jsx
index ca5be61f..8029d2b7 100755
--- a/packages/app/src/components/EmbbededMediaPlayer/index.jsx
+++ b/packages/app/src/components/EmbbededMediaPlayer/index.jsx
@@ -3,6 +3,9 @@ import * as antd from "antd"
import Slider from "@mui/material/Slider"
import classnames from "classnames"
+import UseAnimations from "react-useanimations"
+import LoadingAnimation from "react-useanimations/lib/loading"
+
import { Icons, createIconRender } from "components/Icons"
import "./index.less"
@@ -37,7 +40,6 @@ class SeekBar extends React.Component {
durationText: "00:00",
sliderTime: 0,
sliderLock: false,
- streamMode: false,
}
handleSeek = (value) => {
@@ -58,36 +60,15 @@ class SeekBar extends React.Component {
// get current audio 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)) {
return
}
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
this.setState({
- durationText: `${minutesString}:${secondsString}`
+ durationText: this.seekToTimeLabel(audioDuration)
})
}
@@ -95,22 +76,26 @@ class SeekBar extends React.Component {
// get current audio seek
const seek = app.cores.player.seek()
+ // set time
+ this.setState({
+ timeText: this.seekToTimeLabel(seek)
+ })
+ }
+
+ seekToTimeLabel = (value) => {
// 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
const minutesString = minutes < 10 ? `0${minutes}` : minutes
// 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
const secondsString = seconds < 10 ? `0${seconds}` : seconds
- // set time
- this.setState({
- timeText: `${minutesString}:${secondsString}`
- })
+ return `${minutesString}:${secondsString}`
}
updateProgressBar = () => {
@@ -163,7 +148,6 @@ class SeekBar extends React.Component {
this.setState({
timeText: "00:00",
sliderTime: 0,
- streamMode: false,
})
this.calculateDuration()
@@ -182,7 +166,7 @@ class SeekBar extends React.Component {
}
tick = () => {
- if (this.props.playing || this.state.streamMode) {
+ if (this.props.playing || this.props.streamMode) {
this.interval = setInterval(() => {
this.updateAll()
}, 1000)
@@ -218,23 +202,20 @@ class SeekBar extends React.Component {
return
{
+ return this.seekToTimeLabel((value / 100) * app.cores.player.duration())
+ }}
/>
@@ -263,7 +248,7 @@ class SeekBar extends React.Component {
{
- this.state.streamMode ?
Live :
{this.state.durationText}
+ this.props.streamMode ?
Live :
{this.state.durationText}
}
@@ -307,21 +292,18 @@ export default class AudioPlayer extends React.Component {
bpm: app.cores.player.getState("trackBPM") ?? 0,
showControls: false,
minimized: false,
- initialLoad: false,
+ streamMode: false,
}
events = {
+ "player.livestream.update": (data) => {
+ this.setState({ streamMode: data })
+ },
"player.bpm.update": (data) => {
this.setState({ bpm: data })
},
"player.loading.update": (data) => {
this.setState({ loading: data })
-
- if (!data && !this.state.initialLoad) {
- this.setState({
- initialLoad: true
- })
- }
},
"player.status.update": (data) => {
this.setState({ playbackStatus: data })
@@ -374,11 +356,15 @@ export default class AudioPlayer extends React.Component {
app.cores.player.volume(value)
}
- toogleMute = (to) => {
- app.cores.player.toogleMute(to)
+ toogleMute = () => {
+ app.cores.player.toogleMute()
}
onClickPlayButton = () => {
+ if (this.state.streamMode) {
+ return app.cores.player.playback.stop()
+ }
+
app.cores.player.playback.toogle()
}
@@ -445,11 +431,6 @@ export default class AudioPlayer extends React.Component {
}
-
@@ -463,9 +444,19 @@ export default class AudioPlayer extends React.Component {
:
}
+ icon={this.state.streamMode ?
: playbackStatus === "playing" ?
:
}
onClick={this.onClickPlayButton}
- />
+ className="playButton"
+ >
+ {
+ loading &&
+
+
+ }
+
diff --git a/packages/app/src/components/EmbbededMediaPlayer/index.less b/packages/app/src/components/EmbbededMediaPlayer/index.less
index c6d5d7e0..c2e8b901 100755
--- a/packages/app/src/components/EmbbededMediaPlayer/index.less
+++ b/packages/app/src/components/EmbbededMediaPlayer/index.less
@@ -140,6 +140,8 @@
box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.2);
.cover {
+ position: relative;
+
z-index: 320;
width: 100%;
@@ -164,6 +166,8 @@
}
.header {
+ position: relative;
+
display: flex;
flex-direction: row;
@@ -203,25 +207,6 @@
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 {
@@ -237,6 +222,44 @@
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 {
padding: 10px;
diff --git a/packages/app/src/cores/player/index.jsx b/packages/app/src/cores/player/index.jsx
index f1d49526..344ccb11 100755
--- a/packages/app/src/cores/player/index.jsx
+++ b/packages/app/src/cores/player/index.jsx
@@ -61,6 +61,7 @@ export default class Player extends Core {
playbackStatus: "stopped",
crossfading: false,
trackBPM: 0,
+ livestream: false,
})
public = {
@@ -149,6 +150,11 @@ export default class Player extends Core {
changes.forEach((change) => {
if (change.type === "update") {
switch (change.path[0]) {
+ case "livestream": {
+ app.eventBus.emit("player.livestream.update", change.object.livestream)
+
+ break
+ }
case "trackBPM": {
app.eventBus.emit("player.bpm.update", change.object.trackBPM)
@@ -477,6 +483,10 @@ export default class Player extends Core {
this.audioContext.resume()
}
+ if (!this.currentDomWindow) {
+ this.attachPlayerComponent()
+ }
+
this.currentAudioInstance = instance
this.state.currentAudioManifest = instance.manifest
@@ -503,12 +513,16 @@ export default class Player extends Core {
instance.audioElement.play()
- if (!this.currentDomWindow) {
- // FIXME: i gonna attach the player component after 500ms to avoid error calculating the player position and duration on the first play
- setTimeout(() => {
- this.attachPlayerComponent()
- }, 300)
- }
+ // check if the audio is a live stream when metadata is loaded
+ instance.audioElement.addEventListener("loadedmetadata", () => {
+ console.log("loadedmetadata", instance.audioElement.duration)
+
+ if (instance.audioElement.duration === Infinity) {
+ instance.manifest.stream = true
+
+ this.state.livestream = true
+ }
+ }, { once: true })
}
async startPlaylist(playlist, startIndex = 0) {
@@ -645,6 +659,8 @@ export default class Player extends Core {
this.state.playbackStatus = "stopped"
this.state.currentAudioManifest = null
+ this.state.livestream = false
+
this.audioQueue = []
}