Amélioration avec des fonctions d'un vrai dashboard automotive et containerisation du projet pour faciliter le déploiement

This commit is contained in:
Christian CUNAT-BRULE
2026-09-12 21:13:24 +02:00
parent d170f95c92
commit d8eb7f4375
31 changed files with 2233 additions and 65 deletions
+47
View File
@@ -0,0 +1,47 @@
import { applications, safeWebUrl } from './applications.js';
export function embedUrl(provider, value) {
const safe = safeWebUrl(value); if (!safe) return '';
const url = new URL(safe);
if (provider === 'stream') return safe;
if (provider === 'spotify' && url.hostname === 'open.spotify.com') {
const match = url.pathname.match(/^\/(?:intl-[a-z]+\/)?(track|album|playlist|episode|show)\/([a-zA-Z0-9]+)\/?$/);
return match ? `https://open.spotify.com/embed/${match[1]}/${match[2]}` : '';
}
if (['youtube','youtube-music'].includes(provider) && ['music.youtube.com','www.youtube.com','youtube.com','youtu.be'].includes(url.hostname)) {
const video = url.hostname === 'youtu.be' ? url.pathname.slice(1) : url.searchParams.get('v');
const list = url.searchParams.get('list');
if (video && /^[\w-]{11}$/.test(video)) return `https://www.youtube.com/embed/${video}`;
if (list && /^[\w-]{10,200}$/.test(list)) return `https://www.youtube.com/embed/videoseries?list=${encodeURIComponent(list)}`;
}
return '';
}
export function initEmbeds({storage,toast}) {
const $=s=>document.querySelector(s); let provider=null;
function stop() { $('#embed-container').replaceChildren(); $('#embed-status').textContent='Lecteur arrêté. Vous pouvez le charger à nouveau.'; }
function load() {
if (!provider) return;
const url=embedUrl(provider,provider==='stream'?applications.find(app=>app.id==='stream').url:$('#embed-url').value.trim());
if (!url) return toast('Lien non reconnu. Choisissez un contenu compatible avec ce lecteur.');
if (location.protocol==='https:' && url.startsWith('http:')) return toast('Ce lecteur doit utiliser HTTPS sur votre accès sécurisé.');
stop();
const frame=document.createElement('iframe');frame.className='embed-frame';frame.dataset.provider=provider;
frame.title=`Lecteur ${applications.find(a=>a.id===provider).name}`;frame.allow='autoplay; encrypted-media; fullscreen; picture-in-picture';frame.referrerPolicy='strict-origin-when-cross-origin';
frame.setAttribute('sandbox','allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox allow-presentation');
frame.src=url;$('#embed-container').append(frame);
storage.set(`embed.${provider}`,$('#embed-url').value.trim());
$('#embed-status').textContent=provider==='stream' ? 'Si Jellyfin refuse l’affichage, son serveur doit autoriser l’origine CARIA dans sa politique d’intégration. Le lien externe reste disponible.' : 'Le lecteur officiel gère la connexion et les restrictions de lecture. Si le contenu est indisponible, utilisez le lien externe.';
}
document.addEventListener('caria-embed',e=>{
provider=e.detail;
const app=applications.find(a=>a.id===provider);if(!app?.external)return;
stop();$('#embedded-name').textContent=app.name;
$('#embed-form').hidden=provider==='stream';
$('#embedded-explanation').textContent=provider==='stream' ? 'Jellyfin dans CARIA. La connexion reste gérée par votre serveur ; son autorisation d’affichage intégré est nécessaire.' : provider==='spotify' ? 'Lecteur officiel Spotify pour un morceau, album, podcast ou playlist. Ce n’est pas l’application Spotify complète ; la lecture dépend de votre compte et des règles du lecteur.' : 'Lecteur vidéo officiel YouTube à partir d’un lien YouTube ou YouTube Music. La vidéo reste visible. L’application YouTube Music complète ne peut pas être intégrée ici.';
$('#embed-url').value=provider==='stream'?app.url:storage.get(`embed.${provider}`);
$('#embed-external').href=provider==='stream'?app.url:app.url;
if (embedUrl(provider,$('#embed-url').value)) load();
else $('#embed-status').textContent='Collez le lien d’un contenu pour charger son lecteur dans CARIA.';
});
$('#embed-form').onsubmit=e=>{e.preventDefault();load();};$('#embed-stop').onclick=stop;
document.addEventListener('caria-view',e=>{if(e.detail!=='embedded' && $('#embed-container').childElementCount)stop();});
}