Files
ohm_streaming/static/js/series-search.js
T
root 535005b3d5 fix: resolve all DaisyUI audit issues
- settings.js: replace broken CSS vars with getThemeColor() helper
- base.html: add bg-primary text-primary-content active state to drawer
- All templates: btn-small -> btn-sm (DaisyUI standard)
- Delete orphan templates/components/header.html
- auth-utils.js: fix .show class -> use hidden (Tailwind)
- login.html: remove redundant auth-* classes, keep DaisyUI only
- auth-ui.js: update form selector for cleanup
- watchlist.html: fix nav active class styling
- 4 JS files (series-search, tabs, recommendations, anime-details):
  - Replace all old CSS classes with DaisyUI/Tailwind
  - Remove hardcoded colors, use theme-aware classes
  - loading-spinner -> DaisyUI loading component
  - no-results/search-results -> Tailwind utility layout
  - All badges -> DaisyUI badge variants
2026-04-11 20:20:26 +00:00

172 lines
7.9 KiB
JavaScript

/**
* Series search functionality for FS7
*/
// Handle series search
async function handleSeriesSearch() {
const searchInput = document.getElementById('seriesSearchInput');
const resultsContainer = document.getElementById('seriesSearchResults');
if (!searchInput || !resultsContainer) return;
const query = searchInput.value.trim();
if (!query) {
alert('Veuillez entrer un nom de série');
return;
}
try {
resultsContainer.innerHTML = '<div class="flex justify-center py-8"><span class="loading loading-spinner loading-md"></span><span class="ml-3 text-base-content/60">Recherche de séries TV en cours...</span></div>';
// Search on series providers using the dedicated endpoint
const response = await fetch(`${API_BASE}/series/search?q=${encodeURIComponent(query)}&lang=vf`);
const data = await response.json();
if (data.results && data.results['fs7'] && data.results['fs7'].length > 0) {
const series = data.results['fs7'];
let html = `
<div class="flex items-center gap-2 mb-4">
<h3 class="text-lg font-semibold"><i class="fa-solid fa-tv"></i> Résultats pour "${escapeHtml(query)}"</h3>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
`;
series.forEach(s => {
let coverImage = s.cover_image || '';
// Convert relative poster.php URLs to absolute URLs
if (coverImage.startsWith('/poster.php?url=')) {
const actualUrl = coverImage.replace('/poster.php?url=', '');
coverImage = actualUrl;
} else if (coverImage.startsWith('/')) {
coverImage = 'https://fs7.lol' + coverImage;
}
html += `
<div class="card bg-base-200 border border-base-300 shadow-sm" id="series-fs7-${encodeURIComponent(s.url)}">
<div class="card-body p-4">
<div class="flex justify-between items-start">
<h4 class="font-semibold text-base">${escapeHtml(s.title)}</h4>
<span class="badge badge-sm badge-ghost"><i class="fa-solid fa-tv"></i> French Stream</span>
</div>
${coverImage ? `
<div class="flex justify-center my-2">
<img src="${escapeHtml(coverImage)}" alt="" class="max-w-[200px] rounded-lg" onerror="this.style.display='none'">
</div>
` : ''}
<div class="card-actions justify-end mt-2">
<button class="btn btn-secondary btn-sm" onclick="window.open('${escapeHtml(s.url)}', '_blank')">
<i class="fa-solid fa-link"></i> Voir sur FS7
</button>
<button class="btn btn-primary btn-sm" onclick="loadSeriesEpisodesDirect('${escapeHtml(s.url)}', '${escapeHtml(s.title)}')">
<i class="fa-solid fa-download"></i> Voir les épisodes
</button>
</div>
<div id="episodes-fs7-${encodeURIComponent(s.url)}" class="mt-2"></div>
</div>
</div>
`;
});
html += '</div>';
resultsContainer.innerHTML = html;
} else {
resultsContainer.innerHTML = `
<div class="text-center py-16 text-base-content/50">
<i class="fa-solid fa-xmark text-3xl mb-3 block"></i>
<p>Aucune série trouvée pour "${escapeHtml(query)}"</p>
<p class="text-xs mt-2 opacity-70">
Essayez avec un autre titre ou vérifiez l'orthographe
</p>
</div>`;
}
} catch (error) {
console.error('Error searching series:', error);
resultsContainer.innerHTML = `
<div class="text-center py-16 text-base-content/50">
<i class="fa-solid fa-xmark text-3xl mb-3 block"></i>
<p>Erreur lors de la recherche</p>
<p class="text-xs mt-2 text-error">${error.message}</p>
</div>`;
}
}
// Load series episodes directly without redirecting to search
async function loadSeriesEpisodesDirect(url, title) {
const episodesContainer = document.getElementById(`episodes-fs7-${encodeURIComponent(url)}`);
if (!episodesContainer) return;
try {
episodesContainer.innerHTML = '<div class="flex justify-center py-4"><span class="loading loading-spinner loading-sm"></span><span class="ml-2 text-base-content/60 text-sm">Chargement des épisodes...</span></div>';
const response = await fetch(`${API_BASE}/anime/episodes?url=${encodeURIComponent(url)}&lang=vf`);
const data = await response.json();
if (data.episodes && data.episodes.length > 0) {
let html = `
<div class="mt-3">
<label class="label-text text-xs mb-1 block text-warning">
<i class="fa-solid fa-tv"></i> Sélectionner un épisode:
</label>
<select id="select-episodes-${encodeURIComponent(url)}" class="select select-bordered select-sm w-full">
<option value="">Sélectionner un épisode</option>
${data.episodes.map(ep => `
<option value="${escapeHtml(ep.url)}">Épisode ${escapeHtml(ep.episode)}</option>
`).join('')}
</select>
<button class="btn btn-primary btn-sm w-full mt-2" onclick="downloadSeriesEpisode('${escapeHtml(url)}', '${escapeHtml(title)}')">
<i class="fa-solid fa-download"></i>
Télécharger l'épisode
</button>
</div>
`;
episodesContainer.innerHTML = html;
} else {
episodesContainer.innerHTML = '<div class="text-center py-4 text-base-content/50 text-sm">Aucun épisode disponible</div>';
}
} catch (error) {
console.error('Error loading episodes:', error);
episodesContainer.innerHTML = `<div class="text-center py-4 text-sm text-error">Erreur: ${error.message}</div>`;
}
}
// Download series episode
async function downloadSeriesEpisode(url, title) {
const select = document.getElementById(`select-episodes-${encodeURIComponent(url)}`);
if (!select || !select.value) {
alert('Veuillez sélectionner un épisode');
return;
}
const episodeUrl = select.value;
try {
const response = await fetch(`${API_BASE}/anime/download?url=${encodeURIComponent(episodeUrl)}`, {
method: 'POST'
});
if (response.ok) {
alert(`Téléchargement démarré pour "${title}"`);
// Refresh downloads
if (typeof loadDownloads === 'function') {
loadDownloads();
}
} else {
const error = await response.json();
const errorMessage = error.detail
? (typeof error.detail === 'string' ? error.detail : JSON.stringify(error.detail))
: 'Impossible de démarrer le téléchargement';
alert(`Erreur : ${errorMessage}`);
}
} catch (error) {
console.error('Download error:', error);
alert(`Erreur lors du téléchargement : ${error.message}`);
}
}
// Make functions available globally
window.handleSeriesSearch = handleSeriesSearch;
window.loadSeriesEpisodesDirect = loadSeriesEpisodesDirect;
window.downloadSeriesEpisode = downloadSeriesEpisode;