//const
const Debug_Prefix = "Animated Background DEBUG: ";
const Log_Prefix = "Animated Background: "
//globals
var Root;
var Panel_Holder;
var Hui;
var Lovelace;
var Animated_Config;
var Haobj = null;
var View;
var Debug_Mode = false;
var Loaded = false;
var View_Loaded = false;
var Meme_Remover = null;
var Meme_Count = 0;
//state tracking variables
let Previous_State;
let Previous_Entity;
let Previous_Url;
let Previous_Config;
function STATUS_MESSAGE(message, force) {
if (!Debug_Mode) {
console.log(Log_Prefix + message);
}
else {
if (force) {
console.log(Debug_Prefix + message);
}
}
}
function DEBUG_MESSAGE(message, object, only_if_view_not_loaded) {
if (Debug_Mode) {
if (only_if_view_not_loaded && View_Loaded) {
return;
}
console.log(Debug_Prefix + message);
if (object) {
console.log(object);
}
}
}
function randomIntFromInterval(min, max) { // min and max included
return Math.floor(Math.random() * (max - min + 1) + min);
}
//reset all DOM variables
function getVars() {
Root = document.querySelector("home-assistant");
Root = Root && Root.shadowRoot;
Root = Root && Root.querySelector("home-assistant-main");
Root = Root && Root.shadowRoot;
Root = Root && Root.querySelector("app-drawer-layout partial-panel-resolver, ha-drawer partial-panel-resolver");
Root = (Root && Root.shadowRoot) || Root;
Root = Root && Root.querySelector("ha-panel-lovelace");
if (Root) {
Panel_Holder = Root.shadowRoot;
}
Root = Root && Root.shadowRoot;
Root = Root && Root.querySelector("hui-root");
Hui = Root;
if (Root) {
Lovelace = Root.lovelace;
if (Lovelace) {
Animated_Config = Lovelace.config.animated_background;
}
View = Root.shadowRoot.getElementById("view");
}
}
//Mutation observer to set the background of views to transparent each time a new tab is selected
var View_Observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
if (mutation.addedNodes.length > 0) {
if (!currentConfig() && View_Loaded) {
DEBUG_MESSAGE("No configuration found for this view");
}
View_Loaded = false;
clearMemes();
renderBackgroundHTML();
}
});
});
//Mutation observer to refresh video on HA refresh
var Hui_Observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
if (mutation.addedNodes.length > 0) {
DEBUG_MESSAGE("Proof that this observer is not useless");
renderBackgroundHTML();
}
});
});
//Mutation observer to reload on dashboard change
var Panel_Observer = new MutationObserver(function (mutations) {
mutations.forEach(function (mutation) {
if (mutation.removedNodes.length > 0) {
if (mutation.removedNodes[0].nodeName.toLowerCase() == "hui-editor") {
restart();
}
}
});
});
//Current known support: iphone, ipad (if set to mobile site option), windows, macintosh, android
function deviceIncluded(element, index, array) {
return navigator.userAgent.toLowerCase().includes(element.toLowerCase());
}
//return the currently selected lovelace view
function currentViewPath() {
return window.location.pathname.split('/')[2];
}
//return group config by name if it exists
function getGroupConfig(name) {
var return_config = null;
if (name == "none") {
return { enabled: false, reason: "current group is set to 'none'" };
}
if (Animated_Config.groups) {
Animated_Config.groups.forEach(group => {
if (group.name) {
if (group.name == name) {
if (group.config) {
return_config = group.config;
}
}
}
})
}
return return_config;
}
//return the current view configuration or null if none is found
function currentConfig() {
var current_view_path = currentViewPath();
var return_config = null;
if (current_view_path == undefined) {
return return_config;
}
if (Animated_Config) {
if (Animated_Config.entity || Animated_Config.default_url) {
return_config = Animated_Config;
}
if (Animated_Config.views) {
Animated_Config.views.forEach(view => {
if (view.path == current_view_path) {
if (view.config) {
return_config = view.config;
}
else {
STATUS_MESSAGE("Error, defined view has no config", true);
}
}
});
}
var current_view_path = currentViewPath();
var current_view_config = Lovelace.config.views[Lovelace.current_view];
if (Lovelace && current_view_path) {
for (var i = 0; Lovelace.config.views.length > i; i++) {
if (Lovelace.config.views[i].path == current_view_path) {
current_view_config = Lovelace.config.views[i];
}
else {
if (i.toString() == current_view_path.toString()) {
current_view_config = Lovelace.config.views[i];
}
}
}
if (current_view_config) {
var potential_config = getGroupConfig(current_view_config.animated_background);
if (potential_config) {
return_config = potential_config;
}
}
}
if (return_config) {
if (return_config.entity) {
var current_state = getEntityState(return_config.entity);
var current_url = return_config.state_url[current_state];
if (current_url) {
if (current_url == "none") {
return_config = { enabled: false, reason: "current state('" + current_state + "') state_url is set to 'none'", entity: return_config.entity, default_url: return_config.default_url, state_url: return_config.state_url };
}
}
}
}
}
return return_config;
}
//logic for checking if enabled in configuration
function enabled() {
var temp_enabled = false;
if (Animated_Config) {
if (Animated_Config.default_url || Animated_Config.entity || Animated_Config.views || Animated_Config.groups) {
temp_enabled = true;
}
}
if (temp_enabled == false) {
return false;
}
var current_config = currentConfig();
if (!Haobj) {
return false;
}
if (!current_config) {
return false;
}
//Root configuration exceptions
if (Animated_Config.excluded_devices) {
if (Animated_Config.excluded_devices.some(deviceIncluded)) {
if (temp_enabled) {
DEBUG_MESSAGE("Current device is excluded", null, true);
temp_enabled = false;
}
}
}
if (Animated_Config.excluded_users) {
if (Animated_Config.excluded_users.map(username => username.toLowerCase()).includes(Haobj.user.name.toLowerCase())) {
if (temp_enabled) {
DEBUG_MESSAGE("Current user: " + Haobj.user.name + " is excluded", null, true);
temp_enabled = false;
}
}
}
if (Animated_Config.included_users) {
if (Animated_Config.included_users.map(username => username.toLowerCase()).includes(Haobj.user.name.toLowerCase())) {
temp_enabled = true;
}
else {
if (temp_enabled) {
DEBUG_MESSAGE("Current user: " + Haobj.user.name + " is not included", null, true);
temp_enabled = false;
}
}
}
if (Animated_Config.included_devices) {
if (Animated_Config.included_devices.some(deviceIncluded)) {
temp_enabled = true;
}
else {
if (temp_enabled) {
DEBUG_MESSAGE("Current device is not included", null, true);
temp_enabled = false;
}
}
}
//Current config overrides (only does anything if curre_config and Animated_Config are different)
if (current_config.excluded_devices) {
if (current_config.excluded_devices.some(deviceIncluded)) {
if (temp_enabled) {
DEBUG_MESSAGE("Current device is excluded", null, true);
temp_enabled = false;
}
}
}
if (current_config.excluded_users) {
if (current_config.excluded_users.map(username => username.toLowerCase()).includes(Haobj.user.name.toLowerCase())) {
if (temp_enabled) {
DEBUG_MESSAGE("Current user: " + Haobj.user.name + " is excluded", null, true);
temp_enabled = false;
}
}
}
if (current_config.included_users) {
if (current_config.included_users.map(username => username.toLowerCase()).includes(Haobj.user.name.toLowerCase())) {
temp_enabled = true;
}
else {
if (temp_enabled) {
DEBUG_MESSAGE("Current user: " + Haobj.user.name + " is not included", null, true);
temp_enabled = false;
}
}
}
if (current_config.included_devices) {
if (current_config.included_devices.some(deviceIncluded)) {
temp_enabled = true;
}
else {
if (temp_enabled) {
DEBUG_MESSAGE("Current device is not included", null, true);
temp_enabled = false;
}
}
}
if (current_config.enabled == false) {
temp_enabled = false;
}
if (current_config.enabled == true) {
temp_enabled = true;
}
return temp_enabled;
}
//returns selected entity's current state if it is available
function getEntityState(entity) {
var return_state = null;
if (Haobj) {
if (Haobj.states[entity]) {
return_state = Haobj.states[entity].state;
}
}
return return_state;
}
//main render function
function renderBackgroundHTML() {
var current_config = currentConfig();
var state_url = "";
var temp_enabled = true;
//rerender background if entity has changed (to avoid no background refresh if the new entity happens to have the same state)
if (current_config && current_config.entity && Previous_Entity != current_config.entity) {
Previous_State = null;
}
if (current_config != Previous_Config) {
Previous_State = null;
}
//get state of config object
if (current_config) {
if (current_config.entity && current_config.state_url) {
Previous_Entity = current_config.entity;
var current_state = getEntityState(current_config.entity);
if (current_config.state_url[current_state]) {
if (Previous_State != current_state) {
View_Loaded = false;
DEBUG_MESSAGE("Configured entity " + current_config.entity + " is now " + current_state, true);
if (current_config.state_url) {
var url = current_config.state_url[current_state];
if (Array.isArray(url)) {
state_url = url[randomIntFromInterval(0, url.length - 1)];
}
else {
state_url = current_config.state_url[current_state];
}
}
Previous_State = current_state;
}
}
else {
DEBUG_MESSAGE("No state_url found for the current state '" + current_state + "'. Attempting to set default_url")
Previous_State = current_state;
Previous_Url = null;
var url = current_config.default_url;
if (url) {
if (Array.isArray(url)) {
state_url = url[randomIntFromInterval(0, url.length - 1)];
}
else {
state_url = url;
}
}
else {
if (!current_config.reason) {
DEBUG_MESSAGE("No default_url found, restoring lovelace theme")
}
temp_enabled = false;
}
}
}
else {
var url = current_config.default_url;
if (url) {
if (Array.isArray(url)) {
state_url = url[randomIntFromInterval(0, url.length - 1)];
}
else {
state_url = url;
}
}
else {
if (!current_config.reason) {
DEBUG_MESSAGE("No default_url found, restoring lovelace theme")
}
temp_enabled = false;
}
}
}
else {
temp_enabled = false;
}
if (temp_enabled) {
temp_enabled = enabled();
}
processDefaultBackground(temp_enabled);
if (!temp_enabled || !current_config) {
return;
}
Previous_Config = current_config;
var html_to_render;
if (state_url != "" && Hui) {
var bg = Hui.shadowRoot.getElementById("background-iframe");
var video_type = urlIsVideo(state_url);
var doc_body;
if (video_type) {
doc_body = ``
}
else {
doc_body = ``
}
var source_doc = `