mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-28 11:46:42 +00:00
Play audio in the bottom bar media player (#11413)
Co-authored-by: Zack <zackbarett@hey.com>
This commit is contained in:
parent
416e2e26c0
commit
bbcec38450
15
src/data/media_source.ts
Normal file
15
src/data/media_source.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { HomeAssistant } from "../types";
|
||||||
|
|
||||||
|
export interface ResolvedMediaSource {
|
||||||
|
url: string;
|
||||||
|
mime_type: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const resolveMediaSource = (
|
||||||
|
hass: HomeAssistant,
|
||||||
|
media_content_id: string
|
||||||
|
) =>
|
||||||
|
hass.callWS<ResolvedMediaSource>({
|
||||||
|
type: "media_source/resolve_media",
|
||||||
|
media_content_id,
|
||||||
|
});
|
106
src/panels/media-browser/browser-media-player.ts
Normal file
106
src/panels/media-browser/browser-media-player.ts
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
import {
|
||||||
|
BROWSER_PLAYER,
|
||||||
|
MediaPlayerEntity,
|
||||||
|
MediaPlayerItem,
|
||||||
|
SUPPORT_PAUSE,
|
||||||
|
SUPPORT_PLAY,
|
||||||
|
} from "../../data/media-player";
|
||||||
|
import { resolveMediaSource } from "../../data/media_source";
|
||||||
|
import { HomeAssistant } from "../../types";
|
||||||
|
|
||||||
|
export class BrowserMediaPlayer {
|
||||||
|
private player?: HTMLAudioElement;
|
||||||
|
|
||||||
|
private stopped = false;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public hass: HomeAssistant,
|
||||||
|
private item: MediaPlayerItem,
|
||||||
|
private onChange: () => void
|
||||||
|
) {}
|
||||||
|
|
||||||
|
public async initialize() {
|
||||||
|
const resolvedUrl: any = await resolveMediaSource(
|
||||||
|
this.hass,
|
||||||
|
this.item.media_content_id
|
||||||
|
);
|
||||||
|
|
||||||
|
const player = new Audio(resolvedUrl.url);
|
||||||
|
player.addEventListener("play", this._handleChange);
|
||||||
|
player.addEventListener("playing", this._handleChange);
|
||||||
|
player.addEventListener("pause", this._handleChange);
|
||||||
|
player.addEventListener("ended", this._handleChange);
|
||||||
|
player.addEventListener("canplaythrough", () => {
|
||||||
|
if (this.stopped) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.player = player;
|
||||||
|
player.play();
|
||||||
|
this.onChange();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private _handleChange = () => {
|
||||||
|
if (!this.stopped) {
|
||||||
|
this.onChange();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public pause() {
|
||||||
|
if (this.player) {
|
||||||
|
this.player.pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public play() {
|
||||||
|
if (this.player) {
|
||||||
|
this.player.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public stop() {
|
||||||
|
this.stopped = true;
|
||||||
|
// @ts-ignore
|
||||||
|
this.onChange = undefined;
|
||||||
|
if (this.player) {
|
||||||
|
this.player.pause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isPlaying(): boolean {
|
||||||
|
return (
|
||||||
|
this.player !== undefined && !this.player.paused && !this.player.ended
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
static idleStateObj(): MediaPlayerEntity {
|
||||||
|
const now = new Date().toISOString();
|
||||||
|
return {
|
||||||
|
state: "idle",
|
||||||
|
entity_id: BROWSER_PLAYER,
|
||||||
|
last_changed: now,
|
||||||
|
last_updated: now,
|
||||||
|
attributes: {},
|
||||||
|
context: { id: "", user_id: null },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
toStateObj(): MediaPlayerEntity {
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement
|
||||||
|
const base = BrowserMediaPlayer.idleStateObj();
|
||||||
|
if (!this.player) {
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
base.state = this.isPlaying ? "playing" : "paused";
|
||||||
|
base.attributes = {
|
||||||
|
media_title: this.item.title,
|
||||||
|
media_duration: this.player.duration,
|
||||||
|
media_position: this.player.currentTime,
|
||||||
|
media_position_updated_at: base.last_updated,
|
||||||
|
entity_picture: this.item.thumbnail,
|
||||||
|
// eslint-disable-next-line no-bitwise
|
||||||
|
supported_features: SUPPORT_PLAY | SUPPORT_PAUSE,
|
||||||
|
};
|
||||||
|
return base;
|
||||||
|
}
|
||||||
|
}
|
@ -36,6 +36,7 @@ import {
|
|||||||
formatMediaTime,
|
formatMediaTime,
|
||||||
getCurrentProgress,
|
getCurrentProgress,
|
||||||
MediaPlayerEntity,
|
MediaPlayerEntity,
|
||||||
|
MediaPlayerItem,
|
||||||
SUPPORT_BROWSE_MEDIA,
|
SUPPORT_BROWSE_MEDIA,
|
||||||
SUPPORT_PAUSE,
|
SUPPORT_PAUSE,
|
||||||
SUPPORT_PLAY,
|
SUPPORT_PLAY,
|
||||||
@ -43,6 +44,7 @@ import {
|
|||||||
} from "../../data/media-player";
|
} from "../../data/media-player";
|
||||||
import type { HomeAssistant } from "../../types";
|
import type { HomeAssistant } from "../../types";
|
||||||
import "../lovelace/components/hui-marquee";
|
import "../lovelace/components/hui-marquee";
|
||||||
|
import { BrowserMediaPlayer } from "./browser-media-player";
|
||||||
|
|
||||||
@customElement("ha-bar-media-player")
|
@customElement("ha-bar-media-player")
|
||||||
class BarMediaPlayer extends LitElement {
|
class BarMediaPlayer extends LitElement {
|
||||||
@ -59,6 +61,8 @@ class BarMediaPlayer extends LitElement {
|
|||||||
|
|
||||||
@state() private _marqueeActive = false;
|
@state() private _marqueeActive = false;
|
||||||
|
|
||||||
|
@state() private _browserPlayer?: BrowserMediaPlayer;
|
||||||
|
|
||||||
private _progressInterval?: number;
|
private _progressInterval?: number;
|
||||||
|
|
||||||
public connectedCallback(): void {
|
public connectedCallback(): void {
|
||||||
@ -87,73 +91,28 @@ class BarMediaPlayer extends LitElement {
|
|||||||
clearInterval(this._progressInterval);
|
clearInterval(this._progressInterval);
|
||||||
this._progressInterval = undefined;
|
this._progressInterval = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this._browserPlayer) {
|
||||||
|
this._browserPlayer.stop();
|
||||||
|
this._browserPlayer = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async playItem(item: MediaPlayerItem) {
|
||||||
|
if (this.entityId !== BROWSER_PLAYER) {
|
||||||
|
throw Error("Only browser supported");
|
||||||
|
}
|
||||||
|
if (this._browserPlayer) {
|
||||||
|
this._browserPlayer.stop();
|
||||||
|
}
|
||||||
|
this._browserPlayer = new BrowserMediaPlayer(this.hass, item, () =>
|
||||||
|
this.requestUpdate("_browserPlayer")
|
||||||
|
);
|
||||||
|
await this._browserPlayer.initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
const choosePlayerElement = html`
|
const isBrowser = this.entityId === BROWSER_PLAYER;
|
||||||
<div
|
|
||||||
class="choose-player ${this.entityId === BROWSER_PLAYER
|
|
||||||
? "browser"
|
|
||||||
: ""}"
|
|
||||||
>
|
|
||||||
<ha-button-menu corner="BOTTOM_START">
|
|
||||||
${this.narrow
|
|
||||||
? html`
|
|
||||||
<ha-icon-button
|
|
||||||
slot="trigger"
|
|
||||||
.path=${this._stateObj
|
|
||||||
? domainIcon(computeDomain(this.entityId), this._stateObj)
|
|
||||||
: mdiMonitor}
|
|
||||||
></ha-icon-button>
|
|
||||||
`
|
|
||||||
: html`
|
|
||||||
<mwc-button
|
|
||||||
slot="trigger"
|
|
||||||
.label=${this.narrow
|
|
||||||
? ""
|
|
||||||
: `${
|
|
||||||
this._stateObj
|
|
||||||
? computeStateName(this._stateObj)
|
|
||||||
: BROWSER_PLAYER
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<ha-svg-icon
|
|
||||||
slot="icon"
|
|
||||||
.path=${this._stateObj
|
|
||||||
? domainIcon(computeDomain(this.entityId), this._stateObj)
|
|
||||||
: mdiMonitor}
|
|
||||||
></ha-svg-icon>
|
|
||||||
<ha-svg-icon
|
|
||||||
slot="trailingIcon"
|
|
||||||
.path=${mdiChevronDown}
|
|
||||||
></ha-svg-icon>
|
|
||||||
</mwc-button>
|
|
||||||
`}
|
|
||||||
<mwc-list-item .player=${BROWSER_PLAYER} @click=${this._selectPlayer}
|
|
||||||
>${this.hass.localize(
|
|
||||||
"ui.components.media-browser.web-browser"
|
|
||||||
)}</mwc-list-item
|
|
||||||
>
|
|
||||||
${this._mediaPlayerEntities.map(
|
|
||||||
(source) => html`
|
|
||||||
<mwc-list-item
|
|
||||||
?selected=${source.entity_id === this.entityId}
|
|
||||||
.disabled=${UNAVAILABLE_STATES.includes(source.state)}
|
|
||||||
.player=${source.entity_id}
|
|
||||||
@click=${this._selectPlayer}
|
|
||||||
>${computeStateName(source)}</mwc-list-item
|
|
||||||
>
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
</ha-button-menu>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
if (!this._stateObj) {
|
|
||||||
return choosePlayerElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
const stateObj = this._stateObj;
|
const stateObj = this._stateObj;
|
||||||
const controls = !this.narrow
|
const controls = !this.narrow
|
||||||
? computeMediaControls(stateObj)
|
? computeMediaControls(stateObj)
|
||||||
@ -188,13 +147,13 @@ class BarMediaPlayer extends LitElement {
|
|||||||
const mediaDuration = formatMediaTime(stateObj!.attributes.media_duration!);
|
const mediaDuration = formatMediaTime(stateObj!.attributes.media_duration!);
|
||||||
const mediaTitleClean = cleanupMediaTitle(stateObj.attributes.media_title);
|
const mediaTitleClean = cleanupMediaTitle(stateObj.attributes.media_title);
|
||||||
|
|
||||||
|
const mediaArt =
|
||||||
|
stateObj.attributes.entity_picture_local ||
|
||||||
|
stateObj.attributes.entity_picture;
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<div class="info">
|
<div class="info">
|
||||||
${this._image
|
${mediaArt ? html`<img src=${this.hass.hassUrl(mediaArt)} />` : ""}
|
||||||
? html`<img src=${this.hass.hassUrl(this._image)} />`
|
|
||||||
: stateObj.state === "off" || stateObj.state !== "playing"
|
|
||||||
? html`<div class="blank-image"></div>`
|
|
||||||
: ""}
|
|
||||||
<div class="media-info">
|
<div class="media-info">
|
||||||
<hui-marquee
|
<hui-marquee
|
||||||
.text=${mediaTitleClean ||
|
.text=${mediaTitleClean ||
|
||||||
@ -211,19 +170,21 @@ class BarMediaPlayer extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
<div class="controls-progress">
|
<div class="controls-progress">
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
${controls!.map(
|
${controls === undefined
|
||||||
(control) => html`
|
? ""
|
||||||
<ha-icon-button
|
: controls.map(
|
||||||
.label=${this.hass.localize(
|
(control) => html`
|
||||||
`ui.card.media_player.${control.action}`
|
<ha-icon-button
|
||||||
)}
|
.label=${this.hass.localize(
|
||||||
.path=${control.icon}
|
`ui.card.media_player.${control.action}`
|
||||||
action=${control.action}
|
)}
|
||||||
@click=${this._handleClick}
|
.path=${control.icon}
|
||||||
>
|
action=${control.action}
|
||||||
</ha-icon-button>
|
@click=${this._handleClick}
|
||||||
`
|
>
|
||||||
)}
|
</ha-icon-button>
|
||||||
|
`
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
${this.narrow
|
${this.narrow
|
||||||
? html`<mwc-linear-progress></mwc-linear-progress>`
|
? html`<mwc-linear-progress></mwc-linear-progress>`
|
||||||
@ -235,13 +196,85 @@ class BarMediaPlayer extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
`}
|
`}
|
||||||
</div>
|
</div>
|
||||||
${choosePlayerElement}
|
<div class="choose-player ${isBrowser ? "browser" : ""}">
|
||||||
|
<ha-button-menu corner="BOTTOM_START">
|
||||||
|
${this.narrow
|
||||||
|
? html`
|
||||||
|
<ha-icon-button
|
||||||
|
slot="trigger"
|
||||||
|
.path=${isBrowser
|
||||||
|
? mdiMonitor
|
||||||
|
: domainIcon(computeDomain(this.entityId), stateObj)}
|
||||||
|
></ha-icon-button>
|
||||||
|
`
|
||||||
|
: html`
|
||||||
|
<mwc-button
|
||||||
|
slot="trigger"
|
||||||
|
.label=${this.narrow
|
||||||
|
? ""
|
||||||
|
: `${computeStateName(stateObj)}
|
||||||
|
`}
|
||||||
|
>
|
||||||
|
<ha-svg-icon
|
||||||
|
slot="icon"
|
||||||
|
.path=${isBrowser
|
||||||
|
? mdiMonitor
|
||||||
|
: domainIcon(computeDomain(this.entityId), stateObj)}
|
||||||
|
></ha-svg-icon>
|
||||||
|
<ha-svg-icon
|
||||||
|
slot="trailingIcon"
|
||||||
|
.path=${mdiChevronDown}
|
||||||
|
></ha-svg-icon>
|
||||||
|
</mwc-button>
|
||||||
|
`}
|
||||||
|
<mwc-list-item
|
||||||
|
.player=${BROWSER_PLAYER}
|
||||||
|
?selected=${isBrowser}
|
||||||
|
@click=${this._selectPlayer}
|
||||||
|
>
|
||||||
|
${this.hass.localize("ui.components.media-browser.web-browser")}
|
||||||
|
</mwc-list-item>
|
||||||
|
${this._mediaPlayerEntities.map(
|
||||||
|
(source) => html`
|
||||||
|
<mwc-list-item
|
||||||
|
?selected=${source.entity_id === this.entityId}
|
||||||
|
.disabled=${UNAVAILABLE_STATES.includes(source.state)}
|
||||||
|
.player=${source.entity_id}
|
||||||
|
@click=${this._selectPlayer}
|
||||||
|
>
|
||||||
|
${computeStateName(source)}
|
||||||
|
</mwc-list-item>
|
||||||
|
`
|
||||||
|
)}
|
||||||
|
</ha-button-menu>
|
||||||
|
</div>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public willUpdate(changedProps: PropertyValues) {
|
||||||
|
super.willUpdate(changedProps);
|
||||||
|
if (
|
||||||
|
changedProps.has("entityId") &&
|
||||||
|
this.entityId !== BROWSER_PLAYER &&
|
||||||
|
this._browserPlayer
|
||||||
|
) {
|
||||||
|
this._browserPlayer?.stop();
|
||||||
|
this._browserPlayer = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected updated(changedProps: PropertyValues) {
|
protected updated(changedProps: PropertyValues) {
|
||||||
if (!this.hass || !this._stateObj || !changedProps.has("hass")) {
|
super.updated(changedProps);
|
||||||
return;
|
|
||||||
|
if (this.entityId === BROWSER_PLAYER) {
|
||||||
|
if (!changedProps.has("_browserPlayer")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const oldHass = changedProps.get("hass") as HomeAssistant | undefined;
|
||||||
|
if (oldHass && oldHass.states[this.entityId] === this._stateObj) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const stateObj = this._stateObj;
|
const stateObj = this._stateObj;
|
||||||
@ -266,8 +299,14 @@ class BarMediaPlayer extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private get _stateObj(): MediaPlayerEntity | undefined {
|
private get _stateObj(): MediaPlayerEntity {
|
||||||
return this.hass!.states[this.entityId] as MediaPlayerEntity;
|
if (this._browserPlayer) {
|
||||||
|
return this._browserPlayer.toStateObj();
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
(this.hass!.states[this.entityId] as MediaPlayerEntity | undefined) ||
|
||||||
|
BrowserMediaPlayer.idleStateObj()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private get _showProgressBar() {
|
private get _showProgressBar() {
|
||||||
@ -277,10 +316,6 @@ class BarMediaPlayer extends LitElement {
|
|||||||
|
|
||||||
const stateObj = this._stateObj;
|
const stateObj = this._stateObj;
|
||||||
|
|
||||||
if (!stateObj) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
(stateObj.state === "playing" || stateObj.state === "paused") &&
|
(stateObj.state === "playing" || stateObj.state === "paused") &&
|
||||||
"media_duration" in stateObj.attributes &&
|
"media_duration" in stateObj.attributes &&
|
||||||
@ -288,53 +323,48 @@ class BarMediaPlayer extends LitElement {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private get _image() {
|
private get _mediaPlayerEntities() {
|
||||||
if (!this.hass) {
|
return Object.values(this.hass!.states).filter(
|
||||||
return undefined;
|
(entity) =>
|
||||||
}
|
computeStateDomain(entity) === "media_player" &&
|
||||||
|
supportsFeature(entity, SUPPORT_BROWSE_MEDIA)
|
||||||
const stateObj = this._stateObj;
|
|
||||||
|
|
||||||
if (!stateObj) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
stateObj.attributes.entity_picture_local ||
|
|
||||||
stateObj.attributes.entity_picture
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private get _mediaPlayerEntities() {
|
|
||||||
return Object.values(this.hass!.states).filter((entity) => {
|
|
||||||
if (
|
|
||||||
computeStateDomain(entity) === "media_player" &&
|
|
||||||
supportsFeature(entity, SUPPORT_BROWSE_MEDIA)
|
|
||||||
) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private _updateProgressBar(): void {
|
private _updateProgressBar(): void {
|
||||||
if (this._progressBar && this._stateObj?.attributes.media_duration) {
|
if (!this._progressBar || !this._currentProgress) {
|
||||||
const currentProgress = getCurrentProgress(this._stateObj);
|
return;
|
||||||
this._progressBar.progress =
|
}
|
||||||
currentProgress / this._stateObj!.attributes.media_duration;
|
|
||||||
|
|
||||||
if (this._currentProgress) {
|
if (!this._stateObj.attributes.media_duration) {
|
||||||
this._currentProgress.innerHTML = formatMediaTime(currentProgress);
|
this._progressBar.progress = 0;
|
||||||
}
|
this._currentProgress.innerHTML = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentProgress = getCurrentProgress(this._stateObj);
|
||||||
|
this._progressBar.progress =
|
||||||
|
currentProgress / this._stateObj.attributes.media_duration;
|
||||||
|
|
||||||
|
if (this._currentProgress) {
|
||||||
|
this._currentProgress.innerHTML = formatMediaTime(currentProgress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleClick(e: MouseEvent): void {
|
private _handleClick(e: MouseEvent): void {
|
||||||
const action = (e.currentTarget! as HTMLElement).getAttribute("action")!;
|
const action = (e.currentTarget! as HTMLElement).getAttribute("action")!;
|
||||||
this.hass!.callService("media_player", action, {
|
|
||||||
entity_id: this.entityId,
|
if (!this._browserPlayer) {
|
||||||
});
|
this.hass!.callService("media_player", action, {
|
||||||
|
entity_id: this.entityId,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (action === "media_pause") {
|
||||||
|
this._browserPlayer.pause();
|
||||||
|
} else if (action === "media_play") {
|
||||||
|
this._browserPlayer.play();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _marqueeMouseOver(): void {
|
private _marqueeMouseOver(): void {
|
||||||
@ -401,6 +431,10 @@ class BarMediaPlayer extends LitElement {
|
|||||||
padding: 16px;
|
padding: 16px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
height: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
.controls-progress {
|
.controls-progress {
|
||||||
flex: 2;
|
flex: 2;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -436,12 +470,6 @@ class BarMediaPlayer extends LitElement {
|
|||||||
max-height: 100px;
|
max-height: 100px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.blank-image {
|
|
||||||
height: 100px;
|
|
||||||
width: 100px;
|
|
||||||
background-color: var(--divider-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
ha-button-menu mwc-button {
|
ha-button-menu mwc-button {
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
@ -487,6 +515,10 @@ class BarMediaPlayer extends LitElement {
|
|||||||
top: -4px;
|
top: -4px;
|
||||||
left: 0;
|
left: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mwc-list-item[selected] {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import "../../components/ha-menu-button";
|
|||||||
import "../../components/media-player/ha-media-player-browse";
|
import "../../components/media-player/ha-media-player-browse";
|
||||||
import type { MediaPlayerItemId } from "../../components/media-player/ha-media-player-browse";
|
import type { MediaPlayerItemId } from "../../components/media-player/ha-media-player-browse";
|
||||||
import { BROWSER_PLAYER, MediaPickedEvent } from "../../data/media-player";
|
import { BROWSER_PLAYER, MediaPickedEvent } from "../../data/media-player";
|
||||||
|
import { resolveMediaSource } from "../../data/media_source";
|
||||||
import "../../layouts/ha-app-layout";
|
import "../../layouts/ha-app-layout";
|
||||||
import { haStyle } from "../../resources/styles";
|
import { haStyle } from "../../resources/styles";
|
||||||
import type { HomeAssistant, Route } from "../../types";
|
import type { HomeAssistant, Route } from "../../types";
|
||||||
@ -131,25 +132,28 @@ class PanelMediaBrowser extends LitElement {
|
|||||||
ev: HASSDomEvent<MediaPickedEvent>
|
ev: HASSDomEvent<MediaPickedEvent>
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const item = ev.detail.item;
|
const item = ev.detail.item;
|
||||||
if (this._entityId === BROWSER_PLAYER) {
|
if (this._entityId !== BROWSER_PLAYER) {
|
||||||
const resolvedUrl: any = await this.hass.callWS({
|
this.hass!.callService("media_player", "play_media", {
|
||||||
type: "media_source/resolve_media",
|
entity_id: this._entityId,
|
||||||
media_content_id: item.media_content_id,
|
media_content_id: item.media_content_id,
|
||||||
|
media_content_type: item.media_content_type,
|
||||||
});
|
});
|
||||||
|
} else if (item.media_content_type.startsWith("audio/")) {
|
||||||
|
await this.shadowRoot!.querySelector("ha-bar-media-player")!.playItem(
|
||||||
|
item
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
const resolvedUrl: any = await resolveMediaSource(
|
||||||
|
this.hass,
|
||||||
|
item.media_content_id
|
||||||
|
);
|
||||||
|
|
||||||
showWebBrowserPlayMediaDialog(this, {
|
showWebBrowserPlayMediaDialog(this, {
|
||||||
sourceUrl: resolvedUrl.url,
|
sourceUrl: resolvedUrl.url,
|
||||||
sourceType: resolvedUrl.mime_type,
|
sourceType: resolvedUrl.mime_type,
|
||||||
title: item.title,
|
title: item.title,
|
||||||
});
|
});
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.hass!.callService("media_player", "play_media", {
|
|
||||||
entity_id: this._entityId,
|
|
||||||
media_content_id: item.media_content_id,
|
|
||||||
media_content_type: item.media_content_type,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResultGroup {
|
static get styles(): CSSResultGroup {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user