feat: Add series TV support with Vidzy HLS downloads and duplicate prevention
Major improvements: - Series TV support via FS7 provider with dedicated search endpoint - Vidzy downloader now uses Playwright for JS obfuscation and ffmpeg for HLS streams - Episode filenames properly named (Series Title - Episode X) instead of master.m3u8.mp4 - Duplicate download prevention: checks existing tasks before creating new ones - Removed host preference system in favor of intelligent URL-based detection Technical changes: - Vidzy: Added Playwright extraction and M3U8→MP4 conversion with ffmpeg - FS7: Episodes now use pipe format (video_url|series_url|episode_title) - DownloadManager: Extract target_filename from pipe URL and prevent duplicates - UI: New Series tab with search, recommendations, and releases sections - Anime-Sama: Removed hardcoded host preferences, uses site's URL order Generated with [Claude Code](https://claude.com/claude-code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
This commit is contained in:
@@ -14,6 +14,7 @@
|
||||
<script src="/static/js/downloads.js?v=1.5" defer></script>
|
||||
<script src="/static/js/anime.js?v=1.5" defer></script>
|
||||
<script src="/static/js/anime-details.js?v=1.5" defer></script>
|
||||
<script src="/static/js/series-search.js?v=1.5" defer></script>
|
||||
<script src="/static/js/recommendations.js?v=1.5" defer></script>
|
||||
<script src="/static/js/tabs.js?v=1.5" defer></script>
|
||||
<script src="/static/js/main.js?v=1.5" defer></script>
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
{# Template pour un onglet de provider anime spécifique #}
|
||||
{# Variables disponibles: provider_id, provider_info #}
|
||||
<div id="tab-anime-{{ provider_id }}" class="tab-content">
|
||||
<div class="url-form">
|
||||
<div class="anime-input-group">
|
||||
<input
|
||||
type="text"
|
||||
id="searchInput-{{ provider_id }}"
|
||||
placeholder="Rechercher un anime sur {{ provider_info.name }}..."
|
||||
onkeypress="if(event.key === 'Enter') searchAnimeProvider('{{ provider_id }}')"
|
||||
>
|
||||
<select id="langSelect-{{ provider_id }}" style="max-width: 120px;">
|
||||
<option value="vostfr">VOSTFR</option>
|
||||
<option value="vf">VF</option>
|
||||
</select>
|
||||
<button type="button" class="btn-primary" onclick="searchAnimeProvider('{{ provider_id }}')">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
|
||||
</svg>
|
||||
Rechercher
|
||||
</button>
|
||||
</div>
|
||||
<div style="display: flex; align-items: center; gap: 10px; margin-top: 10px; font-size: 13px; color: #888;">
|
||||
<input type="checkbox" id="includeMetadata-{{ provider_id }}" style="width: auto; margin: 0;">
|
||||
<label for="includeMetadata-{{ provider_id }}" style="cursor: pointer; user-select: none;">
|
||||
📊 Inclure les métadonnées
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="searchResults-{{ provider_id }}" class="search-results"></div>
|
||||
</div>
|
||||
@@ -1,28 +0,0 @@
|
||||
<!-- Direct Download Tab -->
|
||||
<div id="tab-direct" class="tab-content">
|
||||
<div class="url-form">
|
||||
<form id="downloadForm">
|
||||
<div class="input-group">
|
||||
<input
|
||||
type="text"
|
||||
id="urlInput"
|
||||
placeholder="Collez le lien de téléchargement ici..."
|
||||
required
|
||||
>
|
||||
<button type="submit" class="btn-primary">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path>
|
||||
</svg>
|
||||
Télécharger
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="supported-hosts">
|
||||
<span class="host-badge">1fichier</span>
|
||||
<span class="host-badge">Doodstream</span>
|
||||
<span class="host-badge">Rapidfile</span>
|
||||
<span class="host-badge">Anime-Sama</span>
|
||||
<span class="host-badge">Anime-Ultime</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -9,12 +9,6 @@
|
||||
</svg>
|
||||
Accueil
|
||||
</button>
|
||||
<button class="tab" data-tab-type="search" onclick="switchTab('search')">
|
||||
<svg style="width:16px;height:16px;vertical-align:middle;margin-right:5px" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
|
||||
</svg>
|
||||
Recherche
|
||||
</button>
|
||||
<button class="tab" data-tab-type="anime" onclick="switchTab('anime')">
|
||||
<svg style="width:16px;height:16px;vertical-align:middle;margin-right:5px" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14.752 11.168l-3.197-2.132A1 1 0 0010 9.87v4.263a1 1 0 001.555.832l3.197-2.132a1 1 0 000-1.664z"></path>
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
<!-- Search Tab -->
|
||||
<div id="tab-search" class="tab-content">
|
||||
<div class="url-form">
|
||||
<div class="input-group">
|
||||
<input
|
||||
type="text"
|
||||
id="searchInput"
|
||||
placeholder="Rechercher un anime (ex: Frieren, One Piece...)"
|
||||
>
|
||||
<button type="button" class="btn-primary" onclick="handleSearch()">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
|
||||
</svg>
|
||||
Rechercher
|
||||
</button>
|
||||
</div>
|
||||
<div style="margin-top: 10px; padding: 10px; background: rgba(0, 217, 255, 0.1); border-radius: 8px; font-size: 12px; color: #aaa;">
|
||||
💡 <strong>Info:</strong> La recherche utilise MyAnimeList pour afficher la fiche complète de l'anime (synopsis, saisons, etc.) et trouve les sources de streaming disponibles.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Anime details and streaming results -->
|
||||
<div id="animeSearchResults"></div>
|
||||
</div>
|
||||
+80
-16
@@ -5,37 +5,101 @@
|
||||
|
||||
{% include "components/home_section.html" %}
|
||||
|
||||
{% include "components/search_tab.html" %}
|
||||
|
||||
<!-- Nouveaux onglets -->
|
||||
<div id="tab-anime" class="tab-content">
|
||||
<!-- Anime Search Section -->
|
||||
<div class="section-header">
|
||||
<h2>🎬 Anime</h2>
|
||||
<div style="display:flex; gap:10px;">
|
||||
<button class="btn-small btn-secondary" onclick="loadAnimeReleases()">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" style="width:14px;height:14px;">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
|
||||
<h2>🎬 Rechercher un Anime</h2>
|
||||
</div>
|
||||
<div class="url-form">
|
||||
<div class="input-group">
|
||||
<input
|
||||
type="text"
|
||||
id="animeSearchInput"
|
||||
placeholder="Rechercher un anime (ex: Frieren, One Piece, Naruto...)"
|
||||
>
|
||||
<button type="button" class="btn-primary" onclick="handleAnimeSearch()">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
|
||||
</svg>
|
||||
Dernières sorties
|
||||
Rechercher
|
||||
</button>
|
||||
</div>
|
||||
<div style="margin-top: 10px; padding: 10px; background: rgba(0, 217, 255, 0.1); border-radius: 8px; font-size: 12px; color: #aaa;">
|
||||
💡 <strong>Info:</strong> La recherche utilise MyAnimeList pour afficher la fiche complète (synopsis, saisons, etc.)
|
||||
</div>
|
||||
</div>
|
||||
<div id="animeReleasesList" class="recommendations-carousel" style="margin-bottom: 40px;"></div>
|
||||
|
||||
<!-- Anime search results -->
|
||||
<div id="animeSearchResults" style="margin-bottom: 40px;"></div>
|
||||
|
||||
<hr style="border: none; border-top: 1px solid rgba(255,255,255,0.1); margin: 40px 0;">
|
||||
|
||||
<!-- Latest Releases Section -->
|
||||
<div class="section-header">
|
||||
<h2>🔥 Dernières sorties Anime</h2>
|
||||
<button class="btn-small btn-secondary" onclick="loadAnimeReleases()">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" style="width:14px;height:14px;">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
|
||||
</svg>
|
||||
Dernières sorties
|
||||
</button>
|
||||
</div>
|
||||
<div id="animeReleasesList" class="recommendations-carousel"></div>
|
||||
</div>
|
||||
|
||||
<div id="tab-series" class="tab-content">
|
||||
<!-- Series Search Section -->
|
||||
<div class="section-header">
|
||||
<h2>📺 Séries TV</h2>
|
||||
<div style="display:flex; gap:10px;">
|
||||
<button class="btn-small btn-secondary" onclick="loadSeriesReleases()">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" style="width:14px;height:14px;">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
|
||||
<h2>📺 Rechercher une Série TV</h2>
|
||||
</div>
|
||||
<div class="url-form">
|
||||
<div class="input-group">
|
||||
<input
|
||||
type="text"
|
||||
id="seriesSearchInput"
|
||||
placeholder="Rechercher une série (ex: Breaking Bad, Game of Thrones...)"
|
||||
>
|
||||
<button type="button" class="btn-primary" onclick="handleSeriesSearch()">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
|
||||
</svg>
|
||||
Dernières sorties
|
||||
Rechercher
|
||||
</button>
|
||||
</div>
|
||||
<div style="margin-top: 10px; padding: 10px; background: rgba(255, 107, 107, 0.1); border-radius: 8px; font-size: 12px; color: #aaa;">
|
||||
💡 <strong>Info:</strong> La recherche utilise FS7 pour trouver des séries TV américaines et européennes
|
||||
</div>
|
||||
</div>
|
||||
<div id="seriesReleasesList" class="releases-carousel" style="margin-bottom: 40px;"></div>
|
||||
|
||||
<!-- Series search results -->
|
||||
<div id="seriesSearchResults" style="margin-bottom: 40px;"></div>
|
||||
|
||||
<hr style="border: none; border-top: 1px solid rgba(255,255,255,0.1); margin: 40px 0;">
|
||||
|
||||
<!-- Recommendations Section -->
|
||||
<div class="section-header">
|
||||
<h2>🎯 Recommandé pour vous</h2>
|
||||
<button class="btn-small btn-secondary" onclick="loadSeriesRecommendations()">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" style="width:14px;height:14px;">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
|
||||
</svg>
|
||||
Actualiser
|
||||
</button>
|
||||
</div>
|
||||
<div id="seriesRecommendationsList" class="recommendations-carousel" style="margin-bottom: 40px;"></div>
|
||||
|
||||
<!-- Latest Releases Section -->
|
||||
<div class="section-header" style="margin-top: 40px;">
|
||||
<h2>🔥 Dernières sorties Séries TV</h2>
|
||||
<button class="btn-small btn-secondary" onclick="loadSeriesReleases()">
|
||||
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24" style="width:14px;height:14px;">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
|
||||
</svg>
|
||||
Dernières sorties
|
||||
</button>
|
||||
</div>
|
||||
<div id="seriesReleasesList" class="releases-carousel"></div>
|
||||
</div>
|
||||
|
||||
<div id="tab-providers" class="tab-content">
|
||||
|
||||
Reference in New Issue
Block a user