From ebc7142769b7d1a60586ea96c6e0bd271674fe47 Mon Sep 17 00:00:00 2001 From: SrGooglo Date: Mon, 3 Apr 2023 16:22:04 +0000 Subject: [PATCH] improve `livestream` mode --- .../components/EmbbededMediaPlayer/index.jsx | 99 +++++++++---------- .../components/EmbbededMediaPlayer/index.less | 61 ++++++++---- packages/app/src/cores/player/index.jsx | 28 ++++-- 3 files changed, 109 insertions(+), 79 deletions(-) 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 { } -
- { - loading && - } -
@@ -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 = [] }