import { selectTree } from "../helpers"; export const MediaPlayerMixin = (SuperClass) => { return class MediaPlayerMixinClass extends SuperClass { public player; private _audio_player; private _video_player; private _player_enabled; private _player_update_cooldown; constructor() { super(); this._audio_player = new Audio(); this._video_player = document.createElement("video"); this._video_player.controls = true; this._video_player.style.setProperty("width", "100%"); this.player = this._audio_player; this._player_enabled = false; for (const ev of ["play", "pause", "ended", "volumechange"]) { this._audio_player.addEventListener(ev, () => this._player_update()); this._video_player.addEventListener(ev, () => this._player_update()); } for (const ev of ["timeupdate"]) { this._audio_player.addEventListener(ev, () => this._player_update_choked() ); this._video_player.addEventListener(ev, () => this._player_update_choked() ); } this.firstInteraction.then(() => { this._player_enabled = true; if (!this.player.ended) this.player.play(); }); this.addEventListener("command-player-play", (ev) => { if (this.player.src) this.player.pause(); if (ev.detail?.media_type) if (ev.detail?.media_type.startsWith("video")) this.player = this._video_player; else this.player = this._audio_player; if (ev.detail?.media_content_id) this.player.src = ev.detail.media_content_id; this.player.play(); this._show_video_player(); }); this.addEventListener("command-player-pause", (ev) => this.player.pause() ); this.addEventListener("command-player-stop", (ev) => { this.player.src = null; this.player.pause(); }); this.addEventListener("command-player-set-volume", (ev) => { if (ev.detail?.volume_level === undefined) return; this.player.volume = ev.detail.volume_level; }); this.addEventListener("command-player-mute", (ev) => { if (ev.detail?.mute !== undefined) this.player.muted = Boolean(ev.detail.mute); else this.player.muted = !this.player.muted; }); this.addEventListener("command-player-seek", (ev) => { this.player.currentTime = ev.detail.position; setTimeout(() => this._player_update(), 10); }); this.addEventListener("command-player-turn-off", (ev) => { if ( this.player === this._video_player && this._video_player.isConnected ) this.closePopup(); else if (this.player.src) this.player.pause(); this.player.src = ""; this._player_update(); }); this.connectionPromise.then(() => this._player_update()); } private _show_video_player() { if (this.player === this._video_player && this.player.src) { selectTree( document, "home-assistant $ dialog-media-player-browse" ).then((el) => el?.closeDialog()); this.showPopup(undefined, this._video_player, { dismiss_action: () => this._video_player.pause(), size: "wide", }); } else if ( this.player !== this._video_player && this._video_player.isConnected ) { this.closePopup(); } } private _player_update_choked() { if (this._player_update_cooldown) return; this._player_update_cooldown = window.setTimeout( () => (this._player_update_cooldown = undefined), 3000 ); this._player_update(); } private _player_update() { const state = this._player_enabled ? !this.player.src || this.player.src === window.location.href ? "off" : this.player.ended ? "stopped" : this.player.paused ? "paused" : "playing" : "unavailable"; this.sendUpdate({ player: { volume: this.player.volume, muted: this.player.muted, src: this.player.src, state, media_duration: this.player.duration, media_position: this.player.currentTime, }, }); } }; };