Files
Agora/plugins/hydracker/api.ts
T

144 lines
5.0 KiB
TypeScript

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<Response> {
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<string, any> = {}) {
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;
}