import { CONFIG } from '../../src/utils/config.js'; export const CONFIG_HYDRACKER = { BASE_URL: (CONFIG.HYDRACKER_URL || '').replace(/\/$/, ''), // Supprime le slash final API_KEY: CONFIG.HYDRACKER_API_KEY, TIMEOUT: CONFIG.HYDRACKER_TIMEOUT || 15000, }; const HYDRACKER_HEADERS = { 'Accept': 'application/json', 'Authorization': `Bearer ${CONFIG_HYDRACKER.API_KEY}`, 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36' }; const TIMEOUT = CONFIG_HYDRACKER.TIMEOUT; // 30 secondes par défaut (configurable) async function fetchWithRetry( url: string, options: RequestInit = {}, maxRetries: number = 2, initialDelay: number = 2000 ): Promise { let attempt = 0; let delay = initialDelay; while (true) { attempt++; const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), TIMEOUT); try { const res = await fetch(url, { ...options, signal: controller.signal }); clearTimeout(timeoutId); if (res.status === 502 || res.status === 503 || res.status === 504 || res.status === 429) { if (attempt < maxRetries) { console.warn(`[Hydracker-API] Attempt ${attempt}/${maxRetries} returned HTTP ${res.status} on fetch. Retrying in ${delay}ms...`); await new Promise(resolve => setTimeout(resolve, delay)); delay *= 2; continue; } } return res; } catch (err: any) { clearTimeout(timeoutId); const isTimeout = err.name === 'AbortError' || err.message?.includes('aborted'); if (attempt < maxRetries) { const waitTime = isTimeout ? 1000 : delay; console.warn(`[Hydracker-API] Attempt ${attempt}/${maxRetries} failed/timed out (${err.message}). Retrying in ${waitTime}ms...`); await new Promise(resolve => setTimeout(resolve, waitTime)); if (!isTimeout) delay *= 2; continue; } throw err; } } } export async function apiGet(urlPath: string, params: Record = {}) { const qs = Object.entries(params).map(([k, v]) => `${k}=${encodeURIComponent(v)}`).join('&'); const url = `${CONFIG_HYDRACKER.BASE_URL}/api/v1/${urlPath}` + (qs ? `?${qs}` : ''); try { const res = await fetchWithRetry(url, { headers: HYDRACKER_HEADERS }); if (!res.ok) { console.error(`[Hydracker-API] apiGet HTTP ${res.status} on ${urlPath}`); return null; } return await res.json(); } catch (e: any) { console.error(`[Hydracker-API] apiGet Error on ${urlPath}:`, e.message); return null; } } export async function apiPost(urlPath: string, body: any = {}) { const url = `${CONFIG_HYDRACKER.BASE_URL}/api/v1/${urlPath}`; try { const res = await fetchWithRetry(url, { method: 'POST', headers: { ...HYDRACKER_HEADERS, 'Content-Type': 'application/json' }, body: JSON.stringify(body) }); return { status: res.status, body: await res.text() }; } catch (e: any) { console.error(`[Hydracker-API] apiPost Error on ${urlPath}:`, e.message); return null; } } export async function fetchSearch(query: string) { const url = `${CONFIG_HYDRACKER.BASE_URL}/api/v1/search/${encodeURIComponent(query)}?loader=searchAutocomplete`; try { const res = await fetchWithRetry(url, { headers: HYDRACKER_HEADERS }); if (!res.ok) { console.error(`[Hydracker-API] Search HTTP ${res.status} for "${query}"`); return null; } return await res.json(); } catch (e: any) { console.error('[Hydracker-API] Search failed:', e.message); return null; } } export async function fetchMovieLinks(titleId: string) { const url = `${CONFIG_HYDRACKER.BASE_URL}/api/v1/titles/${titleId}/download`; try { const res = await fetchWithRetry(url, { headers: HYDRACKER_HEADERS }); if (!res.ok) return null; return await res.json(); } catch (e: any) { return null; } } export async function fetchSeriesLiens(titleId: string, season: number = 1) { const allLiens: any[] = []; let page = 1; while (true) { const result = await apiGet('liens', { title_id: titleId, loader: 'linksdl', season, perPage: 500, page, filters: '', paginate: 'lengthAware' }); if (!result || result.error) break; const pagination = result.pagination || {}; const data = pagination.data || []; if (!data.length) break; allLiens.push(...data); const lastPage = pagination.last_page || pagination.lastPage || 1; if (page >= lastPage) break; page++; } return allLiens; }