improve media player

This commit is contained in:
SrGooglo 2023-03-14 19:52:30 +00:00
parent 7606d3c92c
commit a89228171a
7 changed files with 345 additions and 5 deletions

View File

@ -0,0 +1,184 @@
import React from "react"
import Ticker from "react-ticker"
import { FastAverageColor } from "fast-average-color"
import classnames from "classnames"
import { Icons } from "components/Icons"
import "./index.less"
const useEventBus = (events) => {
const registerEvents = () => {
for (const [event, handler] of Object.entries(events)) {
app.eventBus.on(event, handler)
}
}
const unregisterEvents = () => {
for (const [event, handler] of Object.entries(events)) {
app.eventBus.off(event, handler)
}
}
React.useEffect(() => {
registerEvents()
return () => {
unregisterEvents()
}
}, [])
}
const fac = new FastAverageColor()
const bruh = (props) => {
const [thumbnailAnalysis, setThumbnailAnalysis] = React.useState("#000000")
const [currentPlaying, setCurrentPlaying] = React.useState(app.cores.player.getState("currentAudioManifest"))
const [plabackState, setPlaybackState] = React.useState(app.cores.player.getState("playbackStatus") ?? "stopped")
const onClickMinimize = () => {
app.cores.player.minimize()
}
const calculateAverageCoverColor = async () => {
if (currentPlaying) {
const color = await fac.getColorAsync(currentPlaying.thumbnail)
setThumbnailAnalysis(color)
updateBackgroundItem(color)
}
}
const updateBackgroundItem = () => {
app.SidebarController.updateBackgroundItem(undefined, {
icon: <Icons.MdMusicNote />,
style: {
backgroundColor: thumbnailAnalysis?.hex
}
})
}
useEventBus({
"player.current.update": (data) => {
console.log("player.current.update", data)
setCurrentPlaying(data)
updateBackgroundItem()
},
"player.playback.update": (data) => {
setPlaybackState(data)
updateBackgroundItem()
}
})
React.useEffect(() => {
calculateAverageCoverColor()
}, [currentPlaying])
React.useEffect(() => {
}, [])
return <div
className="background_media_player"
onClick={onClickMinimize}
>
{
currentPlaying && <div
className={classnames(
"background_media_player__title",
{
["lightBackground"]: thumbnailAnalysis.isLight,
}
)}
>
<h4>
{currentPlaying.title} - {currentPlaying.artist}
</h4>
</div>
}
</div>
}
export default class BackgroundMediaPlayer extends React.Component {
state = {
thumbnailAnalysis: null,
currentPlaying: app.cores.player.getState("currentAudioManifest"),
plabackState: app.cores.player.getState("playbackStatus") ?? "stopped",
}
events = {
"player.current.update": (data) => {
this.calculateAverageCoverColor()
this.setState({
currentPlaying: data
})
},
"player.playback.update": (data) => {
this.updateBackgroundItem()
this.setState({
plabackState: data
})
}
}
onClickMinimize = () => {
app.cores.player.minimize()
}
calculateAverageCoverColor = async () => {
if (this.state.currentPlaying) {
const color = await fac.getColorAsync(this.state.currentPlaying.thumbnail)
this.setState({
thumbnailAnalysis: color
})
this.updateBackgroundItem(color)
}
}
updateBackgroundItem = (analysis) => {
app.SidebarController.updateBackgroundItem(undefined, {
icon: <Icons.MdMusicNote />,
style: {
backgroundColor: analysis?.hex ?? this.state.thumbnailAnalysis?.hex,
}
})
}
componentDidMount = async () => {
this.calculateAverageCoverColor()
for (const [event, handler] of Object.entries(this.events)) {
app.eventBus.on(event, handler)
}
}
componentWillUnmount() {
for (const [event, handler] of Object.entries(this.events)) {
app.eventBus.off(event, handler)
}
}
render() {
return <div
className="background_media_player"
onClick={this.onClickMinimize}
>
{
this.state.currentPlaying && <div
className={classnames(
"background_media_player__title",
{
["lightBackground"]: this.state.thumbnailAnalysis?.isLight,
}
)}
>
<h4>
{this.state.currentPlaying?.title} - {this.state.currentPlaying?.artist}
</h4>
</div>
}
</div>
}
}

View File

@ -0,0 +1,36 @@
.background_media_player {
overflow: hidden;
width: 100%;
transition: all 150ms ease-in-out;
.background_media_player__title {
overflow: hidden;
white-space: nowrap;
width: 100%;
&.lightBackground {
h4 {
color: var(--text-color-black);
}
}
h4 {
font-size: 1rem;
font-weight: 600;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-family: "Space Grotesk", sans-serif;
color: var(--text-color-white);
}
}
}

View File

