From 29a08feacd9a2e77a2c2430da05439587e8ad4a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20Lov=C3=A9n?= Date: Thu, 27 Jun 2019 19:57:27 +0200 Subject: [PATCH] Add readme --- README.md | 194 +++++++++++++++++++ custom_components/browser_mod/browser_mod.js | 6 +- 2 files changed, 197 insertions(+), 3 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..38c21e5 --- /dev/null +++ b/README.md @@ -0,0 +1,194 @@ +browser\_mod +============ + +A Home Assistant integration to turn your browser into a controllable entity - and also an audio player. + +## Example uses + +- Make the camera feed from your front door pop up on the tablett in your kitchen when someone rings the doorbell. +- Have a message pop up on every screen in the house when it's bedtime. +- Make the browser on your workstation switch to a specific tab when the kitchen light is on after midnight +- Play a TTS message on your work computer when the trafic sensor tells you it's time to go home. + +# Installation instructions + +*NOTE: This integration required Home Assistant version 0.95 or later* + +- Copy the contents of `custom_components/browser_commander/` to `/custom_components/browser_commander/`. + +- Add the following to your `configuration.yaml`: + +```yaml +browser_commander: +``` + +- Restart Home Assistant + +# Usage + +## Devices +The most basic concept of `browser_mod` is the *device*. + +A *device* is a machine-browser combination identified by a unique `deviceID`. The `deviceID` is randomly generated and may look like `ded3b4dc-abedd098`. + +- Chrome on your desktop and Chrome on your laptor are two differnt *devices*. +- Chrome on your laptop and Safari on your laptop are two different *devices*. +- Two tabs in Firefox on the same computer is the same *device*. +- Two windows in Edge on the same computer is the same *device*. + +In the two latter cases, the last loaded tab/window will be the *active* one. + +Note: Incognito mode will generate a new `deviceID` and thus a new *device* every time it's started. + +### Aliases +Since the deviceID can be a bit hard to remember for devices you use often, you can specify an alias in `configuration.yaml` + +```yaml +browser_mod: + devices: + 99980b13-dabc9563: + name: Arrakis + d2fc860c-16379d23: + name: dashboard +``` +This binds the *aliases* `Arrakis` to `99980b13-dabc9563` and `dashboard` to `d2fc860c-16379d23`. + +Note: Aliases must be unique. + +## media\_player +Once `browser_mod` is installed, loading up your Home Assistant frontend on a new *device* will create a new `media_player` device. + +Any sound played on this media player will be played by the *device*. + +The `media_player` entity also has some extra attributes presenting the current state of the *device*. + +| attribute | content | +| --- | --- | +| `path` | The currently displayed path on the *device*. | +| `visibility` | Whether the frontend is currently visible on the *device*. | +| `userAgent` | The User Agent of the associated browser. | +| `currentUser` | The user currently logged in on the *device*. | + +## `browser_mod.command` service + +Call the `browser_mod.command` service to controll your *device* in various ways. + +All service calls have two parameters in common, `command` which is the command to execute, and `deviceID` which is a list of *devices* to execute the command on. If `deviceID` is ommitted, the command will be executed on **all** currently connected *devices*. + +`deviceID` may also contain aliases, and there's a special alias named `this` which will evaluate to the *device* from which a command was initiated (if from the frontend). + +### set-theme + +``` +service: browser_mod.command +service_data: + command: set-theme + theme: clear_light +``` + +will set the current theme to `clear_light` on all devices. + +### navigate +``` +service: browser_mod.command +service_data: + command: navigate + navigation_path: /lovelace/1 + deviceID: + - ded3b4dc-abedd098 +``` + +will open your second lovelace view on just the *device* `ded3b4dc-abedd098`. + +*Note: `navigation_path` does not have to be a lovelace path. All paths in Home Assistant works.* + +### more-info +``` +service: browser_mod.command +service_data: + command: more-info + entity_id: camera.front_door + deviceID: + - ded3b4dc-abedd098 + - dashboard +``` + +will show the more-info dialog of `camera.front_door` on the *devices* `ded3b4dc-abedd098` and `dashboard`. + +The optional parameter `large: true` will make the popup wider. + +### popup +``` +service: browser_mod.command +service_data: + command: popup + title: Popup example + card: + type: entities + entities: + - light.bed_light + - light.kitchen_lights + - light.ceiling_lights + deviceID: + - this +``` + +will display the specified `entities` card as a popup on the current device. + +![popup-example](https://user-images.githubusercontent.com/1299821/60288984-a7cb6b00-9915-11e9-9322-324323a9ec6e.png) + +The optional parameter `large: true` will make the popup wider. +The optional parameter `style:` will apply css style options to the popup. + +Ex: +```yaml + style: + border-radius: 20px + --ha-card-border-radius: 20px + --ha-card-background: red +``` + +Note: Sometimes this doesn't work if the *device* is not currently displaying a lovelace path. I'm looking into that... + +### close-popup +``` +service: browser_mod.command +service_data: + command: close-popup +``` + +will close all more-info dialogs and popups that are open on all connected *devices*. + +## `browser-player` card + +To control the playback in the current *device*, `browser_mod` includes a custom lovelace card. Just add + +```yaml +type: custom:browser-player +``` + +anywhere in your lovelace configuration. + +The player card also displays the `entityID`. Click it to select, so you can copy it. + +![browser-player](https://user-images.githubusercontent.com/1299821/60288980-a4d07a80-9915-11e9-88ba-e078a3aa24f4.png) + +# FAQ + +### Does this replace lovelace-player and lovelace-browser-commander +Yes. + +Some improvements + +- With the backend support `browser_mod` does the same things as both of those, but better. +- Since `browser_mod` uses a service for executing commands rather than events, the commands can be easily triggered by any lovelace element which has a `tap_action` setting. +This actually means it pretty much replaces `popup-card` as well. +- `browser_mod` uses websockets to get immediate feedback from the *device* to the backend and much better tracking of disconnects. +- *Aliases*. 'nuff said. +- `browser_mod` works outside of `/lovelace`. + +### Does this replace lovelace-fullykiosk +It will, eventually. + +--- +Buy Me A Coffee diff --git a/custom_components/browser_mod/browser_mod.js b/custom_components/browser_mod/browser_mod.js index 95e317b..6cafc4b 100644 --- a/custom_components/browser_mod/browser_mod.js +++ b/custom_components/browser_mod/browser_mod.js @@ -1,4 +1,4 @@ -!function(e){var t={};function n(s){if(t[s])return t[s].exports;var o=t[s]={i:s,l:!1,exports:{}};return e[s].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,s){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:s})},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 s=Object.create(null);if(n.r(s),Object.defineProperty(s,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(s,o,function(t){return e[t]}.bind(null,o));return s},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 s=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"]}();function o(e){return document.querySelector("home-assistant").provideHass(e)}function r(e,t,n=null){if((e=new Event(e,{bubbles:!0,cancelable:!1,composed:!0})).detail=t||{},n)n.dispatchEvent(e);else{var s=document.querySelector("home-assistant");(s=(s=(s=(s=(s=(s=(s=(s=(s=(s=(s=s&&s.shadowRoot)&&s.querySelector("home-assistant-main"))&&s.shadowRoot)&&s.querySelector("app-drawer-layout partial-panel-resolver"))&&s.shadowRoot||s)&&s.querySelector("ha-panel-lovelace"))&&s.shadowRoot)&&s.querySelector("hui-root"))&&s.shadowRoot)&&s.querySelector("ha-app-layout #view"))&&s.firstElementChild)&&s.dispatchEvent(e)}}const a="custom:";function i(e,t){const n=document.createElement("hui-error-card");return n.setConfig({type:"error",error:e,config:t}),n}function l(e,t){if(!t||"object"!=typeof t||!t.type)return i(`No ${e} type configured`,t);let n=t.type;if(n=n.startsWith(a)?n.substr(a.length):`hui-${n}-${e}`,customElements.get(n))return function(e,t){const n=document.createElement(e);try{n.setConfig(t)}catch(e){return i(e,t)}return n}(n,t);const s=i(`Custom element doesn't exist: ${n}.`,t);s.style.display="None";const o=setTimeout(()=>{s.style.display=""},2e3);return customElements.whenDefined(n).then(()=>{clearTimeout(o),r("ll-rebuild",{},s)}),s}function c(e,t=!1){r("hass-more-info",{entityId:e},document.querySelector("home-assistant"));const n=document.querySelector("home-assistant")._moreInfoEl;return n.large=t,n}const u=Object.getPrototypeOf(customElements.get("home-assistant-main")),d=u.prototype.html,p=u.prototype.css;class h extends u{static get properties(){return{hass:{},config:{}}}setConfig(e){this._config=e,this.el?this.el.setConfig(e):this.el=this.create(e),this._hass&&(this.el.hass=this._hass),this.noHass&&o(this)}set config(e){this.setConfig(e)}set hass(e){this._hass=e,this.el&&(this.el.hass=e)}createRenderRoot(){return this}render(){return d`${this.el}`}}if(!customElements.get("card-maker")){class e extends h{create(e){return function(e){return l("card",e)}(e)}}customElements.define("card-maker",e)}if(!customElements.get("element-maker")){class e extends h{create(e){return function(e){return l("element",e)}(e)}}customElements.define("element-maker",e)}if(!customElements.get("entity-row-maker")){class e extends h{create(e){return function(e){const t=new Set(["call-service","divider","section","weblink"]);if(!e)return i("Invalid configuration given.",e);if("string"==typeof e&&(e={entity:e}),"object"!=typeof e||!e.entity&&!e.type)return i("Invalid configuration given.",e);const n=e.type||"default";if(t.has(n)||n.startsWith(a))return l("row",e);const s=e.entity.split(".",1)[0];return Object.assign(e,{type:{alert:"toggle",automation:"toggle",climate:"climate",cover:"cover",fan:"toggle",group:"group",input_boolean:"toggle",input_number:"input-number",input_select:"input-select",input_text:"input-text",light:"toggle",lock:"lock",media_player:"media-player",remote:"toggle",scene:"scene",script:"script",sensor:"sensor",timer:"timer",switch:"toggle",vacuum:"toggle",water_heater:"climate",input_datetime:"input-datetime"}[s]||"text"}),l("entity-row",e)}(e)}}customElements.define("entity-row-maker",e)}function m(e,t,n=!1,s=null){c(Object.keys(document.querySelector("home-assistant").hass.states)[0]);const o=document.createElement("card-maker");o.noHass=!0,o.config=t;const r=document.createElement("div");r.innerHTML=`\n \n \n \n
\n ${e}\n
\n
\n `,r.appendChild(o);const a=document.querySelector("home-assistant")._moreInfoEl;a.large=n,a._page="none",a.shadowRoot.appendChild(r);let i={};if(s)for(var l in s)i[l]=a.style[l],a.style.setProperty(l,s[l]);return setTimeout(()=>{let e=setInterval(()=>{if(a.getAttribute("aria-hidden"))for(var t in clearInterval(e),r.parentNode.removeChild(r),i)a.style.setProperty(t,i[t])},100)},1e3),a}customElements.define("browser-player",class extends u{static get properties(){return{hass:{}}}setConfig(e){this._config=e}handleMute(e){window.browser_mod.mute({})}handleVolumeChange(e){const t=parseFloat(e.target.value);window.browser_mod.set_volume({volume_level:t})}handleMoreInfo(e){c(window.browser_mod.entity_id)}handlePlayPause(e){window.browser_mod.player.paused?window.browser_mod.play({}):window.browser_mod.pause({})}render(){const e=window.browser_mod.player;return d` +!function(e){var t={};function n(o){if(t[o])return t[o].exports;var s=t[o]={i:o,l:!1,exports:{}};return e[o].call(s.exports,s,s.exports,n),s.l=!0,s.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 s in e)n.d(o,s,function(t){return e[t]}.bind(null,s));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"]}();function s(e){return document.querySelector("home-assistant").provideHass(e)}function r(e,t,n=null){if((e=new Event(e,{bubbles:!0,cancelable:!1,composed:!0})).detail=t||{},n)n.dispatchEvent(e);else{var o=document.querySelector("home-assistant");(o=(o=(o=(o=(o=(o=(o=(o=(o=(o=(o=o&&o.shadowRoot)&&o.querySelector("home-assistant-main"))&&o.shadowRoot)&&o.querySelector("app-drawer-layout partial-panel-resolver"))&&o.shadowRoot||o)&&o.querySelector("ha-panel-lovelace"))&&o.shadowRoot)&&o.querySelector("hui-root"))&&o.shadowRoot)&&o.querySelector("ha-app-layout #view"))&&o.firstElementChild)&&o.dispatchEvent(e)}}const a="custom:";function i(e,t){const n=document.createElement("hui-error-card");return n.setConfig({type:"error",error:e,config:t}),n}function l(e,t){if(!t||"object"!=typeof t||!t.type)return i(`No ${e} type configured`,t);let n=t.type;if(n=n.startsWith(a)?n.substr(a.length):`hui-${n}-${e}`,customElements.get(n))return function(e,t){const n=document.createElement(e);try{n.setConfig(t)}catch(e){return i(e,t)}return n}(n,t);const o=i(`Custom element doesn't exist: ${n}.`,t);o.style.display="None";const s=setTimeout(()=>{o.style.display=""},2e3);return customElements.whenDefined(n).then(()=>{clearTimeout(s),r("ll-rebuild",{},o)}),o}function c(e,t=!1){r("hass-more-info",{entityId:e},document.querySelector("home-assistant"));const n=document.querySelector("home-assistant")._moreInfoEl;return n.large=t,n}const u=Object.getPrototypeOf(customElements.get("home-assistant-main")),d=u.prototype.html,p=u.prototype.css;class h extends u{static get properties(){return{hass:{},config:{}}}setConfig(e){this._config=e,this.el?this.el.setConfig(e):this.el=this.create(e),this._hass&&(this.el.hass=this._hass),this.noHass&&s(this)}set config(e){this.setConfig(e)}set hass(e){this._hass=e,this.el&&(this.el.hass=e)}createRenderRoot(){return this}render(){return d`${this.el}`}}if(!customElements.get("card-maker")){class e extends h{create(e){return function(e){return l("card",e)}(e)}}customElements.define("card-maker",e)}if(!customElements.get("element-maker")){class e extends h{create(e){return function(e){return l("element",e)}(e)}}customElements.define("element-maker",e)}if(!customElements.get("entity-row-maker")){class e extends h{create(e){return function(e){const t=new Set(["call-service","divider","section","weblink"]);if(!e)return i("Invalid configuration given.",e);if("string"==typeof e&&(e={entity:e}),"object"!=typeof e||!e.entity&&!e.type)return i("Invalid configuration given.",e);const n=e.type||"default";if(t.has(n)||n.startsWith(a))return l("row",e);const o=e.entity.split(".",1)[0];return Object.assign(e,{type:{alert:"toggle",automation:"toggle",climate:"climate",cover:"cover",fan:"toggle",group:"group",input_boolean:"toggle",input_number:"input-number",input_select:"input-select",input_text:"input-text",light:"toggle",lock:"lock",media_player:"media-player",remote:"toggle",scene:"scene",script:"script",sensor:"sensor",timer:"timer",switch:"toggle",vacuum:"toggle",water_heater:"climate",input_datetime:"input-datetime"}[o]||"text"}),l("entity-row",e)}(e)}}customElements.define("entity-row-maker",e)}function m(e,t,n=!1,o=null){c(Object.keys(document.querySelector("home-assistant").hass.states)[0]);const s=document.createElement("card-maker");s.noHass=!0,s.config=t;const r=document.createElement("div");r.innerHTML=`\n \n \n \n
\n ${e}\n
\n
\n `,r.appendChild(s);const a=document.querySelector("home-assistant")._moreInfoEl;a.large=n,a._page="none",a.shadowRoot.appendChild(r);let i={};if(o)for(var l in o)console.log(`Applying: ${l}: ${o[l]}`),i[l]=a.style[l],a.style.setProperty(l,o[l]),console.log(a.style[l]),console.log(a.style);return setTimeout(()=>{let e=setInterval(()=>{if(a.getAttribute("aria-hidden"))for(var t in clearInterval(e),r.parentNode.removeChild(r),i)a.style.setProperty(t,i[t])},100)},1e3),a}customElements.define("browser-player",class extends u{static get properties(){return{hass:{}}}setConfig(e){this._config=e}handleMute(e){window.browser_mod.mute({})}handleVolumeChange(e){const t=parseFloat(e.target.value);window.browser_mod.set_volume({volume_level:t})}handleMoreInfo(e){c(window.browser_mod.entity_id)}handlePlayPause(e){window.browser_mod.player.paused?window.browser_mod.play({}):window.browser_mod.pause({})}render(){const e=window.browser_mod.player;return d`
- ${s} + ${o}
@@ -53,4 +53,4 @@ -moz-user-select: all; -ms-user-select: all; } - `}});window.browser_mod=new class{set hass(e){if(!e)return;if(this._hass=e,this.hassPatched)return;const t=e.callService;e.callService=(e,n,o)=>{if("browser_mod"===e&&"command"===n&&o.deviceID){const e=o.deviceID.indexOf("this");-1!==e&&(o.deviceID[e]=s)}t(e,n,o)},this.hassPatched=!0,document.querySelector("home-assistant").hassChanged(e,e)}constructor(){window.hassConnection.then(e=>this.connect(e.conn)),this.player=new Audio;const e=this.update.bind(this);this.player.addEventListener("ended",e),this.player.addEventListener("play",e),this.player.addEventListener("pause",e),this.player.addEventListener("volumechange",e),document.addEventListener("visibilitychange",e),window.addEventListener("location-changed",e),o(this)}connect(e){this.conn=e,e.subscribeMessage(e=>this.callback(e),{type:"browser_mod/connect",deviceID:s})}callback(e){switch(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);break;case"popup":this.popup(e);break;case"close-popup":this.close_popup(e);break;case"navigate":this.navigate(e);break;case"more-info":this.more_info(e);break;case"set-theme":this.set_theme(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){void 0===e.mute&&(e.mute=!this.player.muted),this.player.muted=Boolean(e.mute)}popup(e){e.title&&e.card&&m(e.title,e.card,e.large,e.style)}close_popup(e){document.querySelector("home-assistant")._moreInfoEl.close()}navigate(e){e.navigation_path&&(history.pushState(null,"",e.navigation_path),r("location-changed",{},document.querySelector("home-assistant")))}more_info(e){e.entity_id&&c(e.entity_id,e.large)}set_theme(e){e.theme||(e.theme="default"),r("settheme",e.theme,document.querySelector("home-assistant"))}update(e=null){this.conn&&(e&&e.entity_id&&(this.entity_id=e.entity_id),this.conn.sendMessage({type:"browser_mod/update",deviceID:s,data:{browser:{path:window.location.pathname,visibility:document.visibilityState,userAgent:navigator.userAgent,currentUser:this._hass&&this._hass.user&&this._hass.user.name},player:{volume:this.player.volume,muted:this.player.muted,src:this.player.src,state:this.player_state}}}))}}}]); \ No newline at end of file + `}});window.browser_mod=new class{set hass(e){if(!e)return;if(this._hass=e,this.hassPatched)return;const t=e.callService;e.callService=(e,n,s)=>{if("browser_mod"===e&&"command"===n&&s.deviceID){const e=s.deviceID.indexOf("this");-1!==e&&(s.deviceID[e]=o)}t(e,n,s)},this.hassPatched=!0,document.querySelector("home-assistant").hassChanged(e,e)}constructor(){window.hassConnection.then(e=>this.connect(e.conn)),this.player=new Audio;const e=this.update.bind(this);this.player.addEventListener("ended",e),this.player.addEventListener("play",e),this.player.addEventListener("pause",e),this.player.addEventListener("volumechange",e),document.addEventListener("visibilitychange",e),window.addEventListener("location-changed",e),s(this)}connect(e){this.conn=e,e.subscribeMessage(e=>this.callback(e),{type:"browser_mod/connect",deviceID:o})}callback(e){switch(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);break;case"popup":this.popup(e);break;case"close-popup":this.close_popup(e);break;case"navigate":this.navigate(e);break;case"more-info":this.more_info(e);break;case"set-theme":this.set_theme(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){void 0===e.mute&&(e.mute=!this.player.muted),this.player.muted=Boolean(e.mute)}popup(e){e.title&&e.card&&m(e.title,e.card,e.large,e.style)}close_popup(e){document.querySelector("home-assistant")._moreInfoEl.close()}navigate(e){e.navigation_path&&(history.pushState(null,"",e.navigation_path),r("location-changed",{},document.querySelector("home-assistant")))}more_info(e){e.entity_id&&c(e.entity_id,e.large)}set_theme(e){e.theme||(e.theme="default"),r("settheme",e.theme,document.querySelector("home-assistant"))}update(e=null){this.conn&&(e&&e.entity_id&&(this.entity_id=e.entity_id),this.conn.sendMessage({type:"browser_mod/update",deviceID:o,data:{browser:{path:window.location.pathname,visibility:document.visibilityState,userAgent:navigator.userAgent,currentUser:this._hass&&this._hass.user&&this._hass.user.name},player:{volume:this.player.volume,muted:this.player.muted,src:this.player.src,state:this.player_state}}}))}}}]); \ No newline at end of file