diff --git a/src/components/media-player/ha-media-player-browse.ts b/src/components/media-player/ha-media-player-browse.ts index df10572558..8f54e1204c 100644 --- a/src/components/media-player/ha-media-player-browse.ts +++ b/src/components/media-player/ha-media-player-browse.ts @@ -68,6 +68,8 @@ export class HaMediaPlayerBrowse extends LitElement { @internalProperty() private _loading = false; + @internalProperty() private _error?: { message: string; code: string }; + @internalProperty() private _mediaPlayerItems: MediaPlayerItem[] = []; private _resizeObserver?: ResizeObserver; @@ -92,11 +94,55 @@ export class HaMediaPlayerBrowse extends LitElement { this._navigate(item); } + private _renderError(err: { message: string; code: string }) { + if (err.message === "Media directory does not exist.") { + return html` +

No local media found.

+

+ It looks like you have not yet created a media directory. +
Create a directory with the name "media" in the + configuration directory of Home Assistant + (${this.hass.config.config_dir}).
Place your video, audio and + image files in this directory to be able to browse and play them in + the browser or on supported media players. +

+ +

+ Check the + documentation + for more info +

+ `; + } + return err.message; + } + protected render(): TemplateResult { if (this._loading) { return html``; } + if (this._error && !this._mediaPlayerItems.length) { + if (this.dialog) { + this._closeDialogAction(); + showAlertDialog(this, { + title: this.hass.localize( + "ui.components.media-browser.media_browsing_error" + ), + text: this._renderError(this._error), + }); + } else { + return html`
+ ${this._renderError(this._error)} +
`; + } + } + if (!this._mediaPlayerItems.length) { return html``; } @@ -216,7 +262,11 @@ export class HaMediaPlayerBrowse extends LitElement { ` : ""} - ${currentItem.children?.length + ${this._error + ? html`
+ ${this._renderError(this._error)} +
` + : currentItem.children?.length ? hasExpandableChildren ? html`
@@ -316,7 +366,9 @@ export class HaMediaPlayerBrowse extends LitElement { )} ` - : this.hass.localize("ui.components.media-browser.no_items")} + : html`
+ ${this.hass.localize("ui.components.media-browser.no_items")} +
`} `; } @@ -342,15 +394,22 @@ export class HaMediaPlayerBrowse extends LitElement { return; } - this._fetchData(this.mediaContentId, this.mediaContentType).then( - (itemData) => { + if (changedProps.has("entityId")) { + this._error = undefined; + this._mediaPlayerItems = []; + } + + this._fetchData(this.mediaContentId, this.mediaContentType) + .then((itemData) => { if (!itemData) { return; } this._mediaPlayerItems = [itemData]; - } - ); + }) + .catch((err) => { + this._error = err; + }); } private _actionClicked(ev: MouseEvent): void { @@ -381,12 +440,22 @@ export class HaMediaPlayerBrowse extends LitElement { } private async _navigate(item: MediaPlayerItem) { - const itemData = await this._fetchData( - item.media_content_id, - item.media_content_type - ); + this._error = undefined; - if (!itemData) { + let itemData: MediaPlayerItem; + + try { + itemData = await this._fetchData( + item.media_content_id, + item.media_content_type + ); + } catch (err) { + showAlertDialog(this, { + title: this.hass.localize( + "ui.components.media-browser.media_browsing_error" + ), + text: this._renderError(err), + }); return; } @@ -397,33 +466,23 @@ export class HaMediaPlayerBrowse extends LitElement { private async _fetchData( mediaContentId?: string, mediaContentType?: string - ): Promise { - let itemData: MediaPlayerItem | undefined; - try { - itemData = - this.entityId !== BROWSER_SOURCE - ? await browseMediaPlayer( - this.hass, - this.entityId, - mediaContentId, - mediaContentType - ) - : await browseLocalMediaPlayer(this.hass, mediaContentId); - itemData.children = itemData.children?.sort((first, second) => - !first.can_expand && second.can_expand - ? 1 - : first.can_expand && !second.can_expand - ? -1 - : compare(first.title, second.title) - ); - } catch (error) { - showAlertDialog(this, { - title: this.hass.localize( - "ui.components.media-browser.media_browsing_error" - ), - text: error.message, - }); - } + ): Promise { + const itemData = + this.entityId !== BROWSER_SOURCE + ? await browseMediaPlayer( + this.hass, + this.entityId, + mediaContentId, + mediaContentType + ) + : await browseLocalMediaPlayer(this.hass, mediaContentId); + itemData.children = itemData.children?.sort((first, second) => + !first.can_expand && second.can_expand + ? 1 + : first.can_expand && !second.can_expand + ? -1 + : compare(first.title, second.title) + ); return itemData; } @@ -451,8 +510,8 @@ export class HaMediaPlayerBrowse extends LitElement { this._resizeObserver.observe(this); } - private _hasExpandableChildren = memoizeOne((children) => - children.find((item: MediaPlayerItem) => item.can_expand) + private _hasExpandableChildren = memoizeOne((children?: MediaPlayerItem[]) => + children?.find((item: MediaPlayerItem) => item.can_expand) ); private _closeDialogAction(): void { @@ -471,6 +530,10 @@ export class HaMediaPlayerBrowse extends LitElement { flex-direction: column; } + .container { + padding: 16px; + } + .header { display: flex; justify-content: space-between;