Initial commit

This commit is contained in:
2026-03-23 20:59:26 +01:00
commit 16c95f747b
56 changed files with 21177 additions and 0 deletions

880
app/templates/admin.html Normal file
View File

@@ -0,0 +1,880 @@
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Lycostorrent - Administration</title>
<!-- Chargement du thème (en premier pour éviter le flash) -->
<script src="/static/js/theme-loader.js"></script>
<!-- PWA Meta Tags -->
<meta name="theme-color" content="#e63946">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="Lycostorrent">
<!-- PWA Manifest -->
<link rel="manifest" href="/static/manifest.json">
<!-- Icons -->
<link rel="icon" type="image/png" sizes="192x192" href="/static/icons/icon-192x192.png">
<link rel="apple-touch-icon" href="/static/icons/icon-192x192.png">
<link rel="stylesheet" href="/static/css/style.css">
<link rel="stylesheet" href="/static/css/themes.css">
<link rel="stylesheet" href="/static/css/admin.css">
</head>
<body>
<div class="container">
<!-- Header -->
<header class="header">
<h1>⚙️ Administration</h1>
<p class="subtitle">Configuration de Lycostorrent</p>
<nav class="main-nav" id="mainNav">
<!-- Navigation générée dynamiquement -->
</nav>
</header>
<!-- Onglets -->
<div class="admin-tabs">
<button class="tab-btn active" data-tab="modules">
<span class="tab-icon">🧩</span>
<span class="tab-label">Modules</span>
</button>
<button class="tab-btn" data-tab="categories">
<span class="tab-icon">📂</span>
<span class="tab-label">Catégories</span>
</button>
<button class="tab-btn" data-tab="tags">
<span class="tab-icon">🏷️</span>
<span class="tab-label">Tags</span>
</button>
<button class="tab-btn" data-tab="filters">
<span class="tab-icon">🎛️</span>
<span class="tab-label">Filtres</span>
</button>
<button class="tab-btn" data-tab="rss">
<span class="tab-icon">📡</span>
<span class="tab-label">Flux RSS</span>
</button>
<button class="tab-btn" data-tab="cache">
<span class="tab-icon">🔄</span>
<span class="tab-label">Cache</span>
</button>
<button class="tab-btn" data-tab="torrent-client">
<span class="tab-icon">⬇️</span>
<span class="tab-label">Client Torrent</span>
</button>
<button class="tab-btn" data-tab="appearance">
<span class="tab-icon">🎨</span>
<span class="tab-label">Apparence</span>
</button>
</div>
<!-- Contenu des onglets -->
<div class="admin-content">
<!-- ═══════════════════════════════════════════════════════════
ONGLET MODULES
═══════════════════════════════════════════════════════════ -->
<div id="tab-modules" class="tab-content active">
<div class="tab-header">
<h2>🧩 Modules</h2>
<p>Activez ou désactivez les fonctionnalités de Lycostorrent.</p>
</div>
<div class="admin-card">
<h3>📱 Fonctionnalités disponibles</h3>
<p class="help-text">Cochez les modules que vous souhaitez activer. La navigation s'adaptera automatiquement.</p>
<div class="modules-list">
<div class="module-item">
<div class="module-toggle">
<input type="checkbox" id="module-search" checked>
<label for="module-search"></label>
</div>
<div class="module-info">
<div class="module-header">
<span class="module-icon">🔍</span>
<span class="module-name">Recherche</span>
</div>
<p class="module-description">Recherche de torrents sur vos trackers configurés (Jackett/Prowlarr).</p>
</div>
</div>
<div class="module-item">
<div class="module-toggle">
<input type="checkbox" id="module-latest" checked>
<label for="module-latest"></label>
</div>
<div class="module-info">
<div class="module-header">
<span class="module-icon">🎬</span>
<span class="module-name">Nouveautés</span>
</div>
<p class="module-description">Dernières sorties depuis vos trackers (Films, Séries, Anime, Musique).</p>
</div>
</div>
<div class="module-item">
<div class="module-toggle">
<input type="checkbox" id="module-discover">
<label for="module-discover"></label>
</div>
<div class="module-info">
<div class="module-header">
<span class="module-icon">🌟</span>
<span class="module-name">Découvrir</span>
<span class="module-badge">Nouveau</span>
</div>
<p class="module-description">Explorez les nouveautés cinéma et TV depuis TMDb, puis trouvez les torrents disponibles.</p>
</div>
</div>
</div>
<div class="action-bar">
<button id="saveModulesBtn" class="btn btn-primary">💾 Sauvegarder</button>
</div>
</div>
<!-- Configuration des trackers pour Discover -->
<div class="admin-card" id="discoverTrackersCard">
<h3>🌟 Trackers pour Découvrir</h3>
<p class="help-text">Sélectionnez les trackers à utiliser pour la recherche de torrents dans la page Découvrir.</p>
<div class="discover-trackers-list" id="discoverTrackersList">
<p class="loading">Chargement des trackers...</p>
</div>
<div class="action-bar">
<button id="selectAllDiscoverTrackers" class="btn btn-secondary">✅ Tout sélectionner</button>
<button id="selectNoneDiscoverTrackers" class="btn btn-secondary">❌ Tout désélectionner</button>
<button id="saveDiscoverTrackers" class="btn btn-primary">💾 Sauvegarder</button>
</div>
</div>
<div class="admin-card">
<h3> À propos des modules</h3>
<div class="module-help">
<p><strong>🔍 Recherche</strong> : Page d'accueil par défaut. Permet de rechercher des torrents par mots-clés sur tous vos trackers.</p>
<p><strong>🎬 Nouveautés</strong> : Affiche les derniers torrents publiés sur vos trackers, enrichis avec les métadonnées TMDb/Last.fm.</p>
<p><strong>🌟 Découvrir</strong> : Inverse la logique - part des nouveautés TMDb (films/séries récents) et recherche les torrents disponibles.</p>
</div>
</div>
</div>
<!-- ═══════════════════════════════════════════════════════════
ONGLET CATÉGORIES
═══════════════════════════════════════════════════════════ -->
<div id="tab-categories" class="tab-content">
<div class="tab-header">
<h2>📂 Configuration des Catégories</h2>
<p>Associez les catégories Jackett/Prowlarr à chaque type de contenu pour chaque tracker.</p>
</div>
<!-- Sélection du tracker -->
<div class="admin-card">
<h3>1. Sélectionner un tracker</h3>
<div id="trackerSelector" class="tracker-grid">
<p class="loading">Chargement des trackers...</p>
</div>
</div>
<!-- Catégories disponibles -->
<div id="categoriesSection" class="admin-card hidden">
<h3>2. Catégories disponibles sur <span id="selectedTrackerName" class="highlight"></span></h3>
<div id="availableCategories" class="categories-cloud">
<p class="loading">Chargement...</p>
</div>
</div>
<!-- Configuration -->
<div id="configSection" class="admin-card hidden">
<h3>3. Associer les catégories</h3>
<p class="help-text">Cliquez sur une catégorie ci-dessus pour l'ajouter, ou entrez les IDs manuellement.</p>
<div class="config-grid">
<div class="config-item">
<label>🎥 Films</label>
<input type="text" id="config-movies" placeholder="Ex: 2000,2010">
<div class="quick-add" data-target="movies"></div>
</div>
<div class="config-item">
<label>📺 Séries</label>
<input type="text" id="config-tv" placeholder="Ex: 5000,5010">
<div class="quick-add" data-target="tv"></div>
</div>
<div class="config-item">
<label>🎌 Anime</label>
<input type="text" id="config-anime" placeholder="Ex: 5070">
<div class="quick-add" data-target="anime"></div>
</div>
<div class="config-item">
<label>🎵 Musique</label>
<input type="text" id="config-music" placeholder="Ex: 3000">
<div class="quick-add" data-target="music"></div>
</div>
</div>
<div class="action-bar">
<button id="saveConfigBtn" class="btn btn-primary">💾 Sauvegarder</button>
<button id="resetConfigBtn" class="btn btn-secondary">🔄 Réinitialiser</button>
</div>
</div>
<!-- Résumé -->
<div class="admin-card">
<h3>📋 Configuration actuelle</h3>
<div id="configSummary" class="config-summary">
<p class="loading">Chargement...</p>
</div>
</div>
</div>
<!-- ═══════════════════════════════════════════════════════════
ONGLET TAGS
═══════════════════════════════════════════════════════════ -->
<div id="tab-tags" class="tab-content">
<div class="tab-header">
<h2>🏷️ Tags de Parsing</h2>
<p>Ces tags sont utilisés pour nettoyer les titres avant la recherche TMDb/Last.fm.</p>
</div>
<!-- Tags actuels -->
<div class="admin-card">
<h3>Tags de coupure</h3>
<p class="help-text">Le titre sera coupé au premier tag rencontré. Ex: <code>Avatar.2009.MULTi.1080p</code><code>Avatar 2009</code></p>
<div id="tagsList" class="tags-cloud editable">
<p class="loading">Chargement...</p>
</div>
<div class="add-form">
<input type="text" id="newTagInput" placeholder="Nouveau tag..." maxlength="30">
<button id="addTagBtn" class="btn btn-primary"> Ajouter</button>
</div>
<div class="action-bar">
<button id="saveTagsBtn" class="btn btn-primary">💾 Sauvegarder</button>
<button id="resetTagsBtn" class="btn btn-secondary">🔄 Réinitialiser</button>
</div>
</div>
<!-- Présets -->
<div class="admin-card">
<h3>📦 Ajouter des présets</h3>
<div class="presets-grid">
<button class="preset-btn" data-preset="langues">
🗣️ Langues
<small>VFF, VFQ, VOSTFR...</small>
</button>
<button class="preset-btn" data-preset="resolutions">
📺 Résolutions
<small>1080p, 720p, 4K...</small>
</button>
<button class="preset-btn" data-preset="sources">
📀 Sources
<small>BluRay, WEB, HDTV...</small>
</button>
<button class="preset-btn" data-preset="codecs">
🎬 Codecs
<small>x264, x265, HEVC...</small>
</button>
<button class="preset-btn" data-preset="audio">
🔊 Audio
<small>DTS, AC3, FLAC...</small>
</button>
</div>
</div>
<!-- Test -->
<div class="admin-card">
<h3>🧪 Tester le parsing</h3>
<div class="test-form">
<input type="text" id="testTitleInput" placeholder="Ex: Avatar.2009.MULTi.1080p.BluRay.x264">
<button id="testParsingBtn" class="btn btn-primary">Tester</button>
</div>
<div id="testResult" class="test-result hidden">
<div class="result-row">
<span class="label">Original:</span>
<span id="testOriginal" class="value"></span>
</div>
<div class="result-row success">
<span class="label">Nettoyé:</span>
<span id="testCleaned" class="value"></span>
</div>
</div>
</div>
</div>
<!-- ═══════════════════════════════════════════════════════════
ONGLET FILTRES
═══════════════════════════════════════════════════════════ -->
<div id="tab-filters" class="tab-content">
<div class="tab-header">
<h2>🎛️ Filtres de Recherche</h2>
<p>Configurez les mots-clés détectés dans les titres de torrents pour créer les filtres.</p>
</div>
<!-- Liste des filtres -->
<div class="admin-card">
<h3>Filtres configurés</h3>
<p class="help-text">Cliquez sur un filtre pour modifier ses valeurs. Les valeurs sont détectées dans les titres de torrents.</p>
<div id="filtersList" class="filters-editor">
<p class="loading">Chargement...</p>
</div>
<div class="action-bar">
<button id="saveFiltersBtn" class="btn btn-primary">💾 Sauvegarder</button>
<button id="resetFiltersBtn" class="btn btn-secondary">🔄 Réinitialiser</button>
<button id="addFilterBtn" class="btn btn-secondary"> Nouveau filtre</button>
</div>
</div>
<!-- Test -->
<div class="admin-card">
<h3>🧪 Tester la détection</h3>
<p class="help-text">Entrez un titre de torrent pour voir les filtres détectés.</p>
<div class="test-form">
<input type="text" id="testFilterInput" placeholder="Ex: Gojira.-.Fortitude.2021.FLAC.24bit.WEB.Album">
<button id="testFilterBtn" class="btn btn-primary">Tester</button>
</div>
<div id="filterTestResult" class="test-result hidden"></div>
</div>
<!-- Aide -->
<div class="admin-card collapsible collapsed">
<h3 class="collapsible-header">
❓ Aide - Comment ça marche
<span class="collapse-icon"></span>
</h3>
<div class="collapsible-content">
<div class="help-section">
<h4>Principe</h4>
<p>Le parser analyse les titres de torrents et cherche les mots-clés configurés. Chaque mot trouvé crée une option de filtre.</p>
<h4>Exemple</h4>
<p><code>Gojira.-.Fortitude.2021.FLAC.24bit.WEB.Album</code></p>
<p>→ Format Audio: <strong>FLAC, 24bit</strong> | Type: <strong>Album</strong> | Source: <strong>WEB</strong></p>
<h4>Conseils</h4>
<ul>
<li>Les mots-clés sont insensibles à la casse (FLAC = flac = Flac)</li>
<li>Évitez les mots trop courts ou trop communs</li>
<li>Testez vos modifications avant de sauvegarder</li>
</ul>
</div>
</div>
</div>
</div>
<!-- ═══════════════════════════════════════════════════════════
ONGLET RSS
═══════════════════════════════════════════════════════════ -->
<div id="tab-rss" class="tab-content">
<div class="tab-header">
<h2>📡 Flux RSS</h2>
<p>Ajoutez des flux RSS pour les trackers non disponibles dans Jackett/Prowlarr.</p>
</div>
<!-- Formulaire d'ajout -->
<div class="admin-card">
<h3> Ajouter un flux</h3>
<form id="add-feed-form" class="rss-form">
<div class="form-row">
<div class="form-group">
<label for="feed-name">Nom *</label>
<input type="text" id="feed-name" placeholder="Ex: YGG Films" required>
</div>
<div class="form-group">
<label for="feed-category">Catégorie *</label>
<select id="feed-category" required>
<option value="">-- Choisir --</option>
<option value="movies">🎬 Films</option>
<option value="tv">📺 Séries</option>
<option value="anime">🎌 Anime</option>
<option value="music">🎵 Musique</option>
<option value="all">📦 Toutes</option>
</select>
</div>
</div>
<div class="form-group">
<label for="feed-url">URL du flux RSS *</label>
<input type="url" id="feed-url" placeholder="https://tracker.xxx/rss?passkey={passkey}" required>
<small>Utilisez <code>{passkey}</code> comme placeholder</small>
</div>
<div class="form-group">
<label for="feed-passkey">Passkey</label>
<input type="text" id="feed-passkey" placeholder="Votre passkey privé">
</div>
<div class="form-row">
<div class="form-group checkbox-inline">
<label>
<input type="checkbox" id="feed-flaresolverr">
<span>🛡️ Flaresolverr</span>
</label>
<small>Anti-Cloudflare</small>
</div>
</div>
<div class="form-group">
<label for="feed-cookies">Cookies de session</label>
<textarea id="feed-cookies" rows="2" placeholder="ygg_=abc123; cf_clearance=xyz789"></textarea>
<small>Récupérez-les depuis DevTools (F12) → Application → Cookies</small>
</div>
<div class="action-bar">
<button type="button" id="test-feed-btn" class="btn btn-secondary">🧪 Tester</button>
<button type="submit" class="btn btn-primary"> Ajouter</button>
</div>
</form>
<div id="test-result" class="test-result hidden"></div>
</div>
<!-- Liste des flux -->
<div class="admin-card">
<h3>📋 Flux configurés</h3>
<div id="feeds-list" class="feeds-list">
<p class="loading">Chargement...</p>
</div>
</div>
<!-- Aide -->
<div class="admin-card collapsible">
<h3 class="collapsible-header">
❓ Aide - Comment configurer un flux RSS
<span class="collapse-icon"></span>
</h3>
<div class="collapsible-content">
<div class="help-section">
<h4>YGGTorrent</h4>
<ol>
<li>Connectez-vous à YGG</li>
<li>Profil → "Mon RSS"</li>
<li>Copiez l'URL avec votre passkey</li>
</ol>
<h4>Catégories YGG</h4>
<div class="help-table">
<span class="help-row"><code>id=2145</code> Films</span>
<span class="help-row"><code>id=2184</code> Séries</span>
<span class="help-row"><code>id=2179</code> Anime</span>
<span class="help-row"><code>id=2139</code> Musique</span>
</div>
</div>
</div>
</div>
</div>
<!-- ═══════════════════════════════════════════════════════════
ONGLET CACHE
═══════════════════════════════════════════════════════════ -->
<div id="tab-cache" class="tab-content">
<div class="tab-header">
<h2>🔄 Cache des données</h2>
<p>Pré-chargez les données Latest et Discover pour un affichage instantané.</p>
</div>
<!-- Statut du cache -->
<div class="admin-card">
<h3>📊 Statut du cache</h3>
<div id="cacheStatus" class="cache-status">
<div class="status-row">
<span class="status-label">État :</span>
<span id="cacheStatusBadge" class="status-badge">Chargement...</span>
</div>
<div class="status-row">
<span class="status-label">Dernier refresh :</span>
<span id="cacheLastRefresh">-</span>
</div>
<div class="status-row">
<span class="status-label">Prochain refresh :</span>
<span id="cacheNextRefresh">-</span>
</div>
<div class="status-row">
<span class="status-label">Taille du cache :</span>
<span id="cacheSizeDisplay">-</span>
</div>
</div>
<div class="action-bar" style="margin-top: 15px;">
<button id="refreshCacheBtn" class="btn btn-primary">🔄 Forcer le refresh maintenant</button>
<button id="clearCacheBtn" class="btn btn-secondary">🗑️ Vider le cache</button>
</div>
</div>
<!-- Configuration -->
<div class="admin-card">
<h3>⚙️ Configuration</h3>
<div class="form-row">
<div class="form-group">
<label for="cacheEnabled">
<input type="checkbox" id="cacheEnabled">
Activer le cache automatique
</label>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="cacheInterval">Intervalle de refresh</label>
<select id="cacheInterval">
<option value="15">15 minutes</option>
<option value="30">30 minutes</option>
<option value="60" selected>1 heure</option>
<option value="120">2 heures</option>
<option value="240">4 heures</option>
<option value="360">6 heures</option>
</select>
</div>
</div>
</div>
<!-- Configuration Latest -->
<div class="admin-card">
<h3>📥 Cache Latest (Nouveautés)</h3>
<div class="form-row">
<div class="form-group">
<label for="cacheLatestEnabled">
<input type="checkbox" id="cacheLatestEnabled" checked>
Activer le cache Latest
</label>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label>Catégories à cacher :</label>
<div class="checkbox-group">
<label><input type="checkbox" id="cacheLatestMovies" checked> 🎥 Films</label>
<label><input type="checkbox" id="cacheLatestTv" checked> 📺 Séries</label>
<label><input type="checkbox" id="cacheLatestAnime"> 🎌 Anime</label>
<label><input type="checkbox" id="cacheLatestMusic"> 🎵 Musique</label>
</div>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="cacheLatestLimit">Nombre de résultats par catégorie</label>
<select id="cacheLatestLimit">
<option value="30">30</option>
<option value="50" selected>50</option>
<option value="100">100</option>
</select>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label>Trackers à utiliser :</label>
<p class="help-text">Laissez vide pour utiliser tous les trackers actifs</p>
<div id="cacheTrackersList" class="checkbox-group trackers-checkboxes">
<!-- Rempli dynamiquement -->
</div>
</div>
</div>
</div>
<!-- Configuration Discover -->
<div class="admin-card">
<h3>🎬 Cache Discover</h3>
<div class="form-row">
<div class="form-group">
<label for="cacheDiscoverEnabled">
<input type="checkbox" id="cacheDiscoverEnabled" checked>
Activer le cache Discover
</label>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="cacheDiscoverLimit">Nombre de films/séries à cacher</label>
<select id="cacheDiscoverLimit">
<option value="20">20</option>
<option value="30" selected>30</option>
<option value="50">50</option>
</select>
</div>
</div>
</div>
<!-- Sauvegarder -->
<div class="admin-card">
<div class="action-bar">
<button id="saveCacheConfigBtn" class="btn btn-primary">💾 Sauvegarder la configuration</button>
</div>
</div>
</div>
<!-- ═══════════════════════════════════════════════════════════
ONGLET CLIENT TORRENT
═══════════════════════════════════════════════════════════ -->
<div id="tab-torrent-client" class="tab-content">
<div class="tab-header">
<h2>⬇️ Client Torrent</h2>
<p>Configurez votre client torrent pour envoyer directement les téléchargements.</p>
</div>
<!-- Statut -->
<div class="admin-card">
<h3>📊 Statut</h3>
<div id="torrentClientStatus" class="client-status">
<span class="status-loading">Chargement...</span>
</div>
</div>
<!-- Configuration -->
<div class="admin-card">
<h3>⚙️ Configuration</h3>
<div class="form-row">
<div class="form-group">
<label for="tcEnabled">
<input type="checkbox" id="tcEnabled">
Activer le client torrent
</label>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="tcPlugin">Client</label>
<select id="tcPlugin">
<option value="">-- Sélectionner --</option>
</select>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="tcHost">Hôte</label>
<input type="text" id="tcHost" placeholder="geco.useed.me ou 192.168.1.x">
<small class="form-help">Domaine ou IP (sans http://)</small>
</div>
<div class="form-group">
<label for="tcPort">Port</label>
<input type="number" id="tcPort" placeholder="8080 ou vide">
<small class="form-help">Laisser vide si port par défaut</small>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="tcPath">Chemin (optionnel)</label>
<input type="text" id="tcPath" placeholder="/qbittorrent">
<small class="form-help">Si derrière un reverse proxy</small>
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="tcUsername">Utilisateur</label>
<input type="text" id="tcUsername" placeholder="admin">
</div>
<div class="form-group">
<label for="tcPassword">Mot de passe</label>
<input type="password" id="tcPassword" placeholder="••••••••">
</div>
</div>
<div class="form-row">
<div class="form-group">
<label for="tcSSL">
<input type="checkbox" id="tcSSL">
Utiliser SSL (HTTPS)
</label>
</div>
</div>
<div class="action-bar">
<button id="testTorrentClientBtn" class="btn btn-secondary">🔌 Tester la connexion</button>
<button id="saveTorrentClientBtn" class="btn btn-primary">💾 Sauvegarder</button>
</div>
<div id="tcTestResult" class="test-result hidden"></div>
</div>
<!-- Catégories personnalisées -->
<div class="admin-card">
<h3>📁 Catégories & Dossiers</h3>
<p class="help-text">Définissez vos catégories avec leur dossier de destination par défaut.</p>
<div id="customCategoriesList" class="custom-categories-list">
<!-- Rempli dynamiquement -->
</div>
<div class="add-category-form">
<div class="form-row">
<div class="form-group">
<label for="newCategoryName">Nom de la catégorie</label>
<input type="text" id="newCategoryName" placeholder="Films, Séries, Musique...">
</div>
<div class="form-group">
<label for="newCategoryPath">Chemin de destination</label>
<input type="text" id="newCategoryPath" placeholder="/downloads/films">
</div>
<div class="form-group form-group-btn">
<button id="addCategoryBtn" class="btn btn-success"> Ajouter</button>
</div>
</div>
</div>
<div class="action-bar">
<button id="syncCategoriesBtn" class="btn btn-secondary">🔄 Synchroniser avec le client</button>
<button id="saveCategoriesBtn" class="btn btn-primary">💾 Sauvegarder</button>
</div>
</div>
<!-- Plugins disponibles -->
<div class="admin-card collapsible collapsed">
<h3 class="collapsible-header">
🔌 Plugins disponibles
<span class="collapse-icon"></span>
</h3>
<div class="collapsible-content">
<div id="pluginsList" class="plugins-list">
<p class="loading">Chargement...</p>
</div>
<p class="help-text">
Pour ajouter un nouveau client, créez un plugin dans <code>plugins/torrent_clients/</code>
</p>
</div>
</div>
</div>
<!-- ═══════════════════════════════════════════════════════════
ONGLET APPARENCE
═══════════════════════════════════════════════════════════ -->
<div id="tab-appearance" class="tab-content">
<div class="tab-header">
<h2>🎨 Apparence</h2>
<p>Personnalisez l'apparence de Lycostorrent.</p>
</div>
<!-- Sélection du thème -->
<div class="admin-card">
<h3>🎭 Thème</h3>
<p class="help-text">Choisissez un thème pour l'interface.</p>
<div class="theme-grid">
<div class="theme-card" data-theme="dark">
<div class="theme-preview theme-preview-dark">
<div class="preview-header"></div>
<div class="preview-content">
<div class="preview-card"></div>
<div class="preview-card"></div>
</div>
</div>
<span class="theme-name">🌙 Sombre</span>
</div>
<div class="theme-card" data-theme="light">
<div class="theme-preview theme-preview-light">
<div class="preview-header"></div>
<div class="preview-content">
<div class="preview-card"></div>
<div class="preview-card"></div>
</div>
</div>
<span class="theme-name">☀️ Clair</span>
</div>
<div class="theme-card" data-theme="ocean">
<div class="theme-preview theme-preview-ocean">
<div class="preview-header"></div>
<div class="preview-content">
<div class="preview-card"></div>
<div class="preview-card"></div>
</div>
</div>
<span class="theme-name">🌊 Océan</span>
</div>
<div class="theme-card" data-theme="purple">
<div class="theme-preview theme-preview-purple">
<div class="preview-header"></div>
<div class="preview-content">
<div class="preview-card"></div>
<div class="preview-card"></div>
</div>
</div>
<span class="theme-name">💜 Violet</span>
</div>
<div class="theme-card" data-theme="nature">
<div class="theme-preview theme-preview-nature">
<div class="preview-header"></div>
<div class="preview-content">
<div class="preview-card"></div>
<div class="preview-card"></div>
</div>
</div>
<span class="theme-name">🌿 Nature</span>
</div>
<div class="theme-card" data-theme="sunset">
<div class="theme-preview theme-preview-sunset">
<div class="preview-header"></div>
<div class="preview-content">
<div class="preview-card"></div>
<div class="preview-card"></div>
</div>
</div>
<span class="theme-name">🌅 Sunset</span>
</div>
<div class="theme-card" data-theme="cyberpunk">
<div class="theme-preview theme-preview-cyberpunk">
<div class="preview-header"></div>
<div class="preview-content">
<div class="preview-card"></div>
<div class="preview-card"></div>
</div>
</div>
<span class="theme-name">🤖 Cyberpunk</span>
</div>
<div class="theme-card" data-theme="nord">
<div class="theme-preview theme-preview-nord">
<div class="preview-header"></div>
<div class="preview-content">
<div class="preview-card"></div>
<div class="preview-card"></div>
</div>
</div>
<span class="theme-name">❄️ Nord</span>
</div>
</div>
</div>
</div>
</div>
<!-- Message toast -->
<div id="toast" class="toast hidden"></div>
<!-- Footer -->
<footer class="app-footer">
<span>Lycostorrent v<span id="app-version">1.0.0</span></span>
</footer>
</div>
<script src="/static/js/admin.js"></script>
<script src="/static/js/nav.js"></script>
<script>
fetch('/api/version').then(r => r.json()).then(data => {
if (data.version) document.getElementById('app-version').textContent = data.version;
}).catch(() => {});
</script>
</body>
</html>