|
console.log("custom-ha-script.js chargé v33 - Shuffle Images + Vidéos (dashboards filtrés)"); |
|
|
|
// === 0) Allowed dashboards === |
|
// Put here the dashboard IDs as they appear in the URL: |
|
// e.g.: http://.../lovelace-tablette/0 → "lovelace-tablette" |
|
const DASHBOARD_WHITELIST = [ |
|
"dashboard-test", |
|
"lovelace-salon" |
|
]; |
|
|
|
// Detect the current dashboard ID from the URL |
|
function getCurrentDashboardId() { |
|
const path = window.location.pathname || ""; |
|
// Example path: "/lovelace-tablette/0" |
|
const parts = path.split("/").filter(Boolean); |
|
// The first segment after the root is usually the dashboard ID |
|
return parts.length > 0 ? parts[0] : null; |
|
} |
|
|
|
const currentDashboardId = getCurrentDashboardId(); |
|
console.log("Dashboard courant détecté :", currentDashboardId); |
|
|
|
// If the current dashboard is not in the whitelist, stop everything |
|
if (!currentDashboardId || !DASHBOARD_WHITELIST.includes(currentDashboardId)) { |
|
console.log("Dashboard non autorisé pour le slideshow Immich, script arrêté."); |
|
} else { |
|
|
|
console.log("Dashboard autorisé, activation du slideshow Immich."); |
|
|
|
const CHANGE_INTERVAL = 60000; // 60 seconds |
|
const ALBUM_ID = 'YOUR_ALBUM_ID'; |
|
const IMMICH_BASE_URL = 'https://immich.domain.com/api'; |
|
const IMMICH_API_KEY = 'YOUR_IMMICH_API_KEY'; |
|
|
|
let currentBlobUrl = null; |
|
let currentVideoElement = null; |
|
let currentTimeoutId = null; |
|
let albumMediaAssets = []; |
|
let playlist = []; |
|
let playlistIndex = 0; |
|
let haVisible = true; |
|
|
|
// 1) Function to make HA transparent |
|
function setHATransparency(isTransparent) { |
|
const main = document.querySelector("body"); |
|
if (isTransparent) { |
|
document.documentElement.style.setProperty("--lovelace-background", "transparent"); |
|
document.documentElement.style.setProperty("--ha-card-background", "rgba(255, 255, 255, 0.1)"); |
|
if (main) main.style.backgroundColor = "transparent"; |
|
} else { |
|
document.documentElement.style.setProperty("--lovelace-background", "black"); |
|
} |
|
} |
|
|
|
// 2) Function to hide/show home-assistant |
|
function toggleHomeAssistantVisibility() { |
|
const haRoot = document.querySelector("home-assistant"); |
|
if (!haRoot) { |
|
console.warn("home-assistant introuvable dans le DOM"); |
|
return; |
|
} |
|
|
|
haVisible = !haVisible; |
|
|
|
if (haVisible) { |
|
haRoot.style.visibility = "visible"; |
|
haRoot.style.opacity = "1"; |
|
console.log("🔲 home-assistant visible"); |
|
} else { |
|
haRoot.style.visibility = "hidden"; |
|
haRoot.style.opacity = "0"; |
|
console.log("⬛ home-assistant masqué"); |
|
} |
|
} |
|
|
|
// --- Playlist logic --- |
|
function shuffleArray(arr) { |
|
const a = arr.slice(); |
|
for (let i = a.length - 1; i > 0; i--) { |
|
const j = Math.floor(Math.random() * (i + 1)); |
|
[a[i], a[j]] = [a[j], a[i]]; |
|
} |
|
return a; |
|
} |
|
|
|
async function loadAlbumIfNeeded() { |
|
if (albumMediaAssets.length > 0) return; |
|
try { |
|
console.log("Chargement album Immich…"); |
|
const res = await fetch(`${IMMICH_BASE_URL}/albums/${ALBUM_ID}`, { |
|
method: "GET", |
|
headers: { |
|
"x-api-key": IMMICH_API_KEY, |
|
"Accept": "application/json" |
|
} |
|
}); |
|
if (!res.ok) { |
|
console.error("Erreur API Immich (album) :", res.status, res.statusText); |
|
return; |
|
} |
|
const album = await res.json(); |
|
albumMediaAssets = (album.assets || []).filter(a => a.type === "IMAGE" || a.type === "VIDEO"); |
|
if (!albumMediaAssets.length) { |
|
console.warn("Aucune image ou vidéo dans cet album."); |
|
return; |
|
} |
|
console.log("Album chargé, nombre de médias (image+vidéo) :", albumMediaAssets.length); |
|
playlist = shuffleArray(albumMediaAssets); |
|
playlistIndex = 0; |
|
} catch (err) { |
|
console.error("Erreur lors de la récupération de l'album Immich :", err); |
|
} |
|
} |
|
|
|
async function getNextAssetFromPlaylist() { |
|
await loadAlbumIfNeeded(); |
|
if (!albumMediaAssets.length) return null; |
|
if (playlistIndex >= playlist.length) { |
|
playlist = shuffleArray(albumMediaAssets); |
|
playlistIndex = 0; |
|
console.log("Nouvelle playlist shuffle générée."); |
|
} |
|
const asset = playlist[playlistIndex]; |
|
playlistIndex += 1; |
|
console.log( |
|
"Média depuis playlist :", |
|
asset.type, |
|
asset.id, |
|
asset.originalFileName, |
|
`(${playlistIndex}/${playlist.length})` |
|
); |
|
return asset; |
|
} |
|
|
|
// --- Display --- |
|
function cleanupCurrentMedia() { |
|
if (currentTimeoutId) { |
|
clearTimeout(currentTimeoutId); |
|
currentTimeoutId = null; |
|
} |
|
if (currentBlobUrl) { |
|
URL.revokeObjectURL(currentBlobUrl); |
|
currentBlobUrl = null; |
|
} |
|
document.body.style.backgroundImage = ""; |
|
if (currentVideoElement) { |
|
currentVideoElement.pause(); |
|
currentVideoElement.remove(); |
|
currentVideoElement = null; |
|
} |
|
} |
|
|
|
function displayImage(blobUrl) { |
|
setHATransparency(false); |
|
document.body.style.backgroundImage = `url("${blobUrl}")`; |
|
document.body.style.backgroundSize = "contain"; |
|
document.body.style.backgroundPosition = "center"; |
|
document.body.style.backgroundRepeat = "no-repeat"; |
|
document.body.style.backgroundColor = "black"; |
|
} |
|
|
|
function displayVideo(blobUrl) { |
|
setHATransparency(true); |
|
|
|
const video = document.createElement("video"); |
|
video.src = blobUrl; |
|
video.autoplay = true; |
|
video.muted = true; |
|
video.playsInline = true; |
|
video.loop = false; |
|
|
|
Object.assign(video.style, { |
|
position: "fixed", |
|
top: "0", |
|
left: "0", |
|
width: "100%", |
|
height: "100%", |
|
objectFit: "contain", |
|
backgroundColor: "black", |
|
zIndex: "-1", |
|
pointerEvents: "none" |
|
}); |
|
|
|
video.addEventListener("error", (e) => { |
|
console.error("Erreur de lecture vidéo :", e, video.error); |
|
}); |
|
|
|
document.body.appendChild(video); |
|
currentVideoElement = video; |
|
console.log("Vidéo ajoutée en background, src =", blobUrl); |
|
return video; |
|
} |
|
|
|
// --- Progress bar --- |
|
function startProgress(duration) { |
|
let container = document.getElementById("bg-progress-container"); |
|
if (!container) { |
|
container = document.createElement("div"); |
|
container.id = "bg-progress-container"; |
|
Object.assign(container.style, { |
|
position: "fixed", |
|
left: "0", |
|
bottom: "0", |
|
width: "100%", |
|
height: "4px", |
|
background: "rgba(0, 0, 0, 0.4)", |
|
zIndex: "9999" |
|
}); |
|
const bar = document.createElement("div"); |
|
bar.id = "bg-progress-bar"; |
|
Object.assign(bar.style, { |
|
width: "0%", |
|
height: "100%", |
|
background: "#00bcd4", |
|
transition: "none" |
|
}); |
|
container.appendChild(bar); |
|
document.body.appendChild(container); |
|
} |
|
const bar = document.getElementById("bg-progress-bar"); |
|
bar.style.transition = "none"; |
|
bar.style.width = "0%"; |
|
void bar.offsetWidth; |
|
bar.style.transition = `width ${duration}ms linear`; |
|
bar.style.width = "100%"; |
|
} |
|
|
|
async function showNextMedia() { |
|
console.log("showNextMedia() appelé"); |
|
const asset = await getNextAssetFromPlaylist(); |
|
if (!asset) { |
|
console.warn("Impossible de choisir un asset depuis la playlist. Nouveau essai dans 5s."); |
|
setTimeout(showNextMedia, 5000); |
|
return; |
|
} |
|
|
|
const isVideo = asset.type === "VIDEO"; |
|
console.log("=== Nouveau média ===", isVideo ? "VIDEO" : "IMAGE", asset.id); |
|
|
|
const url = isVideo |
|
? `${IMMICH_BASE_URL}/assets/${asset.id}/original` |
|
: `${IMMICH_BASE_URL}/assets/${asset.id}/thumbnail?size=preview`; |
|
|
|
console.log("Fetch asset :", url); |
|
|
|
try { |
|
const res = await fetch(url, { |
|
headers: { "x-api-key": IMMICH_API_KEY } |
|
}); |
|
|
|
if (!res.ok) { |
|
console.error("Erreur API Immich (asset) :", res.status, res.statusText); |
|
setTimeout(showNextMedia, 5000); |
|
return; |
|
} |
|
|
|
const blob = await res.blob(); |
|
console.log("Blob reçu : type =", blob.type, ", taille =", blob.size, "bytes"); |
|
|
|
cleanupCurrentMedia(); |
|
currentBlobUrl = URL.createObjectURL(blob); |
|
|
|
if (isVideo) { |
|
const video = displayVideo(currentBlobUrl); |
|
|
|
const playPromise = video.play(); |
|
if (playPromise && typeof playPromise.then === "function") { |
|
playPromise |
|
.then(() => { |
|
console.log("play() résolu, la vidéo devrait être en cours de lecture"); |
|
}) |
|
.catch((err) => { |
|
console.error("Erreur lors de play() sur la vidéo :", err); |
|
}); |
|
} |
|
|
|
video.addEventListener("loadedmetadata", () => { |
|
let durationSec = video.duration; |
|
if (!isFinite(durationSec) || durationSec <= 0) { |
|
durationSec = CHANGE_INTERVAL / 1000; |
|
} |
|
const durationMs = durationSec * 1000; |
|
console.log("Durée vidéo détectée :", durationSec, "sec"); |
|
startProgress(durationMs); |
|
currentTimeoutId = setTimeout(showNextMedia, durationMs + 500); |
|
}); |
|
|
|
video.addEventListener("ended", () => { |
|
console.log("Vidéo terminée, passage immédiat au média suivant."); |
|
if (currentTimeoutId) { |
|
clearTimeout(currentTimeoutId); |
|
currentTimeoutId = null; |
|
} |
|
showNextMedia(); |
|
}); |
|
} else { |
|
displayImage(currentBlobUrl); |
|
startProgress(CHANGE_INTERVAL); |
|
currentTimeoutId = setTimeout(showNextMedia, CHANGE_INTERVAL); |
|
} |
|
|
|
console.log("Média affiché :", asset.type, "id :", asset.id); |
|
} catch (e) { |
|
console.error("Erreur lors du téléchargement de l'asset :", e); |
|
setTimeout(showNextMedia, 5000); |
|
} |
|
} |
|
|
|
// --- Keyboard controls --- |
|
document.addEventListener("keydown", (e) => { |
|
if (e.key === "ArrowRight" || e.code === "ArrowRight" || e.keyCode === 39) { |
|
console.log("➡️ Touche ArrowRight détectée → passage au média suivant"); |
|
e.preventDefault(); |
|
showNextMedia(); |
|
} |
|
if (e.key === "ArrowDown" || e.code === "ArrowDown" || e.keyCode === 40) { |
|
console.log("⬇️ Touche ArrowDown détectée → toggle home-assistant"); |
|
e.preventDefault(); |
|
toggleHomeAssistantVisibility(); |
|
} |
|
}); |
|
|
|
// --- Reliable start --- |
|
if (document.readyState === "complete" || document.readyState === "interactive") { |
|
console.log("DOM déjà prêt – démarrage slideshow Immich…"); |
|
setTimeout(showNextMedia, 0); |
|
} else { |
|
document.addEventListener("DOMContentLoaded", () => { |
|
console.log("DOMContentLoaded – démarrage slideshow Immich…"); |
|
showNextMedia(); |
|
}); |
|
} |
|
|
|
} // end of allowed dashboard if-block |