import 'package:mangayomi/bridge_lib.dart'; import 'dart:convert'; class AniFlix extends MProvider { AniFlix(); @override Future getPopular(MSource source, int page) async { final headers = getHeader(source.baseUrl); final data = { "url": "${source.baseUrl}/api/show/new/${page - 1}", "headers": headers }; final res = await http('GET', json.encode(data)); return parseAnimeList(res, source.baseUrl, true); } @override Future getLatestUpdates(MSource source, int page) async { final headers = getHeader(source.baseUrl); final data = { "url": "${source.baseUrl}/api/show/airing/${page - 1}", "headers": headers }; final res = await http('GET', json.encode(data)); final datas = json.decode(res); List animeList = []; List ids = []; for (var data in datas) { final anim = data["season"]["show"]; if (!ids.contains(anim["id"])) { ids.add(anim["id"]); MManga anime = MManga(); anime.name = anim["name"]; anime.imageUrl = "${source.baseUrl}/storage/" + (anim["cover_portrait"] ?? ""); anime.link = getUrlWithoutDomain("${source.baseUrl}/api/show/${anim['url']}"); anime.description = anim["description"]; if (anim["airing"] == 0) { anime.status = MStatus.completed; } else if (anim["airing"] == 1) { anime.status = MStatus.ongoing; } animeList.add(anime); } } return MPages(animeList, true); } @override Future search( MSource source, String query, int page, FilterList filterList) async { final data = { "url": "${source.baseUrl}/api/show/search", "body": {"search": query}, "headers": { 'Referer': source.baseUrl, 'Accept': 'application/json', 'Content-Type': 'application/json' } }; final res = await http('POST', json.encode(data)); return parseAnimeList(res, source.baseUrl, false); } @override Future getDetail(MSource source, String url) async { final data = {"url": "${source.baseUrl}$url"}; final res = await http('GET', json.encode(data)); MManga anime = MManga(); final jsonRes = json.decode(res); anime.name = jsonRes["name"]; if (jsonRes["cover_portrait"] != null) { anime.imageUrl = "${source.baseUrl}/storage/" + jsonRes["cover_portrait"]; } anime.description = jsonRes["description"]; anime.genre = (jsonRes["genres"] as List>) .map((e) => e["name"]) .toList(); var seasons = jsonRes["seasons"]; final animeUrl = jsonRes["url"]; List? episodesList = []; for (var season in seasons) { List> episodes = season["episodes"]; int page = 1; final res = await http( 'GET', json.encode({ "url": "${source.baseUrl}/api/show/$animeUrl/${season["id"]}/$page" })); bool hasMoreResult = (json.decode(res)["episodes"] as List>) .isNotEmpty; while (hasMoreResult) { final res = await http( 'GET', json.encode({ "url": "${source.baseUrl}/api/show/$animeUrl/${season["id"]}/$page" })); final epList = json.decode(res)["episodes"] as List>; page++; episodes.addAll(epList); hasMoreResult = epList.isNotEmpty; } for (var episode in episodes) { String name = episode["name"] ?? ""; if (name.toLowerCase().contains("folge") || name.toLowerCase().contains("episode")) { name = ""; } else { name = ": $name"; } MChapter ep = MChapter(); ep.name = "Staffel ${season["number"]} Folge ${episode["number"]}$name"; ep.url = "/api/episode/show/$animeUrl/season/${season["number"]}/episode/${episode["number"]}"; episodesList.add(ep); } } anime.chapters = episodesList.reversed.toList(); return anime; } @override Future> getVideoList(MSource source, String url) async { final headers = getHeader(source.baseUrl); final data = {"url": "${source.baseUrl}$url", "headers": headers}; final res = await http('GET', json.encode(data)); final jsonRes = json.decode(res)["streams"]; List videos = []; final hosterSelection = preferenceHosterSelection(source.id); for (var stream in jsonRes) { List a = []; String quality = '${stream["hoster"]["name"]} - ${stream["lang"]}'; String link = stream["link"]; print(link); if (link.contains("https://dood") && hosterSelection.contains("doodstream")) { a = await doodExtractor(link, quality); } else if (link.contains("https://streamtape") && hosterSelection.contains("streamtape")) { a = await streamTapeExtractor(link, quality); } else if (link.contains("https://voe.sx") && hosterSelection.contains("voe")) { a = await voeExtractor(link, quality); } else if (link.contains("https://streamlare") && hosterSelection.contains("streamlare")) { a = await streamlareExtractor(link, quality, '', ''); } videos.addAll(a); } return sortVideos(videos, source.id); } String getUrlWithoutDomain(String orig) { final uri = Uri.parse(orig.replaceAll(' ', '%20')); String out = uri.path; if (uri.query.isNotEmpty) { out += '?${uri.query}'; } if (uri.fragment.isNotEmpty) { out += '#${uri.fragment}'; } return out; } MPages parseAnimeList(String res, String baseUrl, bool hasNextPage) { final datas = json.decode(res); List animeList = []; for (var data in datas) { MManga anime = MManga(); anime.name = data["name"]; anime.imageUrl = "$baseUrl/storage/" + (data["cover_portrait"] ?? ""); anime.link = getUrlWithoutDomain("$baseUrl/api/show/${data['url']}"); anime.description = data["description"]; if (data["airing"] == 0) { anime.status = MStatus.completed; } else if (data["airing"] == 1) { anime.status = MStatus.ongoing; } animeList.add(anime); } return MPages(animeList, hasNextPage); } List sortVideos(List videos, int sourceId) { print(videos.length); String hoster = getPreferenceValue(sourceId, "preferred_hoster"); String sub = getPreferenceValue(sourceId, "preferred_sub"); videos.sort((MVideo a, MVideo b) { int hosterMatchA = 0; if (a.url.toLowerCase().contains(hoster.toLowerCase()) && a.quality.toLowerCase().contains(sub.toLowerCase())) { hosterMatchA = 1; } int hosterMatchB = 0; if (b.url.toLowerCase().contains(hoster.toLowerCase()) && b.quality.toLowerCase().contains(sub.toLowerCase())) { hosterMatchB = 1; } return hosterMatchB - hosterMatchA; }); return videos; } List preferenceHosterSelection(int sourceId) { return getPreferenceValue(sourceId, "hoster_selectionn"); } @override List getSourcePreferences(MSource source) { return [ ListPreference( key: "preferred_hoster", title: "Standard-Hoster", summary: "", valueIndex: 0, entries: [ "Streamtape", "Doodstream", "Voe", "Streamlare" ], entryValues: [ "https://streamtape.com", "https://dood", "https://voe.sx", "https://streamlare.com" ]), ListPreference( key: "preferred_sub", title: "Standardmäßig Sub oder Dub?", summary: "", valueIndex: 0, entries: ["Sub", "Dub"], entryValues: ["Sub", "Dub"]), MultiSelectListPreference( key: "hoster_selectionn", title: "Hoster auswählen", summary: "", entries: ["Streamtape", "Doodstream", "Voe", "Streamlare"], entryValues: ["streamtape", "doodstream", "voe", "streamlare"], values: ["streamtape", "doodstream", "voe", "streamlare"]), ]; } } Map getHeader(String url) { return {'Referer': url}; } AniFlix main() { return AniFlix(); }