mirror of
https://github.com/R0m1k3/xtremflow.git
synced 2026-10-12 01:36:20 +02:00
Security: - Replace unsalted SHA-256 password hashing with bcrypt (lazy rehash on login) - Add authenticated /api/xtream-api gateway: Xtream credentials are injected server-side and never sent to the frontend; /api/playlists no longer returns passwords - Redact credentials from all logs (login body, proxy/FFmpeg/scheduler URLs) - Add auth to recordings, EPG, season-passes and streaming routes (HttpOnly session cookie for hls.js; loopback bypass for local FFmpeg) - Lock player postMessage to same-origin in both directions - Vendor and pin hls.js 1.6.7 / mpegts.js 1.7.3 (drop CDN @latest) - Fix rate limiter (client IP was never resolved), add login rate limit, restrict CORS, add CSP Report-Only, block private-IP SSRF targets, fix path traversal in recording log retrieval, chmod 777 -> 770 - Remove dead HiveService (seeded admin/admin into IndexedDB with SHA-256) - Fix authMiddleware not populating 'user' context (getPlaylist ignored the logged-in user; admin purge always returned 403) Streaming: - New FfmpegSessionManager: process registry, idle reaper (4 min live / 15 min VOD), orphan cleanup at startup, clean SIGTERM shutdown, fast-fail with stderr instead of 30 s timeout - Quality selection (source/high/medium/low) for live and VOD; source mode streams with -c:v copy (zero transcoding); selector wired into the player - Concurrent recordings (MAX_CONCURRENT_RECORDINGS, default 2); conflicts retry on the next tick instead of silently failing - Lower live latency (HLS window 20 -> 10 segments, liveSync 10 -> 3) - Fix recording log lookup (.mp4 vs .mkv mismatch) Design: - Replace hardcoded colors with AppColors tokens (12 files) - web/theme.css syncs HTML players with the Flutter palette - DPAD/keyboard navigation (arrow-key focus, player shortcuts) - Tooltips on player icon buttons, Semantics on content cards - Remove 7 dead widgets broken since the Stitch merge Quality: - bin/test/: 21 unit tests (bcrypt, redaction, traversal, SSRF, recording conflicts) plus a quality-selector widget test - GitHub Actions CI (analyze + test + build web) - Archive stale status docs into docs/archive/ Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
323 lines
18 KiB
HTML
323 lines
18 KiB
HTML
<!DOCTYPE html>
|
|
|
|
<html class="dark" lang="fr"><head>
|
|
<meta charset="utf-8"/>
|
|
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
|
<title>Paramètres - XtremFlow</title>
|
|
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Space+Grotesk:wght@500;600;700&display=swap" rel="stylesheet"/>
|
|
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
|
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
|
<script id="tailwind-config">
|
|
tailwind.config = {
|
|
darkMode: "class",
|
|
theme: {
|
|
extend: {
|
|
"colors": {
|
|
"tertiary-fixed": "#e2e2e2",
|
|
"inverse-surface": "#e3e2e7",
|
|
"on-secondary-fixed-variant": "#46464e",
|
|
"on-secondary": "#2f3037",
|
|
"inverse-on-surface": "#2f3035",
|
|
"primary": "#adc6ff",
|
|
"on-primary": "#002e69",
|
|
"primary-fixed-dim": "#adc6ff",
|
|
"on-primary-fixed-variant": "#004493",
|
|
"on-error-container": "#ffdad6",
|
|
"tertiary": "#c6c6c7",
|
|
"on-background": "#e3e2e7",
|
|
"on-surface": "#e3e2e7",
|
|
"surface": "#121317",
|
|
"outline-variant": "#414755",
|
|
"on-primary-container": "#00285c",
|
|
"error": "#ffb4ab",
|
|
"surface-container-low": "#1a1b20",
|
|
"outline": "#8b90a0",
|
|
"on-tertiary-container": "#282a2a",
|
|
"surface-tint": "#adc6ff",
|
|
"on-primary-fixed": "#001a41",
|
|
"on-tertiary-fixed": "#1a1c1c",
|
|
"inverse-primary": "#005bc1",
|
|
"background": "#121317",
|
|
"surface-bright": "#38393d",
|
|
"error-container": "#93000a",
|
|
"surface-dim": "#121317",
|
|
"surface-container-highest": "#343439",
|
|
"tertiary-fixed-dim": "#c6c6c7",
|
|
"secondary-container": "#4a4b53",
|
|
"primary-fixed": "#d8e2ff",
|
|
"on-surface-variant": "#c1c6d7",
|
|
"surface-container": "#1f1f24",
|
|
"secondary-fixed": "#e3e1eb",
|
|
"tertiary-container": "#909191",
|
|
"secondary-fixed-dim": "#c6c5cf",
|
|
"secondary": "#c6c5cf",
|
|
"surface-variant": "#343439",
|
|
"on-secondary-container": "#bcbbc4",
|
|
"on-tertiary": "#2f3131",
|
|
"on-error": "#690005",
|
|
"primary-container": "#4b8eff",
|
|
"on-tertiary-fixed-variant": "#454747",
|
|
"surface-container-lowest": "#0d0e12",
|
|
"on-secondary-fixed": "#1a1b22",
|
|
"surface-container-high": "#292a2e"
|
|
},
|
|
"borderRadius": {
|
|
"DEFAULT": "0.25rem",
|
|
"lg": "0.5rem",
|
|
"xl": "0.75rem",
|
|
"full": "9999px"
|
|
},
|
|
"spacing": {
|
|
"md": "24px",
|
|
"sm": "12px",
|
|
"margin": "32px",
|
|
"gutter": "24px",
|
|
"base": "8px",
|
|
"xs": "4px",
|
|
"lg": "48px",
|
|
"xl": "80px"
|
|
},
|
|
"fontFamily": {
|
|
"body-md": ["Inter"],
|
|
"label-sm": ["Inter"],
|
|
"body-lg": ["Inter"],
|
|
"label-lg": ["Inter"],
|
|
"headline-xl": ["Space Grotesk"],
|
|
"headline-md": ["Space Grotesk"],
|
|
"headline-lg": ["Space Grotesk"]
|
|
},
|
|
"fontSize": {
|
|
"body-md": ["16px", { "lineHeight": "1.5", "fontWeight": "400" }],
|
|
"label-sm": ["12px", { "lineHeight": "1.2", "letterSpacing": "0.02em", "fontWeight": "500" }],
|
|
"body-lg": ["18px", { "lineHeight": "1.6", "fontWeight": "400" }],
|
|
"label-lg": ["14px", { "lineHeight": "1.2", "letterSpacing": "0.05em", "fontWeight": "600" }],
|
|
"headline-xl": ["48px", { "lineHeight": "1.1", "letterSpacing": "-0.02em", "fontWeight": "700" }],
|
|
"headline-md": ["24px", { "lineHeight": "1.3", "fontWeight": "500" }],
|
|
"headline-lg": ["32px", { "lineHeight": "1.2", "letterSpacing": "-0.01em", "fontWeight": "600" }]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
<style>
|
|
body {
|
|
background-color: #0F1014; /* Base Level 0 */
|
|
color: #e3e2e7;
|
|
}
|
|
.glass-panel {
|
|
background: rgba(24, 25, 32, 0.4);
|
|
backdrop-filter: blur(20px);
|
|
-webkit-backdrop-filter: blur(20px);
|
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
}
|
|
.glass-floating {
|
|
background: rgba(24, 25, 32, 0.6);
|
|
backdrop-filter: blur(40px);
|
|
-webkit-backdrop-filter: blur(40px);
|
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
box-shadow: inset 1px 1px 0px 0px rgba(173, 198, 255, 0.2), 0 10px 30px -10px rgba(0, 0, 0, 0.5);
|
|
}
|
|
.neon-glow {
|
|
box-shadow: 0 0 15px rgba(0, 122, 255, 0.5);
|
|
}
|
|
.input-dark {
|
|
background-color: #181920;
|
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
color: #e3e2e7;
|
|
}
|
|
.input-dark:focus {
|
|
border-color: #007AFF;
|
|
box-shadow: 0 0 10px rgba(0, 122, 255, 0.3);
|
|
outline: none;
|
|
}
|
|
.chip {
|
|
background-color: rgba(173, 198, 255, 0.1);
|
|
color: #ffffff;
|
|
border: 1px solid rgba(173, 198, 255, 0.3);
|
|
}
|
|
</style>
|
|
</head>
|
|
<body class="font-body-md text-body-md antialiased min-h-screen flex selection:bg-primary selection:text-on-primary">
|
|
<!-- SideNavBar Component -->
|
|
<nav class="hidden md:flex flex-col h-full py-8 h-screen fixed left-0 top-0 w-64 border-r border-white/10 shadow-[10px_0_30px_-15px_rgba(0,122,255,0.2)] bg-[#0F1014]/80 backdrop-blur-2xl z-40">
|
|
<div class="px-6 mb-8 flex items-center gap-3">
|
|
<div class="w-10 h-10 rounded-full bg-gradient-to-br from-blue-500 to-cyan-400 p-0.5">
|
|
<img alt="User Profile" class="w-full h-full rounded-full object-cover" data-alt="Close-up portrait of a young woman with natural lighting, subtle background blur, high-quality professional photography" src="https://lh3.googleusercontent.com/aida-public/AB6AXuCe_G8mDdSMWIlLiW3aBKMRw0ljyLQN8lQuS0_yMFEhjzDIKoe33IJaWfOIOBts14PZb6rXQDhow4BGwoTgoTe6uFLWYfDtjuwow1CAY5UM6O9ZqLYVIbRMx2MmMqMVY6A0WRKOfIEkskYWuoU9dAWtQvIJvov34E6i5pCqhZBjcNL5bGjpsdotbd4skKJtxgUz8XhVkS-3hhZI9ChoZUOskixxOsI4mZgKbBjshcAZAeoAYoNBN1rwl-YzXm75MwvUKoQaDCDRHUg"/>
|
|
</div>
|
|
<div>
|
|
<h2 class="font-headline-md text-headline-md text-blue-500 font-bold uppercase tracking-widest text-sm">Command Center</h2>
|
|
<p class="font-label-sm text-label-sm text-slate-400">Premium Tier</p>
|
|
</div>
|
|
</div>
|
|
<div class="flex-1 overflow-y-auto space-y-1 mt-4">
|
|
<a class="text-slate-500 flex items-center gap-4 px-6 py-4 hover:bg-white/5 hover:text-white transition-colors group" href="#">
|
|
<span class="material-symbols-outlined group-hover:translate-x-1 transition-transform duration-200">live_tv</span>
|
|
<span class="font-['Space_Grotesk'] text-sm font-medium">Live TV</span>
|
|
</a>
|
|
<a class="text-slate-500 flex items-center gap-4 px-6 py-4 hover:bg-white/5 hover:text-white transition-colors group" href="#">
|
|
<span class="material-symbols-outlined group-hover:translate-x-1 transition-transform duration-200">movie</span>
|
|
<span class="font-['Space_Grotesk'] text-sm font-medium">Movies</span>
|
|
</a>
|
|
<a class="text-slate-500 flex items-center gap-4 px-6 py-4 hover:bg-white/5 hover:text-white transition-colors group" href="#">
|
|
<span class="material-symbols-outlined group-hover:translate-x-1 transition-transform duration-200">theaters</span>
|
|
<span class="font-['Space_Grotesk'] text-sm font-medium">Series</span>
|
|
</a>
|
|
<a class="text-slate-500 flex items-center gap-4 px-6 py-4 hover:bg-white/5 hover:text-white transition-colors group" href="#">
|
|
<span class="material-symbols-outlined group-hover:translate-x-1 transition-transform duration-200">fiber_manual_record</span>
|
|
<span class="font-['Space_Grotesk'] text-sm font-medium">Recordings</span>
|
|
</a>
|
|
<a class="bg-blue-500/10 text-blue-400 border-l-4 border-blue-500 flex items-center gap-4 px-6 py-4 group" href="#">
|
|
<span class="material-symbols-outlined group-hover:translate-x-1 transition-transform duration-200" style="font-variation-settings: 'FILL' 1;">settings</span>
|
|
<span class="font-['Space_Grotesk'] text-sm font-medium">Settings</span>
|
|
</a>
|
|
</div>
|
|
<div class="mt-auto px-6 space-y-1">
|
|
<a class="text-slate-500 flex items-center gap-4 py-3 hover:bg-white/5 hover:text-white transition-colors group rounded-lg px-4 -mx-4" href="#">
|
|
<span class="material-symbols-outlined group-hover:translate-x-1 transition-transform duration-200">help</span>
|
|
<span class="font-['Space_Grotesk'] text-sm font-medium">Support</span>
|
|
</a>
|
|
<a class="text-slate-500 flex items-center gap-4 py-3 hover:bg-white/5 hover:text-white transition-colors group rounded-lg px-4 -mx-4" href="#">
|
|
<span class="material-symbols-outlined group-hover:translate-x-1 transition-transform duration-200">logout</span>
|
|
<span class="font-['Space_Grotesk'] text-sm font-medium">Logout</span>
|
|
</a>
|
|
</div>
|
|
</nav>
|
|
<!-- Main Content Area -->
|
|
<main class="flex-1 md:ml-64 p-margin lg:p-lg min-h-screen flex flex-col gap-lg">
|
|
<!-- Header & Tabs -->
|
|
<header class="flex flex-col gap-md">
|
|
<div>
|
|
<h1 class="font-headline-xl text-headline-xl text-on-surface mb-xs">Paramètres</h1>
|
|
<p class="font-body-lg text-body-lg text-on-surface-variant">Configuration de votre expérience XtremFlow.</p>
|
|
</div>
|
|
<div class="glass-panel rounded-lg p-1 flex gap-2 w-fit">
|
|
<button class="bg-primary/20 text-primary font-label-lg text-label-lg px-6 py-2.5 rounded-md border border-primary/30 shadow-[0_0_15px_rgba(0,122,255,0.2)] transition-all">Filtres</button>
|
|
<button class="text-on-surface-variant hover:text-on-surface hover:bg-white/5 font-label-lg text-label-lg px-6 py-2.5 rounded-md transition-all">Streaming</button>
|
|
<button class="text-on-surface-variant hover:text-on-surface hover:bg-white/5 font-label-lg text-label-lg px-6 py-2.5 rounded-md transition-all">Apparence</button>
|
|
<button class="text-on-surface-variant hover:text-on-surface hover:bg-white/5 font-label-lg text-label-lg px-6 py-2.5 rounded-md transition-all">Administration</button>
|
|
</div>
|
|
</header>
|
|
<!-- Content Grid -->
|
|
<div class="grid grid-cols-1 xl:grid-cols-3 gap-gutter flex-1">
|
|
<!-- Filtre TV Live -->
|
|
<section class="glass-floating rounded-xl p-md flex flex-col gap-md">
|
|
<div class="flex items-center gap-3 pb-sm border-b border-white/10">
|
|
<div class="w-8 h-8 rounded-full bg-primary/10 flex items-center justify-center border border-primary/20">
|
|
<span class="material-symbols-outlined text-primary text-xl">live_tv</span>
|
|
</div>
|
|
<h2 class="font-headline-lg text-headline-md text-on-surface">Filtre TV Live</h2>
|
|
</div>
|
|
<div class="flex flex-col gap-4">
|
|
<div>
|
|
<label class="font-label-sm text-label-sm text-on-surface-variant block mb-2 uppercase tracking-wider">Rechercher une catégorie</label>
|
|
<div class="relative">
|
|
<span class="material-symbols-outlined absolute left-3 top-1/2 -translate-y-1/2 text-outline">search</span>
|
|
<input class="w-full input-dark rounded-md py-2.5 pl-10 pr-4 font-body-md text-body-md transition-all" placeholder="Ex: France, Sport, Info..." type="text"/>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label class="font-label-sm text-label-sm text-on-surface-variant block mb-3 uppercase tracking-wider">Catégories Actives</label>
|
|
<div class="flex flex-wrap gap-2">
|
|
<div class="chip rounded-full px-4 py-1.5 flex items-center gap-2 cursor-pointer hover:bg-primary/20 transition-colors">
|
|
<span class="font-label-sm text-label-sm">FRANCE</span>
|
|
<span class="material-symbols-outlined text-[14px]">close</span>
|
|
</div>
|
|
<div class="chip rounded-full px-4 py-1.5 flex items-center gap-2 cursor-pointer hover:bg-primary/20 transition-colors">
|
|
<span class="font-label-sm text-label-sm">SPORT</span>
|
|
<span class="material-symbols-outlined text-[14px]">close</span>
|
|
</div>
|
|
<div class="chip rounded-full px-4 py-1.5 flex items-center gap-2 cursor-pointer hover:bg-primary/20 transition-colors">
|
|
<span class="font-label-sm text-label-sm">DOCUMENTAIRE</span>
|
|
<span class="material-symbols-outlined text-[14px]">close</span>
|
|
</div>
|
|
<div class="chip rounded-full px-4 py-1.5 flex items-center gap-2 cursor-pointer hover:bg-primary/20 transition-colors">
|
|
<span class="font-label-sm text-label-sm">MUSIQUE</span>
|
|
<span class="material-symbols-outlined text-[14px]">close</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
<!-- Filtre Films -->
|
|
<section class="glass-floating rounded-xl p-md flex flex-col gap-md">
|
|
<div class="flex items-center gap-3 pb-sm border-b border-white/10">
|
|
<div class="w-8 h-8 rounded-full bg-primary/10 flex items-center justify-center border border-primary/20">
|
|
<span class="material-symbols-outlined text-primary text-xl">movie</span>
|
|
</div>
|
|
<h2 class="font-headline-lg text-headline-md text-on-surface">Filtre Films</h2>
|
|
</div>
|
|
<div class="flex flex-col gap-4">
|
|
<div>
|
|
<label class="font-label-sm text-label-sm text-on-surface-variant block mb-2 uppercase tracking-wider">Rechercher une catégorie</label>
|
|
<div class="relative">
|
|
<span class="material-symbols-outlined absolute left-3 top-1/2 -translate-y-1/2 text-outline">search</span>
|
|
<input class="w-full input-dark rounded-md py-2.5 pl-10 pr-4 font-body-md text-body-md transition-all" placeholder="Ex: Action, VF, 4K..." type="text"/>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label class="font-label-sm text-label-sm text-on-surface-variant block mb-3 uppercase tracking-wider">Catégories Actives</label>
|
|
<div class="flex flex-wrap gap-2">
|
|
<div class="chip rounded-full px-4 py-1.5 flex items-center gap-2 cursor-pointer hover:bg-primary/20 transition-colors">
|
|
<span class="font-label-sm text-label-sm">VF</span>
|
|
<span class="material-symbols-outlined text-[14px]">close</span>
|
|
</div>
|
|
<div class="chip rounded-full px-4 py-1.5 flex items-center gap-2 cursor-pointer hover:bg-primary/20 transition-colors">
|
|
<span class="font-label-sm text-label-sm">ACTION</span>
|
|
<span class="material-symbols-outlined text-[14px]">close</span>
|
|
</div>
|
|
<div class="chip rounded-full px-4 py-1.5 flex items-center gap-2 cursor-pointer hover:bg-primary/20 transition-colors">
|
|
<span class="font-label-sm text-label-sm">SCI-FI</span>
|
|
<span class="material-symbols-outlined text-[14px]">close</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
<!-- Filtre Séries -->
|
|
<section class="glass-floating rounded-xl p-md flex flex-col gap-md">
|
|
<div class="flex items-center gap-3 pb-sm border-b border-white/10">
|
|
<div class="w-8 h-8 rounded-full bg-primary/10 flex items-center justify-center border border-primary/20">
|
|
<span class="material-symbols-outlined text-primary text-xl">theaters</span>
|
|
</div>
|
|
<h2 class="font-headline-lg text-headline-md text-on-surface">Filtre Séries</h2>
|
|
</div>
|
|
<div class="flex flex-col gap-4">
|
|
<div>
|
|
<label class="font-label-sm text-label-sm text-on-surface-variant block mb-2 uppercase tracking-wider">Rechercher une catégorie</label>
|
|
<div class="relative">
|
|
<span class="material-symbols-outlined absolute left-3 top-1/2 -translate-y-1/2 text-outline">search</span>
|
|
<input class="w-full input-dark rounded-md py-2.5 pl-10 pr-4 font-body-md text-body-md transition-all" placeholder="Ex: Netflix, VOSTFR, Drame..." type="text"/>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label class="font-label-sm text-label-sm text-on-surface-variant block mb-3 uppercase tracking-wider">Catégories Actives</label>
|
|
<div class="flex flex-wrap gap-2">
|
|
<div class="chip rounded-full px-4 py-1.5 flex items-center gap-2 cursor-pointer hover:bg-primary/20 transition-colors">
|
|
<span class="font-label-sm text-label-sm">NETFLIX</span>
|
|
<span class="material-symbols-outlined text-[14px]">close</span>
|
|
</div>
|
|
<div class="chip rounded-full px-4 py-1.5 flex items-center gap-2 cursor-pointer hover:bg-primary/20 transition-colors">
|
|
<span class="font-label-sm text-label-sm">VOSTFR</span>
|
|
<span class="material-symbols-outlined text-[14px]">close</span>
|
|
</div>
|
|
<div class="chip rounded-full px-4 py-1.5 flex items-center gap-2 cursor-pointer hover:bg-primary/20 transition-colors">
|
|
<span class="font-label-sm text-label-sm">DRAME</span>
|
|
<span class="material-symbols-outlined text-[14px]">close</span>
|
|
</div>
|
|
<div class="chip rounded-full px-4 py-1.5 flex items-center gap-2 cursor-pointer hover:bg-primary/20 transition-colors">
|
|
<span class="font-label-sm text-label-sm">HBO</span>
|
|
<span class="material-symbols-outlined text-[14px]">close</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
<!-- Action Buttons -->
|
|
<div class="flex justify-end gap-4 mt-auto pt-8 border-t border-white/10">
|
|
<button class="px-6 py-2.5 rounded-md border border-outline-variant text-on-surface hover:bg-surface-variant transition-colors font-label-lg text-label-lg glass-panel">Annuler</button>
|
|
<button class="bg-gradient-to-r from-[#007AFF] to-[#00A8FF] text-white px-8 py-2.5 rounded-md font-label-lg text-label-lg hover:shadow-[0_0_20px_rgba(0,122,255,0.4)] transition-all">Sauvegarder les filtres</button>
|
|
</div>
|
|
</main>
|
|
</body></html> |