Allow changing volume media player entity (#11781)

Co-authored-by: Zack Barett <zackbarett@hey.com>
This commit is contained in:
Paulus Schoutsen 2022-02-22 14:51:25 -08:00 committed by GitHub
parent f5b5414461
commit 5335772a7a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 64 additions and 3 deletions

View File

@ -360,3 +360,17 @@ export const cleanupMediaTitle = (title?: string): string | undefined => {
const index = title.indexOf("?authSig="); const index = title.indexOf("?authSig=");
return index > 0 ? title.slice(0, index) : title; return index > 0 ? title.slice(0, index) : title;
}; };
/**
* Set volume of a media player entity.
* @param hass Home Assistant object
* @param entity_id entity ID of media player
* @param volume_level number between 0..1
* @returns
*/
export const setMediaPlayerVolume = (
hass: HomeAssistant,
entity_id: string,
volume_level: number
) =>
hass.callService("media_player", "volume_set", { entity_id, volume_level });

View File

@ -4,6 +4,7 @@ import {
MediaPlayerItem, MediaPlayerItem,
SUPPORT_PAUSE, SUPPORT_PAUSE,
SUPPORT_PLAY, SUPPORT_PLAY,
SUPPORT_VOLUME_SET,
} from "../../data/media-player"; } from "../../data/media-player";
import { ResolvedMediaSource } from "../../data/media_source"; import { ResolvedMediaSource } from "../../data/media_source";
import { HomeAssistant } from "../../types"; import { HomeAssistant } from "../../types";
@ -20,9 +21,11 @@ export class BrowserMediaPlayer {
public hass: HomeAssistant, public hass: HomeAssistant,
public item: MediaPlayerItem, public item: MediaPlayerItem,
public resolved: ResolvedMediaSource, public resolved: ResolvedMediaSource,
volume: number,
private onChange: () => void private onChange: () => void
) { ) {
const player = new Audio(this.resolved.url); const player = new Audio(this.resolved.url);
player.volume = volume;
player.addEventListener("play", this._handleChange); player.addEventListener("play", this._handleChange);
player.addEventListener("playing", () => { player.addEventListener("playing", () => {
this.buffering = false; this.buffering = false;
@ -57,6 +60,11 @@ export class BrowserMediaPlayer {
this.player.play(); this.player.play();
} }
public setVolume(volume: number) {
this.player.volume = volume;
this.onChange();
}
public remove() { public remove() {
this._removed = true; this._removed = true;
// @ts-ignore // @ts-ignore
@ -89,8 +97,9 @@ export class BrowserMediaPlayer {
base.attributes = { base.attributes = {
media_title: this.item.title, media_title: this.item.title,
entity_picture: this.item.thumbnail, entity_picture: this.item.thumbnail,
volume_level: this.player.volume,
// eslint-disable-next-line no-bitwise // eslint-disable-next-line no-bitwise
supported_features: SUPPORT_PLAY | SUPPORT_PAUSE, supported_features: SUPPORT_PLAY | SUPPORT_PAUSE | SUPPORT_VOLUME_SET,
}; };
if (this.player.duration) { if (this.player.duration) {

View File

@ -9,6 +9,7 @@ import {
mdiPlay, mdiPlay,
mdiPlayPause, mdiPlayPause,
mdiStop, mdiStop,
mdiVolumeHigh,
} from "@mdi/js"; } from "@mdi/js";
import { import {
css, css,
@ -40,10 +41,12 @@ import {
getCurrentProgress, getCurrentProgress,
MediaPlayerEntity, MediaPlayerEntity,
MediaPlayerItem, MediaPlayerItem,
setMediaPlayerVolume,
SUPPORT_BROWSE_MEDIA, SUPPORT_BROWSE_MEDIA,
SUPPORT_PAUSE, SUPPORT_PAUSE,
SUPPORT_PLAY, SUPPORT_PLAY,
SUPPORT_STOP, SUPPORT_STOP,
SUPPORT_VOLUME_SET,
} from "../../data/media-player"; } from "../../data/media-player";
import { ResolvedMediaSource } from "../../data/media_source"; import { ResolvedMediaSource } from "../../data/media_source";
import type { HomeAssistant } from "../../types"; import type { HomeAssistant } from "../../types";
@ -77,6 +80,8 @@ export class BarMediaPlayer extends LitElement {
private _progressInterval?: number; private _progressInterval?: number;
private _browserPlayerVolume = 0.8;
public connectedCallback(): void { public connectedCallback(): void {
super.connectedCallback(); super.connectedCallback();
@ -124,6 +129,7 @@ export class BarMediaPlayer extends LitElement {
this.hass, this.hass,
item, item,
resolved, resolved,
this._browserPlayerVolume,
() => this.requestUpdate("_browserPlayer") () => this.requestUpdate("_browserPlayer")
); );
this._newMediaExpected = false; this._newMediaExpected = false;
@ -230,7 +236,7 @@ export class BarMediaPlayer extends LitElement {
)} )}
.path=${control.icon} .path=${control.icon}
action=${control.action} action=${control.action}
@click=${this._handleClick} @click=${this._handleControlClick}
> >
</ha-icon-button> </ha-icon-button>
` `
@ -257,6 +263,27 @@ export class BarMediaPlayer extends LitElement {
const isBrowser = this.entityId === BROWSER_PLAYER; const isBrowser = this.entityId === BROWSER_PLAYER;
return html` return html`
<div class="choose-player ${isBrowser ? "browser" : ""}"> <div class="choose-player ${isBrowser ? "browser" : ""}">
${
stateObj && supportsFeature(stateObj, SUPPORT_VOLUME_SET)
? html`
<ha-button-menu corner="BOTTOM_START">
<ha-icon-button
slot="trigger"
.path=${mdiVolumeHigh}
></ha-icon-button>
<ha-slider
min="0"
max="100"
step="1"
.value=${stateObj.attributes.volume_level! * 100}
@change=${this._handleVolumeChange}
>
</ha-slider>
</ha-button-menu>
`
: ""
}
<ha-button-menu corner="BOTTOM_START"> <ha-button-menu corner="BOTTOM_START">
${ ${
this.narrow this.narrow
@ -441,7 +468,7 @@ export class BarMediaPlayer extends LitElement {
} }
} }
private _handleClick(e: MouseEvent): void { private _handleControlClick(e: MouseEvent): void {
const action = (e.currentTarget! as HTMLElement).getAttribute("action")!; const action = (e.currentTarget! as HTMLElement).getAttribute("action")!;
if (!this._browserPlayer) { if (!this._browserPlayer) {
@ -474,6 +501,17 @@ export class BarMediaPlayer extends LitElement {
fireEvent(this, "player-picked", { entityId }); fireEvent(this, "player-picked", { entityId });
} }
private async _handleVolumeChange(ev) {
ev.stopPropagation();
const value = Number(ev.target.value) / 100;
if (this._browserPlayer) {
this._browserPlayerVolume = value;
this._browserPlayer.setVolume(value);
} else {
await setMediaPlayerVolume(this.hass, this.entityId, value);
}
}
static get styles(): CSSResultGroup { static get styles(): CSSResultGroup {
return css` return css`
:host { :host {