// AniLiberty module for Sora // Author: emp0ry // Version: 1.0.0 // Description: // Streams anime directly from AniLiberty / AniLibria API v1 // Endpoints used: // • /app/status // • /app/search/releases?query= // • /anime/releases/{id} // // Supports 1080p / 720p / 480p HLS playback // ------------------------------------------------------------ // Detect working API domain // ------------------------------------------------------------ async function checkApiStatus() { const domains = [ "https://anilibria.top/api/v1/", "https://aniliberty.top/api/v1/", "https://anilibria.wtf/api/v1/" ]; for (const base of domains) { try { const res = await fetchv2(base + "app/status"); const data = await res.json(); if (data?.is_alive || data?.result === "ok") return base; } catch (_) {} } return "https://anilibria.top/api/v1/"; } // ------------------------------------------------------------ // Search anime releases // ------------------------------------------------------------ async function searchResults(keyword) { const base = await checkApiStatus(); const url = `${base}app/search/releases?query=${encodeURIComponent(keyword)}&include=id,name,poster,year,description`; try { const response = await fetchv2(url); const data = await response.json(); if (!Array.isArray(data) || !data.length) return [{ title: `No results from AniLiberty (${base})`, image: "https://anilibria.top/favicon.ico", href: "https://anilibria.top" }]; return data.map(item => { const title = item.name?.main || item.name?.english || "Unknown title"; const year = item.year ? ` (${item.year})` : ""; const img = item.poster?.optimized?.preview ? `https://anilibria.top${item.poster.optimized.preview}` : `https://anilibria.top${item.poster?.preview || "/favicon.ico"}`; return { title: title + year, image: img, href: `${base}anime/releases/${item.id}` }; }); } catch (err) { console.log("AniLiberty search error:", err); return [{ title: "AniLiberty: Error during search", image: "https://anilibria.top/favicon.ico", href: "https://anilibria.top" }]; } } // ------------------------------------------------------------ // Extract anime details // ------------------------------------------------------------ async function extractDetails(url) { try { const response = await fetchv2(url); const data = await response.json(); return [{ description: data.description || "No description available.", aliases: data.name?.english || "N/A", airdate: data.year ? String(data.year) : "Unknown" }]; } catch (err) { console.log("AniLiberty details error:", err); return [{ description: "Error loading details", aliases: "N/A", airdate: "N/A" }]; } } // ------------------------------------------------------------ // Extract episode list (with HLS sources) // ------------------------------------------------------------ async function extractEpisodes(url) { try { const response = await fetchv2(url); const data = await response.json(); const eps = data.episodes || []; if (!eps.length) return []; return eps.map(ep => ({ number: ep.ordinal || ep.sort_order || 0, image: ep.preview?.optimized?.preview ? `https://anilibria.top${ep.preview.optimized.preview}` : "https://anilibria.top/favicon.ico", href: ep.hls_1080 || ep.hls_720 || ep.hls_480 || null })).filter(e => e.href); } catch (err) { console.log("AniLiberty episodes error:", err); return []; } } // ------------------------------------------------------------ // Extract direct stream URL (HLS) // ------------------------------------------------------------ async function extractStreamUrl(url) { try { // Direct HLS links are already provided; just return the same URL return url; } catch (err) { console.log("AniLiberty stream error:", err); return null; } }