From 3e704e97d1ba12f695b6d20b1ce7b500999795e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Lov=C3=A9n?= Date: Thu, 27 Jun 2019 11:10:10 +0200 Subject: [PATCH] Player controlls working --- custom_components/browser_mod/browser_mod.js | 2 +- custom_components/browser_mod/connection.py | 5 +- custom_components/browser_mod/media_player.py | 33 ++++++---- js/main.js | 63 ++++++++++++++++++- 4 files changed, 84 insertions(+), 19 deletions(-) diff --git a/custom_components/browser_mod/browser_mod.js b/custom_components/browser_mod/browser_mod.js index 5c492f8..b498437 100644 --- a/custom_components/browser_mod/browser_mod.js +++ b/custom_components/browser_mod/browser_mod.js @@ -1 +1 @@ -!function(e){var o={};function n(t){if(o[t])return o[t].exports;var r=o[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,n),r.l=!0,r.exports}n.m=e,n.c=o,n.d=function(e,o,t){n.o(e,o)||Object.defineProperty(e,o,{enumerable:!0,get:t})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,o){if(1&o&&(e=n(e)),8&o)return e;if(4&o&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(n.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&o&&"string"!=typeof e)for(var r in e)n.d(t,r,function(o){return e[o]}.bind(null,r));return t},n.n=function(e){var o=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(o,"a",o),o},n.o=function(e,o){return Object.prototype.hasOwnProperty.call(e,o)},n.p="",n(n.s=0)}([function(e,o,n){"use strict";n.r(o);let t=function(){if(window.fully&&"function"==typeof fully.getDeviceId)return fully.getDeviceId();if(!localStorage["lovelace-player-device-id"]){const e=()=>Math.floor(1e5*(1+Math.random())).toString(16).substring(1);localStorage["lovelace-player-device-id"]=`${e()}${e()}-${e()}${e()}`}return localStorage["lovelace-player-device-id"]}();window.browser_mod=new class{constructor(){window.hassConnection.then(e=>this.connect(e.conn))}connect(e){console.log("Connection opened. Connecting to browser_mod"),this.conn=e,e.subscribeMessage(e=>this.callback(e),{type:"browser_mod/connect",deviceID:t}),console.log("Connected"),console.log(this.connection)}callback(e){console.log("Got ws message"),console.log(e),"update"===e.command&&this.update()}update(){this.conn&&this.conn.sendMessage({type:"browser_mod/update",deviceID:t,data:{browser:{},player:{state:"idle"}}})}}}]); \ No newline at end of file +!function(e){var t={};function n(o){if(t[o])return t[o].exports;var r=t[o]={i:o,l:!1,exports:{}};return e[o].call(r.exports,r,r.exports,n),r.l=!0,r.exports}n.m=e,n.c=t,n.d=function(e,t,o){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:o})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var o=Object.create(null);if(n.r(o),Object.defineProperty(o,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var r in e)n.d(o,r,function(t){return e[t]}.bind(null,r));return o},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){"use strict";n.r(t);let o=function(){if(window.fully&&"function"==typeof fully.getDeviceId)return fully.getDeviceId();if(!localStorage["lovelace-player-device-id"]){const e=()=>Math.floor(1e5*(1+Math.random())).toString(16).substring(1);localStorage["lovelace-player-device-id"]=`${e()}${e()}-${e()}${e()}`}return localStorage["lovelace-player-device-id"]}();window.browser_mod=new class{constructor(){window.hassConnection.then(e=>this.connect(e.conn)),this.player=new Audio,this.player.addEventListener("ended",this.update.bind(this)),this.player.addEventListener("play",this.update.bind(this)),this.player.addEventListener("pause",this.update.bind(this)),this.player.addEventListener("volumechange",this.update.bind(this))}connect(e){console.log("Connection opened. Connecting to browser_mod"),this.conn=e,e.subscribeMessage(e=>this.callback(e),{type:"browser_mod/connect",deviceID:o}),console.log("Connected"),console.log(this.connection)}callback(e){switch(console.log("Got ws message"),console.log(e),e.command){case"update":this.update(e);break;case"play":this.play(e);break;case"pause":this.pause(e);break;case"stop":this.stop(e);break;case"set_volume":this.set_volume(e);break;case"mute":this.mute(e)}}get player_state(){return this.player.src?this.player.ended?"stopped":this.player.paused?"paused":"playing":"stopped"}play(e){const t=e.media_content_id;t&&(this.player.src=t),this.player.play()}pause(e){this.player.pause()}stop(e){this.player.pause(),this.player.src=null}set_volume(e){void 0!==e.volume_level&&(this.player.volume=e.volume_level)}mute(e){this.player.muted=Boolean(e.mute)}update(){this.conn&&this.conn.sendMessage({type:"browser_mod/update",deviceID:o,data:{browser:{},player:{volume:this.player.volume,muted:this.player.muted,src:this.player.src,state:this.player_state}}})}}}]); \ No newline at end of file diff --git a/custom_components/browser_mod/connection.py b/custom_components/browser_mod/connection.py index 6daa447..c746ff7 100644 --- a/custom_components/browser_mod/connection.py +++ b/custom_components/browser_mod/connection.py @@ -52,11 +52,10 @@ class BrowserModEntity(Entity): self._ws_connection = None self.entity_id = async_generate_entity_id("media_player.{}", alias or deviceID, hass=hass) - def ws_send(self, command, data=None): - data = data or {} + def ws_send(self, command, **kwargs): self._ws_connection.send_message(event_message(self._ws_cid, { "command": command, - **data, + **kwargs, })) def ws_connect(self, connection, cid): diff --git a/custom_components/browser_mod/media_player.py b/custom_components/browser_mod/media_player.py index 9966061..b71761f 100644 --- a/custom_components/browser_mod/media_player.py +++ b/custom_components/browser_mod/media_player.py @@ -10,6 +10,7 @@ from homeassistant.const import ( STATE_PAUSED, STATE_PLAYING, STATE_IDLE, + STATE_UNKNOWN, ) from .const import DOMAIN, DATA_DEVICES, DATA_ADDERS, DATA_ALIASES @@ -46,12 +47,20 @@ class BrowserModPlayer(MediaPlayerDevice, BrowserModEntity): "browser": self._ws_data.get("browser"), } + @property + def _player_data(self): + return self._ws_data.get("player", {}); + @property def state(self): if not self._ws_connection: return STATE_UNAVAILABLE - return STATE_IDLE - return None + state = self._player_data.get("state", "unknown") + return { + "playing": STATE_PLAYING, + "paused": STATE_PAUSED, + "stopped": STATE_IDLE, + }.get(state, STATE_UNKNOWN) @property def supported_features(self): return ( @@ -61,26 +70,26 @@ class BrowserModPlayer(MediaPlayerDevice, BrowserModEntity): ) @property def volume_level(self): - return 0 + return self._player_data.get("volume", 0) @property - def is_volume_mutes(self): - return False + def is_volume_muted(self): + return self._player_data.get("muted", False) @property def media_content_id(self): - return "" + return self._player_data.get("src", "") def set_volume_level(self, volume): - pass + self.ws_send("set_volume", volume_level=volume) def mute_volume(self, mute): - pass + self.ws_send("mute", mute=mute) def play_media(self, media_type, media_id, **kwargs): - pass + self.ws_send("play", media_content_id=media_id) def media_play(self): - pass + self.ws_send("play") def media_pause(self): - pass + self.ws_send("pause") def media_stop(self): - pass + self.ws_send("stop") diff --git a/js/main.js b/js/main.js index 9dd5ceb..0f9a952 100644 --- a/js/main.js +++ b/js/main.js @@ -3,6 +3,12 @@ class BrowserMod { constructor() { window.hassConnection.then((conn) => this.connect(conn.conn)); + this.player = new Audio(); + + this.player.addEventListener("ended", this.update.bind(this)); + this.player.addEventListener("play", this.update.bind(this)); + this.player.addEventListener("pause", this.update.bind(this)); + this.player.addEventListener("volumechange", this.update.bind(this)); } connect(conn) { @@ -19,10 +25,58 @@ class BrowserMod { callback(msg) { console.log("Got ws message"); console.log(msg); - if(msg.command === "update") - this.update(); + switch (msg.command) { + case "update": + this.update(msg); + break; + + case "play": + this.play(msg); + break; + case "pause": + this.pause(msg); + break; + case "stop": + this.stop(msg); + break; + case "set_volume": + this.set_volume(msg); + break; + case "mute": + this.mute(msg); + break; + } } + get player_state() { + if (!this.player.src) return "stopped"; + if (this.player.ended) return "stopped"; + if (this.player.paused) return "paused"; + return "playing"; + } + + play(msg) { + const src = msg.media_content_id; + if(src) + this.player.src = src; + this.player.play(); + } + pause(msg) { + this.player.pause(); + } + stop(msg) { + this.player.pause(); + this.player.src = null; + } + set_volume(msg) { + if (msg.volume_level === undefined) return; + this.player.volume = msg.volume_level; + } + mute(msg) { + this.player.muted = Boolean(msg.mute) + } + + update() { if(!this.conn) return; @@ -34,7 +88,10 @@ class BrowserMod { }, player: { - state: "idle", + volume: this.player.volume, + muted: this.player.muted, + src: this.player.src, + state: this.player_state, }, }, });