From d2e9e22e4e0e8aadd5572bd6cd9b391035359744 Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Wed, 30 Sep 2020 10:24:38 +0200 Subject: [PATCH] Add media player to cast app (#7160) Co-authored-by: Paulus Schoutsen --- cast/src/receiver/entrypoint.ts | 101 ++++++++++++++++++++++++++-- cast/src/receiver/layout/hc-main.ts | 15 +---- package.json | 2 +- yarn.lock | 8 +-- 4 files changed, 103 insertions(+), 23 deletions(-) diff --git a/cast/src/receiver/entrypoint.ts b/cast/src/receiver/entrypoint.ts index c52c137048..2807d597a7 100644 --- a/cast/src/receiver/entrypoint.ts +++ b/cast/src/receiver/entrypoint.ts @@ -6,13 +6,58 @@ import { castContext } from "./cast_context"; import { HcMain } from "./layout/hc-main"; import { ReceivedMessage } from "./types"; -const controller = new HcMain(); -document.body.append(controller); +const lovelaceController = new HcMain(); +document.body.append(lovelaceController); + +const mediaPlayer = document.createElement("cast-media-player"); +mediaPlayer.style.display = "none"; +document.body.append(mediaPlayer); +const playerStylesAdded = false; + +let controls: HTMLElement | null; + +const setTouchControlsVisibility = (visible: boolean) => { + if (!castContext.getDeviceCapabilities().touch_input_supported) { + return; + } + controls = + controls || + (document.body.querySelector("touch-controls") as HTMLElement | null); + if (controls) { + controls.style.display = visible ? "initial" : "none"; + } +}; + +const showLovelaceController = () => { + mediaPlayer.style.display = "none"; + lovelaceController.style.display = "initial"; + document.body.setAttribute("style", "overflow-y: auto !important"); + setTouchControlsVisibility(false); +}; + +const showMediaPlayer = () => { + lovelaceController.style.display = "none"; + mediaPlayer.style.display = "initial"; + document.body.removeAttribute("style"); + setTouchControlsVisibility(true); + if (!playerStylesAdded) { + const style = document.createElement("style"); + style.innerHTML = ` + body { + --logo-image: url('https://www.home-assistant.io/images/home-assistant-logo.svg'); + --theme-hue: 200; + --progress-color: #03a9f4; + --splash-image: url('https://home-assistant.io/images/cast/splash.png'); + --splash-size: cover; + } + `; + document.head.appendChild(style); + } +}; const options = new cast.framework.CastReceiverOptions(); options.disableIdleTimeout = true; options.customNamespaces = { - // @ts-ignore [CAST_NS]: cast.framework.system.MessageType.JSON, }; @@ -30,13 +75,61 @@ options.uiConfig = new cast.framework.ui.UiConfig(); // @ts-ignore options.uiConfig.touchScreenOptimizedApp = true; +castContext.setInactivityTimeout(86400); // 1 day + castContext.addCustomMessageListener( CAST_NS, // @ts-ignore (ev: ReceivedMessage) => { + // We received a show Lovelace command, stop media from playing, hide media player and show Lovelace controller + if ( + playerManager.getPlayerState() !== + cast.framework.messages.PlayerState.IDLE + ) { + playerManager.stop(); + } else { + showLovelaceController(); + } const msg = ev.data; msg.senderId = ev.senderId; - controller.processIncomingMessage(msg); + lovelaceController.processIncomingMessage(msg); + } +); + +const playerManager = castContext.getPlayerManager(); + +playerManager.setMessageInterceptor( + cast.framework.messages.MessageType.LOAD, + (loadRequestData) => { + // We received a play media command, hide Lovelace and show media player + showMediaPlayer(); + const media = loadRequestData.media; + // Special handling if it came from Google Assistant + if (media.entity) { + media.contentId = media.entity; + media.streamType = cast.framework.messages.StreamType.LIVE; + media.contentType = "application/vnd.apple.mpegurl"; + // @ts-ignore + media.hlsVideoSegmentFormat = + cast.framework.messages.HlsVideoSegmentFormat.FMP4; + } + return loadRequestData; + } +); + +playerManager.addEventListener( + cast.framework.events.EventType.MEDIA_STATUS, + (event) => { + if ( + event.mediaStatus?.playerState === + cast.framework.messages.PlayerState.IDLE && + event.mediaStatus?.idleReason && + event.mediaStatus?.idleReason !== + cast.framework.messages.IdleReason.INTERRUPTED + ) { + // media finished or stopped, return to default Lovelace + showLovelaceController(); + } } ); diff --git a/cast/src/receiver/layout/hc-main.ts b/cast/src/receiver/layout/hc-main.ts index 03abab575b..e035d5dd4e 100644 --- a/cast/src/receiver/layout/hc-main.ts +++ b/cast/src/receiver/layout/hc-main.ts @@ -216,9 +216,7 @@ export class HcMain extends HassElement { } this._showDemo = false; this._lovelacePath = msg.viewPath; - if (castContext.getDeviceCapabilities().touch_input_supported) { - this._breakFree(); - } + this._sendStatus(); } @@ -241,9 +239,6 @@ export class HcMain extends HassElement { this._showDemo = true; this._lovelacePath = "overview"; this._sendStatus(); - if (castContext.getDeviceCapabilities().touch_input_supported) { - this._breakFree(); - } }); } @@ -264,14 +259,6 @@ export class HcMain extends HassElement { } } - private _breakFree() { - const controls = document.body.querySelector("touch-controls"); - if (controls) { - controls.remove(); - } - document.body.setAttribute("style", "overflow-y: auto !important"); - } - private sendMessage(senderId: string, response: any) { castContext.sendCustomMessage(CAST_NS, senderId, response); } diff --git a/package.json b/package.json index d52dbfd9e6..e176dd4e88 100644 --- a/package.json +++ b/package.json @@ -143,7 +143,7 @@ "@rollup/plugin-node-resolve": "^7.1.3", "@rollup/plugin-replace": "^2.3.2", "@types/chai": "^4.1.7", - "@types/chromecast-caf-receiver": "^3.0.12", + "@types/chromecast-caf-receiver": "^5.0.11", "@types/codemirror": "^0.0.97", "@types/hls.js": "^0.12.3", "@types/js-yaml": "^3.12.1", diff --git a/yarn.lock b/yarn.lock index f50c0810aa..e5b1db760f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2547,10 +2547,10 @@ "@types/filesystem" "*" "@types/har-format" "*" -"@types/chromecast-caf-receiver@^3.0.12": - version "3.0.17" - resolved "https://registry.yarnpkg.com/@types/chromecast-caf-receiver/-/chromecast-caf-receiver-3.0.17.tgz#adc791f501cd8940e5b328c038b9164bf7d07f04" - integrity sha512-hQeEPuK1rM9q7pMdcsjrEy0MgTxnHWbmc+fDiZ/anbp4jLi/hdmG5uWKYepeCq7XOE0p8oSN93V/HfGqUJLzDg== +"@types/chromecast-caf-receiver@^5.0.11": + version "5.0.11" + resolved "https://registry.yarnpkg.com/@types/chromecast-caf-receiver/-/chromecast-caf-receiver-5.0.11.tgz#072aa84363392d83284d4ce091ea51ed588bbe38" + integrity sha512-c5FMxW5rzSZsqy0BU9yrsvZvkBCRFskE3V3jDPK595v6JKa8b1CoS8okXihHji7T2mrZYRUZeImpKe7kLr75lQ== "@types/chromecast-caf-sender@^1.0.3": version "1.0.3"