// Anime details module
// Search anime and display details
async function searchAnimeDetails(query, malId = null) {
const resultsContainer = document.getElementById('animeSearchResults');
if (!resultsContainer) return;
try {
resultsContainer.innerHTML = '
Recherche en cours...
';
// If we have a MAL ID, fetch directly by ID, otherwise search by query
let malUrl;
if (malId) {
malUrl = `${API_BASE}/anime/mal/${malId}`;
} else {
malUrl = `${API_BASE}/anime/mal/search?q=${encodeURIComponent(query)}&limit=5`;
}
// Search MAL and get streaming results in parallel
const [malResponse, streamingData] = await Promise.allSettled([
fetch(malUrl),
searchAnime(query, 'vostfr', false)
]);
let animeData = null;
let malFound = false;
// Check MAL search results
if (malResponse.status === 'fulfilled') {
try {
// malResponse.value is the Response object from fetch
const response = malResponse.value;
// Check if the HTTP request was successful
if (response.ok) {
const data = await response.json();
console.log('MAL search response:', data);
// Handle both direct ID response and search response
if (data.anime) {
animeData = data.anime;
malFound = true;
} else if (data.mal_id) {
// Direct MAL ID response
animeData = data;
malFound = true;
}
} else {
console.warn(`MAL search returned HTTP ${response.status}`);
}
} catch (e) {
console.error('Error parsing MAL response:', e);
}
} else {
console.error('MAL search promise rejected:', malResponse.reason);
}
// Build streaming results HTML
let streamingHtml = '';
if (streamingData.status === 'fulfilled' && streamingData.value && streamingData.value.results) {
const providersData = await getProvidersInfo();
// Build results HTML
const streamingParts = [];
let hasResults = false;
// Display results from each provider - render all cards in parallel
for (const [providerId, results] of Object.entries(streamingData.value.results)) {
if (results && results.length > 0) {
hasResults = true;
const provider = providersData.anime_providers[providerId];
// Render all cards for this provider
const cardPromises = results.map((anime) => renderAnimeCard(anime, providerId, provider, 'vostfr'));
const cards = await Promise.all(cardPromises);
streamingParts.push(...cards);
}
}
// Only add header and wrapper if we have results
if (hasResults) {
streamingParts.unshift(
`
Résultats de streaming
`
);
streamingParts.push('
');
streamingHtml = streamingParts.join('');
}
}
// Display results
if (malFound && animeData) {
// We found MAL data - display anime details card
let html = renderAnimeDetails(animeData);
// Append streaming results if available
html += streamingHtml;
resultsContainer.innerHTML = html;
// Now load seasons after HTML is in DOM
if (streamingData.status === 'fulfilled' && streamingData.value && streamingData.value.results) {
loadStreamingResultsSeasons(streamingData.value.results);
}
} else {
// MAL found nothing but we have streaming results
if (streamingHtml) {
resultsContainer.innerHTML = `
Aucune fiche trouvée sur MyAnimeList pour "${escapeHtml(query)}"
Essayez le nom en anglais ou japonais (ex: "Frieren: Beyond Journey's End")
${streamingHtml}
`;
// Now load seasons after HTML is in DOM
if (streamingData.status === 'fulfilled' && streamingData.value && streamingData.value.results) {
loadStreamingResultsSeasons(streamingData.value.results);
}
} else {
resultsContainer.innerHTML = `
Aucun résultat trouvé pour "${escapeHtml(query)}"
Essayez le nom en anglais ou japonais (ex: "Frieren: Beyond Journey's End", "One Piece")
`;
}
}
// Get provider search results as HTML
async function getProviderSearchResults(query) {
try {
// Use the existing searchAnime function
const data = await searchAnime(query, 'vostfr', false);
if (!data.results) {
return '';
}
// Build results HTML
const htmlParts = [];
let hasResults = false;
// Display results from each provider
for (const [providerId, results] of Object.entries(data.results)) {
if (results && results.length > 0) {
hasResults = true;
const providersData = await getProvidersInfo();
const provider = providersData.anime_providers[providerId];
// Render all cards for this provider in parallel
const cardPromises = results.map((anime) => renderAnimeCard(anime, providerId, provider, 'vostfr'));
const cards = await Promise.all(cardPromises);
htmlParts.push(...cards);
}
}
// Only add header and wrapper if we have results
if (hasResults) {
htmlParts.unshift(
`
Résultats de streaming
`
);
htmlParts.push('
');
}
return htmlParts.join('');
} catch (error) {
console.error('Error getting provider search results:', error);
return '';
}
}
// After displaying streaming results, load seasons for Anime-Sama
async function loadStreamingResultsSeasons(providerResults) {
// providerResults should be the data.results object
let delayCounter = 0;
for (const [providerId, results] of Object.entries(providerResults)) {
if (results && results.length > 0) {
results.forEach((anime, index) => {
// Only load seasons for Anime-Sama
if (providerId === 'animesama' || (anime.url && anime.url.includes('anime-sama'))) {
// Stagger requests: 500ms delay between each anime
setTimeout(() => {
loadSeasonsForAnime(providerId, encodeURIComponent(anime.url));
}, 500 * delayCounter);
delayCounter++;
}
});
}
}
}
// Render anime details card
function renderAnimeDetails(anime) {
const images = anime.images || {};
const imageUrl = images.jpg?.large_image_url || images.jpg?.image_url || images.webp?.large_image_url || '';
const genres = anime.genres || [];
const themes = anime.themes || [];
const studios = anime.studios || [];
const score = anime.score || 0;
const rank = anime.rank || 0;
const popularity = anime.popularity || 0;
const synopsis = anime.synopsis || '';
const related = anime.related || [];
// Generate unique ID for synopsis element
const synopsisId = `synopsis-${anime.mal_id}`;
// Filter only seasons (Sequel, Prequel)
const seasons = related.filter(r => {
const relationType = r.type?.toLowerCase() || '';
return relationType === 'sequel' || relationType === 'prequel';
});
return `