Files
ohm_streaming/static/js/main.js
T
2026-02-28 09:22:57 +00:00

274 lines
9.4 KiB
JavaScript

/**
* Main initialization and event handlers
*/
// Initialize on DOM load
document.addEventListener('DOMContentLoaded', () => {
initializeForms();
loadProviders();
loadDownloads();
setInterval(loadDownloads, 1000);
// Load home content (recommendations & releases)
loadHomeContent();
});
/**
* Initialize form event listeners
*/
function initializeForms() {
// Anime search form
const animeSearchInput = document.getElementById('animeSearchInput');
if (animeSearchInput) {
animeSearchInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
handleAnimeSearch();
}
});
}
// Series search form
const seriesSearchInput = document.getElementById('seriesSearchInput');
if (seriesSearchInput) {
seriesSearchInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
handleSeriesSearch();
}
});
}
// Direct download form
const downloadForm = document.getElementById('downloadForm');
if (downloadForm) {
downloadForm.addEventListener('submit', handleDirectDownload);
}
}
/**
* Load providers dynamically (legacy support)
* Note: This is kept for compatibility but the new interface uses static tabs
*/
async function loadProviders() {
try {
const data = await getProvidersInfo();
// Update supported hosts badges (if element exists)
const hostsContainer = document.querySelector('.supported-hosts');
if (hostsContainer) {
hostsContainer.innerHTML = '';
Object.values(data.file_hosts).forEach(host => {
const badge = document.createElement('span');
badge.className = 'host-badge';
badge.textContent = `${host.icon} ${host.name}`;
hostsContainer.appendChild(badge);
});
}
} catch (error) {
console.error('Error loading providers:', error);
}
}
/**
* Create anime provider tab content
*/
function createAnimeTabContent(providerId, provider) {
return `
<div class="url-form">
<div class="anime-input-group">
<input
type="text"
id="${providerId}UrlInput"
placeholder="URL de l'anime (ex: ${provider.url_pattern})"
>
<button type="button" class="btn-primary" onclick="handleLoadProviderEpisodes('${providerId}')">
<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>
Charger
</button>
</div>
<div id="${providerId}EpisodeSelector" class="anime-select-group" style="display:none;">
<select id="${providerId}EpisodeSelect">
<option value="">Sélectionner un épisode</option>
</select>
<button type="button" class="btn-primary" onclick="handleDownloadProviderEpisode('${providerId}')">
<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>
</div>
`;
}
/**
* Create series provider tab content
*/
function createSeriesTabContent(providerId, provider) {
return `
<div class="url-form">
<div class="anime-input-group">
<input
type="text"
id="${providerId}UrlInput"
placeholder="URL de la série (ex: ${provider.url_pattern})"
>
<button type="button" class="btn-primary" onclick="handleLoadProviderEpisodes('${providerId}')">
<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>
Charger
</button>
</div>
<div id="${providerId}EpisodeSelector" class="anime-select-group" style="display:none;">
<select id="${providerId}EpisodeSelect">
<option value="">Sélectionner un épisode</option>
</select>
<button type="button" class="btn-primary" onclick="handleDownloadProviderEpisode('${providerId}')">
<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>
</div>
`;
}
/**
* Handle load provider episodes
*/
async function handleLoadProviderEpisodes(providerId) {
const animeUrl = document.getElementById(`${providerId}UrlInput`).value;
if (!animeUrl) {
alert('Veuillez entrer une URL d\'anime');
return;
}
try {
const data = await loadEpisodes(animeUrl, null);
if (data.episodes && data.episodes.length > 0) {
const select = document.getElementById(`${providerId}EpisodeSelect`);
select.innerHTML = '<option value="">Sélectionner un épisode</option>';
data.episodes.forEach(ep => {
const option = document.createElement('option');
option.value = ep.url;
option.textContent = `Épisode ${ep.episode}`;
select.appendChild(option);
});
document.getElementById(`${providerId}EpisodeSelector`).style.display = 'flex';
} else {
alert('Aucun épisode trouvé');
}
} catch (error) {
console.error('Error loading episodes:', error);
alert('Erreur lors du chargement des épisodes');
}
}
/**
* Handle download provider episode
*/
async function handleDownloadProviderEpisode(providerId) {
const episodeUrl = document.getElementById(`${providerId}EpisodeSelect`).value;
if (!episodeUrl) {
alert('Veuillez sélectionner un épisode');
return;
}
try {
await downloadEpisode(episodeUrl);
document.getElementById(`${providerId}EpisodeSelect`).value = '';
loadDownloads();
} catch (error) {
console.error('Download error:', error);
alert('Erreur lors du téléchargement');
}
}
/**
* Switch between tabs
*/
function switchTab(tabName) {
// Hide all tabs
document.querySelectorAll('.tab-content').forEach(tab => {
tab.classList.remove('active');
});
document.querySelectorAll('.tab').forEach(btn => {
btn.classList.remove('active');
});
// Show selected tab
const tabElement = document.getElementById(`tab-${tabName}`);
if (tabElement) {
tabElement.classList.add('active');
}
// Find and activate the button
const buttons = document.querySelectorAll('.tab');
buttons.forEach(btn => {
const tabType = btn.getAttribute('data-tab-type');
if (tabType === 'home' && tabName === 'home') {
btn.classList.add('active');
} else if (tabType === 'anime' && tabName === 'anime') {
// Static anime tab
btn.classList.add('active');
} else if (tabType === 'series' && tabName === 'series') {
// Static series tab
btn.classList.add('active');
} else if (tabType === 'providers' && tabName === 'providers') {
// Static providers tab
btn.classList.add('active');
} else if (tabType === 'anime' && btn.getAttribute('data-provider') === tabName.replace('anime-', '')) {
btn.classList.add('active');
} else if (tabType === 'series' && btn.getAttribute('data-provider') === tabName.replace('series-', '')) {
btn.classList.add('active');
}
});
// Load home content when switching to home tab
if (tabName === 'home') {
// Content is already loaded on init, but you can reload if needed
if (typeof loadHomeContent === 'function' && !document.getElementById('recommendationsList').hasChildNodes()) {
loadHomeContent();
}
}
// Load watchlist content when switching to watchlist tab
if (tabName === 'watchlist') {
if (typeof loadSchedulerStatus === 'function') {
loadSchedulerStatus();
}
if (typeof displayWatchlist === 'function') {
displayWatchlist();
}
}
}
// Handle URL hash on page load
if (window.location.hash) {
const hash = window.location.hash.substring(1);
if (hash === 'watchlist' || hash === 'anime' || hash === 'series' || hash === 'providers') {
switchTab(hash);
}
}
// Listen for hash changes
window.addEventListener('hashchange', function() {
if (window.location.hash) {
const hash = window.location.hash.substring(1);
if (hash === 'watchlist' || hash === 'anime' || hash === 'series' || hash === 'providers') {
switchTab(hash);
}
}
});