@ -2,6 +2,7 @@ import React from "react"
import * as antd from "antd"
import Slider from "@mui/material/Slider"
import classnames from "classnames"
import Ticker from "react-ticker"
import { Icons, createIconRender } from "components/Icons"
@ -163,7 +164,7 @@ class SeekBar extends React.Component {
this.calculateTime()
this.updateAll()
}
},
}
tick = () => {
@ -273,6 +274,7 @@ export default class AudioPlayer extends React.Component {
audioVolume: app.cores.player.getState("audioVolume") ?? 0.3,
bpm: app.cores.player.getState("trackBPM") ?? 0,
showControls: false,
minimized: false,
}
events = {
@ -294,6 +296,13 @@ export default class AudioPlayer extends React.Component {
"player.volume.update": (data) => {
this.setState({ audioVolume: data })
},
"player.minimized.update": (minimized) => {
console.log(`Player minimized updated: ${minimized}`)
this.setState({
minimized
})
}
}
componentDidMount = async () => {
@ -319,7 +328,7 @@ export default class AudioPlayer extends React.Component {
}
minimize = () => {
app.cores.player.minimize()
}
updateVolume = (value) => {
@ -356,6 +365,7 @@ export default class AudioPlayer extends React.Component {
"embbededMediaPlayerWrapper",
{
["hovering"]: this.state.showControls,
["minimized"]: this.state.minimized,
}
)}
onMouseEnter={this.onMouse}

View File

@ -18,6 +18,15 @@
border-radius: 12px;
pointer-events: initial;
transition: all 150ms ease-in-out;
&.minimized {
pointer-events: none;
opacity: 0;
}
&.hovering {
.actions_wrapper {
.actions {
@ -88,7 +97,7 @@
top: 0;
left: 0;
opacity: 0;
transition: all 150ms ease-in-out;
@ -97,7 +106,7 @@
.ant-btn {
background-color: var(--background-color-accent);
svg {
margin: 0 !important;
}
@ -231,6 +240,7 @@
.muteButton {
padding: 10px;
svg {
font-size: 1rem;
}

View File

@ -119,6 +119,34 @@ export default class Sidebar extends React.Component {
isExpanded: () => this.state.expanded,
setCustomRender: this.setRender,
closeCustomRender: this.closeRender,
updateBackgroundItem: (children, props) => {
let updatedValue = this.state.backgroundItem
if (typeof children !== "undefined") {
updatedValue.children = children
}
if (typeof props !== "undefined") {
updatedValue.props = props
}
this.setState({
backgroundItem: updatedValue
})
},
setBackgroundItem: (children, props) => {
this.setState({
backgroundItem: {
children: children,
props: props,
},
})
},
clearBackgroundItem: () => {
this.setState({
backgroundItem: null,
})
}
}
this.state = {
@ -130,6 +158,7 @@ export default class Sidebar extends React.Component {
customRenderTitle: null,
customRender: null,
backgroundItem: null,
}
// handle sidedrawer open/close
@ -228,6 +257,10 @@ export default class Sidebar extends React.Component {
}
handleClick = (e) => {
if (e.item.props.ignoreClick) {
return
}
if (e.item.props.override_event) {
return app.eventBus.emit(e.item.props.override_event, e.item.props.override_event_props)
}
@ -341,6 +374,16 @@ export default class Sidebar extends React.Component {
<div key="bottom" className={classnames("app_sidebar_menu_wrapper", "bottom")}>
<Menu selectable={false} mode="inline" onClick={this.handleClick}>
<Menu.Item
{...this.state.backgroundItem?.props ?? {}}
key="background_item"
className={classnames("background_item", { ["active"]: this.state.backgroundItem })}
ignoreClick
>
{
this.state.backgroundItem?.children
}
</Menu.Item>
<Menu.Item key="search" icon={<Icons.Search />} >
<Translation>
{(t) => t("Search")}

View File

@ -182,6 +182,30 @@
}
}
.background_item {
width: 100%;
opacity: 0;
transition: all 150ms ease-in-out;
padding-bottom: 10px;
background-color: transparent;
&:hover{
background-color: unset!important;
}
&:active{
background-color: unset!important;
}
&.active {
opacity: 1;
}
}
.render_content_wrapper {
display: flex;
flex-direction: column;

View File

@ -1,9 +1,12 @@
import React from "react"
import Core from "evite/src/core"
import { Observable } from "object-observer"
import store from "store"
// import { createRealTimeBpmProcessor } from "realtime-bpm-analyzer"
import { EmbbededMediaPlayer } from "components"
import EmbbededMediaPlayer from "components/EmbbededMediaPlayer"
import BackgroundMediaPlayer from "components/BackgroundMediaPlayer"
import { DOMWindow } from "components/RenderWindow"
class AudioPlayerStorage {
@ -47,6 +50,7 @@ export default class Player extends Core {
state = Observable.from({
loading: false,
minimized: false,
audioMuted: AudioPlayerStorage.get("mute") ?? false,
playbackMode: AudioPlayerStorage.get("mode") ?? "repeat",
audioVolume: AudioPlayerStorage.get("volume") ?? 0.3,
@ -63,6 +67,7 @@ export default class Player extends Core {
attachPlayerComponent: this.attachPlayerComponent.bind(this),
detachPlayerComponent: this.detachPlayerComponent.bind(this),
toogleMute: this.toogleMute.bind(this),
minimize: this.toogleMinimize.bind(this),
volume: this.volume.bind(this),
start: this.start.bind(this),
startPlaylist: this.startPlaylist.bind(this),
@ -198,6 +203,17 @@ export default class Player extends Core {
case "playbackStatus": {
app.eventBus.emit("player.status.update", change.object.playbackStatus)
break
}
case "minimized": {
if (change.object.minimized) {
app.SidebarController.setBackgroundItem(React.createElement(BackgroundMediaPlayer))
} else {
app.SidebarController.setBackgroundItem(null)
}
app.eventBus.emit("player.minimized.update", change.object.minimized)
break
}
}
@ -633,6 +649,12 @@ export default class Player extends Core {
return this.state.audioMuted
}
toogleMinimize(to) {
this.state.minimized = to ?? !this.state.minimized
return this.state.minimized
}
volume(volume) {
if (typeof volume !== "number") {
return this.state.audioVolume
@ -716,4 +738,15 @@ export default class Player extends Core {
return this.state.velocity
}
collapse(to) {
if (typeof to !== "boolean") {
console.warn("Collapse must be a boolean")
return false
}
this.state.collapsed = to ?? !this.state.collapsed
return this.state.collapsed
}
}