From 6004f1f8d1a56f882dadb734ce26f50c626a3850 Mon Sep 17 00:00:00 2001 From: Moustapha Kodjo Amadou <107993382+kodjodevf@users.noreply.github.com> Date: Wed, 1 Oct 2025 15:27:46 +0100 Subject: [PATCH] Update --- README.md | 2 +- dart/anime/anime_source_list.dart | 60 - .../datalifeengine/datalifeengine.dart | 457 ------- .../multisrc/datalifeengine/sources.dart | 23 - .../src/frenchanime/frenchanime.dart | 13 - .../datalifeengine/src/frenchanime/icon.png | Bin 5173 -> 0 bytes .../datalifeengine/src/wiflix/icon.png | Bin 4635 -> 0 bytes .../datalifeengine/src/wiflix/wiflix.dart | 13 - dart/anime/multisrc/dopeflix/dopeflix.dart | 577 --------- dart/anime/multisrc/dopeflix/sources.dart | 23 - .../dopeflix/src/dopebox/dopebox.dart | 13 - .../multisrc/dopeflix/src/dopebox/icon.png | Bin 4126 -> 0 bytes .../multisrc/dopeflix/src/sflix/icon.png | Bin 6778 -> 0 bytes .../multisrc/dopeflix/src/sflix/sflix.dart | 13 - dart/anime/multisrc/zorotheme/sources.dart | 22 - .../zorotheme/src/hianime/hianime.dart | 14 - .../multisrc/zorotheme/src/hianime/icon.png | Bin 5120 -> 0 bytes .../multisrc/zorotheme/src/kaido/icon.png | Bin 23349 -> 0 bytes .../multisrc/zorotheme/src/kaido/kaido.dart | 13 - dart/anime/multisrc/zorotheme/zorotheme.dart | 710 ---------- .../all/animeworldindia/animeworldindia.dart | 430 ------ dart/anime/src/all/animeworldindia/icon.png | Bin 7536 -> 0 bytes .../src/all/animeworldindia/sources.dart | 37 - dart/anime/src/all/nyaa/icon.png | Bin 3187 -> 0 bytes dart/anime/src/all/nyaa/nyaa.dart | 220 ---- dart/anime/src/all/nyaa/source.dart | 20 - dart/anime/src/ar/okanime/icon.png | Bin 5358 -> 0 bytes dart/anime/src/ar/okanime/okanime.dart | 234 ---- dart/anime/src/ar/okanime/source.dart | 17 - dart/anime/src/de/animetoast/animetoast.dart | 250 ---- dart/anime/src/de/animetoast/icon.png | Bin 5171 -> 0 bytes dart/anime/src/de/animetoast/source.dart | 17 - dart/anime/src/en/animepahe/animepahe.dart | 415 ------ dart/anime/src/en/animepahe/icon.png | Bin 1934 -> 0 bytes dart/anime/src/en/animepahe/source.dart | 17 - .../src/en/donghuastream/donghuastream.dart | 241 ---- dart/anime/src/en/donghuastream/icon.png | Bin 83031 -> 0 bytes dart/anime/src/en/donghuastream/source.dart | 17 - dart/anime/src/en/gogoanime/gogoanime.dart | 1149 ----------------- dart/anime/src/en/gogoanime/icon.png | Bin 2993 -> 0 bytes dart/anime/src/en/gogoanime/source.dart | 17 - dart/anime/src/en/kisskh/icon.png | Bin 3012 -> 0 bytes dart/anime/src/en/kisskh/kisskh.dart | 223 ---- dart/anime/src/en/kisskh/source.dart | 17 - dart/anime/src/en/nineanimetv/icon.png | Bin 6623 -> 0 bytes .../anime/src/en/nineanimetv/nineanimetv.dart | 580 --------- dart/anime/src/en/nineanimetv/source.dart | 17 - dart/anime/src/en/uhdmovies/icon.png | Bin 3627 -> 0 bytes dart/anime/src/en/uhdmovies/source.dart | 17 - dart/anime/src/en/uhdmovies/uhdmovies.dart | 255 ---- dart/anime/src/en/vumeto/icon.png | Bin 7549 -> 0 bytes dart/anime/src/en/vumeto/source.dart | 19 - dart/anime/src/en/vumeto/vumeto.dart | 336 ----- .../es/animeonlineninja/animeonlineninja.dart | 352 ----- dart/anime/src/es/animeonlineninja/icon.png | Bin 4044 -> 0 bytes .../anime/src/es/animeonlineninja/source.dart | 17 - dart/anime/src/fr/animesama/animesama.dart | 555 -------- dart/anime/src/fr/animesama/icon.png | Bin 4666 -> 0 bytes dart/anime/src/fr/animesama/source.dart | 17 - .../anime/src/fr/animesultra/animesultra.dart | 247 ---- dart/anime/src/fr/animesultra/icon.png | Bin 9789 -> 0 bytes dart/anime/src/fr/animesultra/source.dart | 18 - dart/anime/src/fr/anizone/anizone.dart | 506 -------- dart/anime/src/fr/anizone/icon.png | Bin 26313 -> 0 bytes dart/anime/src/fr/anizone/source.dart | 17 - dart/anime/src/fr/franime/franime.dart | 409 ------ dart/anime/src/fr/franime/icon.png | Bin 3369 -> 0 bytes dart/anime/src/fr/franime/source.dart | 19 - dart/anime/src/fr/otakufr/icon.png | Bin 15379 -> 0 bytes dart/anime/src/fr/otakufr/otakufr.dart | 507 -------- dart/anime/src/fr/otakufr/source.dart | 18 - dart/anime/src/hi/yomovies/icon.png | Bin 3499 -> 0 bytes dart/anime/src/hi/yomovies/source.dart | 17 - dart/anime/src/hi/yomovies/yomovies.dart | 373 ------ dart/anime/src/id/nimegami/icon.png | Bin 3651 -> 0 bytes dart/anime/src/id/nimegami/nimegami.dart | 200 --- dart/anime/src/id/nimegami/source.dart | 17 - dart/anime/src/id/oploverz/icon.png | Bin 14655 -> 0 bytes dart/anime/src/id/oploverz/oploverz.dart | 172 --- dart/anime/src/id/oploverz/source.dart | 17 - dart/anime/src/id/otakudesu/icon.png | Bin 6422 -> 0 bytes dart/anime/src/id/otakudesu/otakudesu.dart | 261 ---- dart/anime/src/id/otakudesu/source.dart | 17 - .../anime/src/it/animesaturn/animesaturn.dart | 394 ------ dart/anime/src/it/animesaturn/icon.png | Bin 6664 -> 0 bytes dart/anime/src/it/animesaturn/source.dart | 17 - .../src/pt/animesvision/animesvision.dart | 308 ----- dart/anime/src/pt/animesvision/icon.png | Bin 3437 -> 0 bytes dart/anime/src/pt/animesvision/source.dart | 17 - dart/anime/src/sq/filma24/filma24.dart | 306 ----- dart/anime/src/sq/filma24/icon.png | Bin 8984 -> 0 bytes dart/anime/src/sq/filma24/source.dart | 17 - dart/anime/src/tr/diziwatch/diziwatch.dart | 241 ---- dart/anime/src/tr/diziwatch/icon.png | Bin 13293 -> 0 bytes dart/anime/src/tr/diziwatch/source.dart | 17 - javascript/anime/src/all/autoembed.js | 714 ---------- javascript/anime/src/all/dramacool.js | 353 ----- javascript/anime/src/all/netflixmirror.js | 333 ----- javascript/anime/src/all/soaper.js | 279 ---- javascript/anime/src/all/torrentio.js | 660 ---------- javascript/anime/src/all/torrentioanime.js | 631 --------- javascript/anime/src/de/aniworld.js | 933 ------------- javascript/anime/src/de/serienstream.js | 964 -------------- javascript/anime/src/en/allanime.js | 505 -------- javascript/anime/src/en/animegg.js | 254 ---- javascript/anime/src/en/animekai.js | 715 ---------- javascript/anime/src/en/animeonsen.js | 246 ---- javascript/anime/src/en/animeparadise.js | 270 ---- javascript/anime/src/en/animez.js | 300 ----- javascript/anime/src/en/aniplay.js | 705 ---------- javascript/anime/src/en/gojo.js | 312 ----- javascript/anime/src/en/sudatchi.js | 292 ----- javascript/anime/src/es/animefenix.js | 937 -------------- javascript/anime/src/es/animeflv.js | 183 --- javascript/anime/src/es/jkanime.js | 1032 --------------- javascript/anime/src/es/tioanime.js | 802 ------------ javascript/anime/src/it/animeworld.js | 959 -------------- javascript/anime/src/zh/360zy.js | 198 --- javascript/anime/src/zh/ffzy.js | 190 --- javascript/anime/src/zh/huaweiba.js | 188 --- javascript/anime/src/zh/jisuzy.js | 196 --- javascript/anime/src/zh/mihdr.js | 216 ---- javascript/anime/src/zh/mikan.js | 163 --- javascript/anime/src/zh/mucpan.js | 214 --- javascript/anime/src/zh/tiankongzy.js | 195 --- javascript/anime/src/zh/wogg.js | 220 ---- javascript/anime/src/zh/yhdm.js | 378 ------ javascript/anime/src/zh/yydsys.js | 213 --- repo.json | 2 +- 129 files changed, 2 insertions(+), 26321 deletions(-) delete mode 100644 dart/anime/anime_source_list.dart delete mode 100644 dart/anime/multisrc/datalifeengine/datalifeengine.dart delete mode 100644 dart/anime/multisrc/datalifeengine/sources.dart delete mode 100644 dart/anime/multisrc/datalifeengine/src/frenchanime/frenchanime.dart delete mode 100644 dart/anime/multisrc/datalifeengine/src/frenchanime/icon.png delete mode 100644 dart/anime/multisrc/datalifeengine/src/wiflix/icon.png delete mode 100644 dart/anime/multisrc/datalifeengine/src/wiflix/wiflix.dart delete mode 100644 dart/anime/multisrc/dopeflix/dopeflix.dart delete mode 100644 dart/anime/multisrc/dopeflix/sources.dart delete mode 100644 dart/anime/multisrc/dopeflix/src/dopebox/dopebox.dart delete mode 100644 dart/anime/multisrc/dopeflix/src/dopebox/icon.png delete mode 100644 dart/anime/multisrc/dopeflix/src/sflix/icon.png delete mode 100644 dart/anime/multisrc/dopeflix/src/sflix/sflix.dart delete mode 100644 dart/anime/multisrc/zorotheme/sources.dart delete mode 100644 dart/anime/multisrc/zorotheme/src/hianime/hianime.dart delete mode 100644 dart/anime/multisrc/zorotheme/src/hianime/icon.png delete mode 100644 dart/anime/multisrc/zorotheme/src/kaido/icon.png delete mode 100644 dart/anime/multisrc/zorotheme/src/kaido/kaido.dart delete mode 100644 dart/anime/multisrc/zorotheme/zorotheme.dart delete mode 100644 dart/anime/src/all/animeworldindia/animeworldindia.dart delete mode 100644 dart/anime/src/all/animeworldindia/icon.png delete mode 100644 dart/anime/src/all/animeworldindia/sources.dart delete mode 100644 dart/anime/src/all/nyaa/icon.png delete mode 100644 dart/anime/src/all/nyaa/nyaa.dart delete mode 100644 dart/anime/src/all/nyaa/source.dart delete mode 100644 dart/anime/src/ar/okanime/icon.png delete mode 100644 dart/anime/src/ar/okanime/okanime.dart delete mode 100644 dart/anime/src/ar/okanime/source.dart delete mode 100644 dart/anime/src/de/animetoast/animetoast.dart delete mode 100644 dart/anime/src/de/animetoast/icon.png delete mode 100644 dart/anime/src/de/animetoast/source.dart delete mode 100644 dart/anime/src/en/animepahe/animepahe.dart delete mode 100644 dart/anime/src/en/animepahe/icon.png delete mode 100644 dart/anime/src/en/animepahe/source.dart delete mode 100644 dart/anime/src/en/donghuastream/donghuastream.dart delete mode 100644 dart/anime/src/en/donghuastream/icon.png delete mode 100644 dart/anime/src/en/donghuastream/source.dart delete mode 100644 dart/anime/src/en/gogoanime/gogoanime.dart delete mode 100644 dart/anime/src/en/gogoanime/icon.png delete mode 100644 dart/anime/src/en/gogoanime/source.dart delete mode 100644 dart/anime/src/en/kisskh/icon.png delete mode 100644 dart/anime/src/en/kisskh/kisskh.dart delete mode 100644 dart/anime/src/en/kisskh/source.dart delete mode 100644 dart/anime/src/en/nineanimetv/icon.png delete mode 100644 dart/anime/src/en/nineanimetv/nineanimetv.dart delete mode 100644 dart/anime/src/en/nineanimetv/source.dart delete mode 100644 dart/anime/src/en/uhdmovies/icon.png delete mode 100644 dart/anime/src/en/uhdmovies/source.dart delete mode 100644 dart/anime/src/en/uhdmovies/uhdmovies.dart delete mode 100644 dart/anime/src/en/vumeto/icon.png delete mode 100644 dart/anime/src/en/vumeto/source.dart delete mode 100644 dart/anime/src/en/vumeto/vumeto.dart delete mode 100644 dart/anime/src/es/animeonlineninja/animeonlineninja.dart delete mode 100644 dart/anime/src/es/animeonlineninja/icon.png delete mode 100644 dart/anime/src/es/animeonlineninja/source.dart delete mode 100644 dart/anime/src/fr/animesama/animesama.dart delete mode 100644 dart/anime/src/fr/animesama/icon.png delete mode 100644 dart/anime/src/fr/animesama/source.dart delete mode 100644 dart/anime/src/fr/animesultra/animesultra.dart delete mode 100644 dart/anime/src/fr/animesultra/icon.png delete mode 100644 dart/anime/src/fr/animesultra/source.dart delete mode 100644 dart/anime/src/fr/anizone/anizone.dart delete mode 100644 dart/anime/src/fr/anizone/icon.png delete mode 100644 dart/anime/src/fr/anizone/source.dart delete mode 100644 dart/anime/src/fr/franime/franime.dart delete mode 100644 dart/anime/src/fr/franime/icon.png delete mode 100644 dart/anime/src/fr/franime/source.dart delete mode 100644 dart/anime/src/fr/otakufr/icon.png delete mode 100644 dart/anime/src/fr/otakufr/otakufr.dart delete mode 100644 dart/anime/src/fr/otakufr/source.dart delete mode 100644 dart/anime/src/hi/yomovies/icon.png delete mode 100644 dart/anime/src/hi/yomovies/source.dart delete mode 100644 dart/anime/src/hi/yomovies/yomovies.dart delete mode 100644 dart/anime/src/id/nimegami/icon.png delete mode 100644 dart/anime/src/id/nimegami/nimegami.dart delete mode 100644 dart/anime/src/id/nimegami/source.dart delete mode 100644 dart/anime/src/id/oploverz/icon.png delete mode 100644 dart/anime/src/id/oploverz/oploverz.dart delete mode 100644 dart/anime/src/id/oploverz/source.dart delete mode 100644 dart/anime/src/id/otakudesu/icon.png delete mode 100644 dart/anime/src/id/otakudesu/otakudesu.dart delete mode 100644 dart/anime/src/id/otakudesu/source.dart delete mode 100644 dart/anime/src/it/animesaturn/animesaturn.dart delete mode 100644 dart/anime/src/it/animesaturn/icon.png delete mode 100644 dart/anime/src/it/animesaturn/source.dart delete mode 100644 dart/anime/src/pt/animesvision/animesvision.dart delete mode 100644 dart/anime/src/pt/animesvision/icon.png delete mode 100644 dart/anime/src/pt/animesvision/source.dart delete mode 100644 dart/anime/src/sq/filma24/filma24.dart delete mode 100644 dart/anime/src/sq/filma24/icon.png delete mode 100644 dart/anime/src/sq/filma24/source.dart delete mode 100644 dart/anime/src/tr/diziwatch/diziwatch.dart delete mode 100644 dart/anime/src/tr/diziwatch/icon.png delete mode 100644 dart/anime/src/tr/diziwatch/source.dart delete mode 100644 javascript/anime/src/all/autoembed.js delete mode 100644 javascript/anime/src/all/dramacool.js delete mode 100644 javascript/anime/src/all/netflixmirror.js delete mode 100644 javascript/anime/src/all/soaper.js delete mode 100644 javascript/anime/src/all/torrentio.js delete mode 100644 javascript/anime/src/all/torrentioanime.js delete mode 100644 javascript/anime/src/de/aniworld.js delete mode 100644 javascript/anime/src/de/serienstream.js delete mode 100644 javascript/anime/src/en/allanime.js delete mode 100644 javascript/anime/src/en/animegg.js delete mode 100644 javascript/anime/src/en/animekai.js delete mode 100644 javascript/anime/src/en/animeonsen.js delete mode 100644 javascript/anime/src/en/animeparadise.js delete mode 100644 javascript/anime/src/en/animez.js delete mode 100644 javascript/anime/src/en/aniplay.js delete mode 100644 javascript/anime/src/en/gojo.js delete mode 100644 javascript/anime/src/en/sudatchi.js delete mode 100644 javascript/anime/src/es/animefenix.js delete mode 100644 javascript/anime/src/es/animeflv.js delete mode 100644 javascript/anime/src/es/jkanime.js delete mode 100644 javascript/anime/src/es/tioanime.js delete mode 100644 javascript/anime/src/it/animeworld.js delete mode 100644 javascript/anime/src/zh/360zy.js delete mode 100644 javascript/anime/src/zh/ffzy.js delete mode 100644 javascript/anime/src/zh/huaweiba.js delete mode 100644 javascript/anime/src/zh/jisuzy.js delete mode 100644 javascript/anime/src/zh/mihdr.js delete mode 100644 javascript/anime/src/zh/mikan.js delete mode 100644 javascript/anime/src/zh/mucpan.js delete mode 100644 javascript/anime/src/zh/tiankongzy.js delete mode 100644 javascript/anime/src/zh/wogg.js delete mode 100644 javascript/anime/src/zh/yhdm.js delete mode 100644 javascript/anime/src/zh/yydsys.js diff --git a/README.md b/README.md index 4b0efb75..1d0ed0b8 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This repository contains the available extension catalogues for the Mangayomi ap ## How to add the extensions -Click on one of the buttons below to add the corresponding repository/repositories: +Click on one of the buttons below to add the corresponding repository/repositories (Manga & novels only): Add all repositories diff --git a/dart/anime/anime_source_list.dart b/dart/anime/anime_source_list.dart deleted file mode 100644 index 7ab0bc58..00000000 --- a/dart/anime/anime_source_list.dart +++ /dev/null @@ -1,60 +0,0 @@ -import '../../model/source.dart'; -import 'multisrc/datalifeengine/sources.dart'; -import 'multisrc/dopeflix/sources.dart'; -import 'multisrc/zorotheme/sources.dart'; -import 'src/all/animeworldindia/sources.dart'; -import 'src/all/nyaa/source.dart'; -import 'src/ar/okanime/source.dart'; -import 'src/de/animetoast/source.dart'; -import 'src/en/animepahe/source.dart'; -import 'src/en/gogoanime/source.dart'; -import 'src/en/kisskh/source.dart'; -import 'src/en/nineanimetv/source.dart'; -import 'src/en/vumeto/source.dart'; -import 'src/es/animeonlineninja/source.dart'; -import 'src/fr/animesama/source.dart'; -import 'src/fr/anizone/source.dart'; -import 'src/hi/yomovies/source.dart'; -import 'src/en/uhdmovies/source.dart'; -import 'src/fr/animesultra/source.dart'; -import 'src/fr/franime/source.dart'; -import 'src/fr/otakufr/source.dart'; -import 'src/id/nimegami/source.dart'; -import 'src/id/oploverz/source.dart'; -import 'src/id/otakudesu/source.dart'; -import 'src/it/animesaturn/source.dart'; -import 'src/pt/animesvision/source.dart'; -import 'src/sq/filma24/source.dart'; -import 'src/tr/diziwatch/source.dart'; -import 'src/en/donghuastream/source.dart'; - -List dartAnimesourceList = [ - gogoanimeSource, - franimeSource, - otakufr, - animesultraSource, - ...zorothemeSourcesList, - okanimeSource, - otakudesu, - nimegami, - oploverz, - ...dopeflixSourcesList, - animesaturn, - uhdmoviesSource, - ...datalifeengineSourcesList, - filma24, - yomoviesSource, - animesamaSource, - nineanimetv, - ...animeworldindiaSourcesList, - nyaaSource, - animepaheSource, - animetoast, - animesvision, - diziwatchSource, - aniZoneSource, - animeonlineninjaSource, - kisskhSource, - vumetoSource, - donghuastreamSource, -]; diff --git a/dart/anime/multisrc/datalifeengine/datalifeengine.dart b/dart/anime/multisrc/datalifeengine/datalifeengine.dart deleted file mode 100644 index 0989ed20..00000000 --- a/dart/anime/multisrc/datalifeengine/datalifeengine.dart +++ /dev/null @@ -1,457 +0,0 @@ -import 'dart:convert'; -import 'package:mangayomi/bridge_lib.dart'; - -class DataLifeEngine extends MProvider { - DataLifeEngine({required this.source}); - - MSource source; - - final Client client = Client(); - - @override - bool get supportsLatest => false; - - @override - String get baseUrl => getPreferenceValue(source.id, "overrideBaseUrl"); - - @override - Future getPopular(int page) async { - final res = - (await client.get( - Uri.parse("$baseUrl${getPath(source)}page/$page"), - )).body; - return animeFromElement(res); - } - - @override - Future getLatestUpdates(int page) async { - return MPages([], false); - } - - @override - Future search(String query, int page, FilterList filterList) async { - final filters = filterList.filters; - String res = ""; - if (query.isNotEmpty) { - if (query.length < 4) - throw "La recherche est suspendue! La chaîne de recherche est vide ou contient moins de 4 caractères."; - final headers = { - "Host": Uri.parse(baseUrl).host, - "Origin": baseUrl, - "Referer": "$baseUrl/", - }; - final cleanQuery = query.replaceAll(" ", "+"); - if (page == 1) { - res = - (await client.post( - Uri.parse( - "$baseUrl?do=search&subaction=search&story=$cleanQuery", - ), - headers: headers, - )).body; - } else { - res = - (await client.post( - Uri.parse( - "$baseUrl?do=search&subaction=search&search_start=$page&full_search=0&result_from=11&story=$cleanQuery", - ), - headers: headers, - )).body; - } - } else { - String url = ""; - for (var filter in filters) { - if (filter.type == "CategoriesFilter") { - if (filter.state != 0) { - url = "$baseUrl${filter.values[filter.state].value}page/$page/"; - } - } else if (filter.type == "GenresFilter") { - if (filter.state != 0) { - url = "$baseUrl${filter.values[filter.state].value}page/$page/"; - } - } - } - res = (await client.get(Uri.parse(url))).body; - } - - return animeFromElement(res); - } - - @override - Future getDetail(String url) async { - String res = - (await client.get( - Uri.parse("$baseUrl${getUrlWithoutDomain(url)}"), - )).body; - MManga anime = MManga(); - final description = xpath(res, '//span[@itemprop="description"]/text()'); - anime.description = description.isNotEmpty ? description.first : ""; - anime.genre = xpath(res, '//span[@itemprop="genre"]/a/text()'); - - List? episodesList = []; - - if (source.name == "French Anime") { - final epsData = xpath(res, '//div[@class="eps"]/text()'); - for (var epData in epsData.first.split('\n')) { - final data = epData.split('!'); - MChapter ep = MChapter(); - ep.name = "Episode ${data.first}"; - ep.url = data.last; - episodesList.add(ep); - } - } else { - final doc = parseHtml(res); - final elements = - doc - .select(".hostsblock div:has(a)") - .where( - (MElement e) => e.outerHtml.contains("loadVideo('https://"), - ) - .toList(); - if (elements.isNotEmpty) { - for (var element in elements) { - element = element as MElement; - MChapter ep = MChapter(); - ep.name = element.className - .replaceAll("ep", "Episode ") - .replaceAll("vs", " VOSTFR") - .replaceAll("vf", " VF"); - ep.url = element - .select("a") - .map( - (MElement e) => substringBefore( - substringAfter(e.attr('onclick'), "loadVideo('"), - "')", - ), - ) - .toList() - .join(",") - .replaceAll("/vd.php?u=", ""); - ep.scanlator = element.className.contains('vf') ? 'VF' : 'VOSTFR'; - episodesList.add(ep); - } - } else { - MChapter ep = MChapter(); - ep.name = "Film"; - ep.url = doc - .select("a") - .where((MElement e) => e.outerHtml.contains("loadVideo('https://")) - .map( - (MElement e) => substringBefore( - substringAfter(e.attr('onclick'), "loadVideo('"), - "')", - ), - ) - .toList() - .join(",") - .replaceAll("/vd.php?u=", ""); - episodesList.add(ep); - } - } - - anime.chapters = episodesList.reversed.toList(); - return anime; - } - - @override - Future> getVideoList(String url) async { - List videos = []; - final sUrls = url.split(','); - for (var sUrl in sUrls) { - List a = []; - if (sUrl.contains("dood") || sUrl.contains("d000")) { - a = await doodExtractor(sUrl, "DoodStream"); - } else if ([ - "streamhide", - "guccihide", - "streamvid", - "dhtpre", - ].any((a) => sUrl.contains(a))) { - a = await streamHideExtractor(sUrl); - } else if (sUrl.contains("uqload")) { - a = await uqloadExtractor(sUrl); - } else if (sUrl.contains("upstream")) { - a = await upstreamExtractor(sUrl); - } else if (sUrl.contains("sibnet")) { - a = await sibnetExtractor(sUrl); - } else if (sUrl.contains("ok.ru")) { - a = await okruExtractor(sUrl); - } else if (sUrl.contains("vidmoly")) { - a = await vidmolyExtractor(sUrl); - } else if (sUrl.contains("streamtape")) { - a = await streamTapeExtractor(sUrl, ""); - } else if (sUrl.contains("voe.sx")) { - a = await voeExtractor(sUrl, ""); - } - videos.addAll(a); - } - return videos; - } - - MPages animeFromElement(String res) { - final htmls = parseHtml(res).select("div#dle-content > div.mov"); - List animeList = []; - for (var h in htmls) { - final html = h.innerHtml; - final url = xpath(html, '//a/@href').first; - final name = xpath(html, '//a/text()').first; - final image = xpath(html, '//div[contains(@class,"mov")]/img/@src').first; - final season = xpath(html, '//div/span[@class="block-sai"]/text()'); - MManga anime = MManga(); - anime.name = - "$name ${season.isNotEmpty ? season.first.replaceAll("\n", " ") : ""}"; - anime.imageUrl = "$baseUrl$image"; - anime.link = url; - animeList.add(anime); - } - final hasNextPage = xpath(res, '//span[@class="pnext"]/a/@href').isNotEmpty; - return MPages(animeList, hasNextPage); - } - - Future> streamHideExtractor(String url) async { - final res = (await client.get(Uri.parse(url))).body; - final masterUrl = substringBefore( - substringAfter( - substringAfter(substringAfter(unpackJs(res), "sources:"), "file:\""), - "src:\"", - ), - '"', - ); - final masterPlaylistRes = (await client.get(Uri.parse(masterUrl))).body; - List videos = []; - for (var it in substringAfter( - masterPlaylistRes, - "#EXT-X-STREAM-INF:", - ).split("#EXT-X-STREAM-INF:")) { - final quality = - "${substringBefore(substringBefore(substringAfter(substringAfter(it, "RESOLUTION="), "x"), ","), "\n")}p"; - - String videoUrl = substringBefore(substringAfter(it, "\n"), "\n"); - - if (!videoUrl.startsWith("http")) { - videoUrl = - "${masterUrl.split("/").sublist(0, masterUrl.split("/").length - 1).join("/")}/$videoUrl"; - } - - MVideo video = MVideo(); - video - ..url = videoUrl - ..originalUrl = videoUrl - ..quality = "StreamHideVid - $quality"; - videos.add(video); - } - return videos; - } - - Future> upstreamExtractor(String url) async { - final res = (await client.get(Uri.parse(url))).body; - final js = xpath(res, '//script[contains(text(), "m3u8")]/text()'); - if (js.isEmpty) { - return []; - } - final masterUrl = substringBefore( - substringAfter(unpackJs(js.first), "{file:\""), - "\"}", - ); - final masterPlaylistRes = (await client.get(Uri.parse(masterUrl))).body; - List videos = []; - for (var it in substringAfter( - masterPlaylistRes, - "#EXT-X-STREAM-INF:", - ).split("#EXT-X-STREAM-INF:")) { - final quality = - "${substringBefore(substringBefore(substringAfter(substringAfter(it, "RESOLUTION="), "x"), ","), "\n")}p"; - - String videoUrl = substringBefore(substringAfter(it, "\n"), "\n"); - - if (!videoUrl.startsWith("http")) { - videoUrl = - "${masterUrl.split("/").sublist(0, masterUrl.split("/").length - 1).join("/")}/$videoUrl"; - } - - MVideo video = MVideo(); - video - ..url = videoUrl - ..originalUrl = videoUrl - ..quality = "Upstream - $quality"; - videos.add(video); - } - return videos; - } - - Future> uqloadExtractor(String url) async { - final res = (await client.get(Uri.parse(url))).body; - final js = xpath(res, '//script[contains(text(), "sources:")]/text()'); - if (js.isEmpty) { - return []; - } - - final videoUrl = substringBefore( - substringAfter(js.first, "sources: [\""), - '"', - ); - MVideo video = MVideo(); - video - ..url = videoUrl - ..originalUrl = videoUrl - ..quality = "Uqload" - ..headers = {"Referer": "${Uri.parse(url).origin}/"}; - return [video]; - } - - Future> vidmolyExtractor(String url) async { - final headers = {'Referer': 'https://vidmoly.to'}; - List videos = []; - final playListUrlResponse = (await client.get(Uri.parse(url))).body; - final playlistUrl = - RegExp(r'file:"(\S+?)"').firstMatch(playListUrlResponse)?.group(1) ?? - ""; - if (playlistUrl.isEmpty) return []; - final masterPlaylistRes = await client.get( - Uri.parse(playlistUrl), - headers: headers, - ); - - if (masterPlaylistRes.statusCode == 200) { - for (var it in substringAfter( - masterPlaylistRes.body, - "#EXT-X-STREAM-INF:", - ).split("#EXT-X-STREAM-INF:")) { - final quality = - "${substringBefore(substringBefore(substringAfter(substringAfter(it, "RESOLUTION="), "x"), ","), "\n")}p"; - - String videoUrl = substringBefore(substringAfter(it, "\n"), "\n"); - - MVideo video = MVideo(); - video - ..url = videoUrl - ..originalUrl = videoUrl - ..quality = "Vidmoly $quality" - ..headers = headers; - videos.add(video); - } - } - - return videos; - } - - String getPath() { - if (source.name == "French Anime") return "/animes-vostfr/"; - return "/serie-en-streaming/"; - } - - @override - List getSourcePreferences() { - return [ - if (source.name == "Wiflix") - EditTextPreference( - key: "overrideBaseUrl", - title: "Changer l'url de base", - summary: "", - value: "https://wiflix-hd.vip", - dialogTitle: "Changer l'url de base", - dialogMessage: "", - text: "https://wiflix-hd.vip", - ), - if (source.name == "French Anime") - EditTextPreference( - key: "overrideBaseUrl", - title: "Changer l'url de base", - summary: "", - value: "https://french-anime.com", - dialogTitle: "Changer l'url de base", - dialogMessage: "", - text: "https://french-anime.com", - ), - ]; - } - - @override - List getFilterList() { - return [ - HeaderFilter("La recherche de texte ignore les filtres"), - if (source.name == "French Anime") - SelectFilter("CategoriesFilter", "Catégories", 0, [ - SelectFilterOption("", ""), - SelectFilterOption("Action", "/genre/action/"), - SelectFilterOption("Aventure", "/genre/aventure/"), - SelectFilterOption("Arts martiaux", "/genre/arts-martiaux/"), - SelectFilterOption("Combat", "/genre/combat/"), - SelectFilterOption("Comédie", "/genre/comedie/"), - SelectFilterOption("Drame", "/genre/drame/"), - SelectFilterOption("Epouvante", "/genre/epouvante/"), - SelectFilterOption("Fantastique", "/genre/fantastique/"), - SelectFilterOption("Fantasy", "/genre/fantasy/"), - SelectFilterOption("Mystère", "/genre/mystere/"), - SelectFilterOption("Romance", "/genre/romance/"), - SelectFilterOption("Shonen", "/genre/shonen/"), - SelectFilterOption("Surnaturel", "/genre/surnaturel/"), - SelectFilterOption("Sci-Fi", "/genre/sci-fi/"), - SelectFilterOption("School life", "/genre/school-life/"), - SelectFilterOption("Ninja", "/genre/ninja/"), - SelectFilterOption("Seinen", "/genre/seinen/"), - SelectFilterOption("Horreur", "/genre/horreur/"), - SelectFilterOption("Tranche de vie", "/genre/tranchedevie/"), - SelectFilterOption("Psychologique", "/genre/psychologique/"), - ]), - if (source.name == "French Anime") - SelectFilter("GenresFilter", "Genres", 0, [ - SelectFilterOption("", ""), - SelectFilterOption("Animes VF", "/animes-vf/"), - SelectFilterOption("Animes VOSTFR", "/animes-vostfr/"), - SelectFilterOption("Films VF et VOSTFR", "/films-vf-vostfr/"), - ]), - if (source.name == "Wiflix") - SelectFilter("CategoriesFilter", "Catégories", 0, [ - SelectFilterOption("", ""), - SelectFilterOption("Séries", "/serie-en-streaming/"), - SelectFilterOption("Films", "/film-en-streaming/"), - ]), - if (source.name == "Wiflix") - SelectFilter("GenresFilter", "Genres", 0, [ - SelectFilterOption("", ""), - SelectFilterOption("Action", "/film-en-streaming/action/"), - SelectFilterOption("Animation", "/film-en-streaming/animation/"), - SelectFilterOption( - "Arts Martiaux", - "/film-en-streaming/arts-martiaux/", - ), - SelectFilterOption("Aventure", "/film-en-streaming/aventure/"), - SelectFilterOption("Biopic", "/film-en-streaming/biopic/"), - SelectFilterOption("Comédie", "/film-en-streaming/comedie/"), - SelectFilterOption( - "Comédie Dramatique", - "/film-en-streaming/comedie-dramatique/", - ), - SelectFilterOption( - "Épouvante Horreur", - "/film-en-streaming/horreur/", - ), - SelectFilterOption("Drame", "/film-en-streaming/drame/"), - SelectFilterOption( - "Documentaire", - "/film-en-streaming/documentaire/", - ), - SelectFilterOption("Espionnage", "/film-en-streaming/espionnage/"), - SelectFilterOption("Famille", "/film-en-streaming/famille/"), - SelectFilterOption("Fantastique", "/film-en-streaming/fantastique/"), - SelectFilterOption("Guerre", "/film-en-streaming/guerre/"), - SelectFilterOption("Historique", "/film-en-streaming/historique/"), - SelectFilterOption("Musical", "/film-en-streaming/musical/"), - SelectFilterOption("Policier", "/film-en-streaming/policier/"), - SelectFilterOption("Romance", "/film-en-streaming/romance/"), - SelectFilterOption( - "Science-Fiction", - "/film-en-streaming/science-fiction/", - ), - SelectFilterOption("Spectacles", "/film-en-streaming/spectacles/"), - SelectFilterOption("Thriller", "/film-en-streaming/thriller/"), - SelectFilterOption("Western", "/film-en-streaming/western/"), - ]), - ]; - } -} - -DataLifeEngine main(MSource source) { - return DataLifeEngine(source: source); -} diff --git a/dart/anime/multisrc/datalifeengine/sources.dart b/dart/anime/multisrc/datalifeengine/sources.dart deleted file mode 100644 index 9d2403ed..00000000 --- a/dart/anime/multisrc/datalifeengine/sources.dart +++ /dev/null @@ -1,23 +0,0 @@ -import '../../../../model/source.dart'; -import 'src/frenchanime/frenchanime.dart'; -import 'src/wiflix/wiflix.dart'; - -const _datalifeengineVersion = "0.0.65"; -const _datalifeengineSourceCodeUrl = - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/multisrc/datalifeengine/datalifeengine.dart"; - -List get datalifeengineSourcesList => _datalifeengineSourcesList; -List _datalifeengineSourcesList = - [ - //French Anime (FR) - frenchanimeSource, - //Wiflix (FR) - wiflixSource, - ] - .map( - (e) => - e - ..sourceCodeUrl = _datalifeengineSourceCodeUrl - ..version = _datalifeengineVersion, - ) - .toList(); diff --git a/dart/anime/multisrc/datalifeengine/src/frenchanime/frenchanime.dart b/dart/anime/multisrc/datalifeengine/src/frenchanime/frenchanime.dart deleted file mode 100644 index 719dcece..00000000 --- a/dart/anime/multisrc/datalifeengine/src/frenchanime/frenchanime.dart +++ /dev/null @@ -1,13 +0,0 @@ -import '../../../../../../model/source.dart'; - -Source get frenchanimeSource => _frenchanimeSource; - -Source _frenchanimeSource = Source( - name: "French Anime", - baseUrl: "https://french-anime.com", - lang: "fr", - typeSource: "datalifeengine", - itemType: ItemType.anime, - iconUrl: - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/multisrc/datalifeengine/src/frenchanime/icon.png", -); diff --git a/dart/anime/multisrc/datalifeengine/src/frenchanime/icon.png b/dart/anime/multisrc/datalifeengine/src/frenchanime/icon.png deleted file mode 100644 index 62591a8ef47880bf6256785139b2d40fcc92fa0b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5173 zcmY+IcQhRB`^N2RD@1QmSIf!p57?z^A^#I?14Z0F&m!nMiecAWQ&bTShi9U27yi!9tN-8+a8BbYXSdYoYsgls{FRMwt!qe0U3Nv3mz!si zGO3a;><1%1nn<1#Ha9m(1&Z|2{tITH{R(@-rTS&RlhTuulPH=3-|cMs{z$q{2chRh zgOpLM7;8tu4bEeoo2-cdgxFW>SN`rS(LgB_WP_j)+{-n}=LU&4LpYys?ZmuNINnN z{XJJfNcrk;gW1!9ZfxdrHn05X77nF(rJ6XhDLfN8mOIXxzwh>mQHxZ`;WP3m>fts? zS>{%l=AZ&iHi9_~rlGfZJ!#(4+SL8t!~{1b0!xNy=rIgVFj-dBnbVilaofuhg=4k! zA&6hpFOA%FOZPIX??SY1a*7C~>GdFCBNk)i0|+4<3h^4BRL^vpwzwy}xt){}R<*ix z^DP4^rmpx+@f_pHUJ}j0lY~_yk)F4fv$kU)cD_?UL)^&QSCK!1vgo0HyezlYReV}G(Y567cJn#HGVh~mTUnobwsI0Hy zZiip8p+Ioe;Gs`eheb5H){Jt45Xrw-y=+F_-U*F5wCuxD{5mo6MBp9i6u)XByB3%% z1+qWfs~k&#sNhTzmQ<>$sNHjAgzrwItcZ?DZUWzjvQpKU5 z?jL?Gd1uPlIr5PZ6$WE` zgsn3wZ7mG}iTnXDCfU~B{%QE_wAGN~)+krSfQNDgt_;&XgV#)0t$c10cIz|Z(kXyplIrzhf>pAGxS+8fk>g($Xqob@%R*YC3VeLBepK~o?qM7>5 zv(g0dr}|tO)jw$XG#?x~w*=7WPhEI$juvO>!jhJdZ_wUp*QhTG>7;2Ykp=xjnDvs? z%)aHx$w_Gb!0uufJ&{N>x3r{e-_uxGS^2iQcT-A=UueE1A$CXtiFvj@6uO3OfS%sa zy8g5j!RMHc5XMoCcIdXc35MJ2F~~<8yvcA8?Zz(u%!T1Za}Cgv*~jbkL$$=+l>y$0 zA8tD7ODb>BFitM6M~@#nMn%D=qq3(WH=2qUinpvFF~gDwK4wNFmq}FS_YQyltQWDS zuYGGf#Tule17$kJYNcDBxY9D-w;A2%z_;V@nE`j=t&0tROrcTv58>8!d5qAg@}bcT9Mqzwv(g*+<@Vw5 zPIC$7vy;qQco{!zczQAZr8S1GVJ+w7o3F*k1gCEuB_$K|5592X*qf|Uv$HuiNo|Jp zQ=$-X-hlW)Xkma_%4!Hi$lTm~et{6L5&4H(h>FX#DL2bmq0VY}ghOcf>u@LGN>Fjk ze=Y;6sdt))OHr*GyCl-Vt9%yjF(xn{43dIdwQPE32!eS{rh(97~pjmU^3n*14R`Vl_1@5H!mW zL-pfj2h-K%yoCLFc1(kq!ufqBG$#>kT8zKz?*Cg6hBLRa5-l2HOY6}u8~eEz5(Awd z$XEX9r#iZ(Kv8b;9ETIT@(c`=i^9cholQ&|C}pc)=If!)babfRxllvOYatDF0ikgZ zyiFpeuKPOZks4RiH21N)CmPQXpozfT!a~Q8kX)~ieU)Z4!TZ0A13ZK?pgDcUH#vJ( z_ZlqlY%L|O6(S*zO2fpD!B&pG?2zSXzFDiAl04I?9^Hr00vlT&h;o}pI~r+IQ;$$M z*1o>JjL%IUKEx68CTeWP)&f$QSDK}}>@pe~6&H7o8$Y7ICxPL_ids&wv){!`p&qdm zw0EMYlhw|+%2^7O&c@ah0AbtJA(isGeEEPC(`CovE~T!nu8=<<;@0iU2dMvOi0l7Oh#QOK79K0jS$b2o1agvX$7_K1oPn)f4F6DY-fqhgIJ^!yhwE&6*B?2vNv{%%;m zgt<+gt@QGX1XalCBO`aAY@dXt7lhDwiJ=O<4~MD@Qp8p=wLT2!j7Ipe%&uQtMX$xZ zk25%QxsGe%^0K2{9XARFtTz#F7k__w)O?GX*DscbvF#`(azEC&BZCD*%y6-D7?lry zh1?y{O-&PAL4G~Gf%)ZUK`(129E&q`XEV>KX(e;{C5I>@275Nqn0h4F2{d^IHOr)lk-4k(KkqWyk=07 z0s{;AoYbAlHp!ijQ7y4*Vl8}b_gh95r>YHw53j(~&-;JX&AU4}#XWoW?AxUv>hr9V zw|5!}*V)klx@FVq;Ora^h0JvepapudOD#6G;yZxKW^x@NnC3}g?-fuZYg@s*#vo1EJBlABh&Bn=r;Us6^ z$$m`+H4{k??ziu@NNq!aSEnvnRj>x%Fd3G4xbB`7j1*1*huu5G@cuH~I6NuezQ*)aD;o}nW6>ij%3 zZ@HSRdp8eJq9vKF*0`?P`$L9A3*jDal(oDCE?xXq=4;1|5I-L9qA@bW>H7W~5HgjR%hntxr-qMDBVj9LXEN8O|^L zn)>JF1P(&^@qs`2Pg;lia&Aq{&UPI|Xbjz9EWiRzs-&cJd`hkv+W7KGk?KpBHm5CR z>?UHESEyZ>z{q$T;$9AuVeCG8sMaGHlO8? zV4X=C#p}bAo%=p_6JF4OVyBs7%f#k78#{R2h|P zDvY$Wv>IWD$xz7T?5v}clejQ68)Yn+eVzRZFq2y&kFzG%(vxWl5Q;}ssPhyeGFJg* zn@6SGST7#-YYMv>r@N;B2FUg|uL4VX2!5&I_Auaaj(6)x+^yE*m|%@T@+vh!>lzg#-J_nD-9-m80r2>GUHMmk)t-&ItGgeZ0bogEh!FUguSXlAEt$R8@sw7S zl@3roNgvLnE)K*s00+4hS3jZkcNMtqV|<^b-Q%)7>tJuDZH`yehU?0#m`{zQK2G%K zix0nTSZ*Smfh>Sr_zLS@-S6)=$V#m?k!+aR5LrUPfa)=TOiUydf8=Y6Tfg87)lNMy z{yKW%)k~j(uqt8e7HAxQIsi*D=Y5Ylq;_$l#Jk@Mc3;7vPL!GFgJ?JER!? z^v`AO;}#42`_G?wIc#H@S^m0&+9vT+iT#?V`>86F4I4Sb>lUc;I!1afX{}j$Eg%no z6Oaw+%x_M^4d8$msuePJa|1cJ#hM9c;=sh$(_zuKupoptO#-BGc&Iexp#)aXK-L1} zt~39OakCoh5%Pi8zu2AKB}`Q}59sYgO%cOcOn>pfpBJ83!tG02I$tEV@g)=jU@H9b z{K&)Gn~e(8Xp!R9_c4#H2gqH@F&|=`wIZF3THoB9y9wf| zq~&g4JPZ2xi#e9sHg2q;?GYtc1LzKuc+rqN93J(Rg6UtAE++V&_8gnYUct*_y=2({ zHGZHD6wGQuj5F!3@!sGdV|;x4r)u8D^0ZWrq%I&6+5-K8pRXAjBeqPtK|Q>dDI?sT zTC`8+hFQQK5YwU)ozG*TQE@3|JvVH+U;TPnN;=;R3P1Q^rgz9cu|U{k+InqeX<0h! zWuKgg41AoEot^#8l^jgDg_qJl^xnO~JbgH8SaPOpW)5vA9+>%lMr}4-TN>i!wfXI= zoBR8+oMF-J6mZ#CbD^FMt+rN^)ym1oo0;&WCy(`qVc97e~x8=U2*^5;HZaEseudLv~L!VkYc8Pb7f7+xyP@adZN&4|D1SO$8H0EHhPTY!M=aRl7R-a1 z3x3+Frm~ec*xnC$_f{Hoam9$bSu1$J>-up?^!9FAlZIy-@w8BVM&jVOU}+;^Lg=45 zP-eLJo+Cx;y0aIefJ_t4+HRPab@Uud4yO3+s2y(ObUyCct}s5LaCqMJuGn=NTe%)3 zD8Nj%l9&u?x5>cj!*SbcDSL%iKT%$wsgffrY0_IaxiPH2f73Xue;-g;)1>FdjUSao zocMap-CmP7)7-R60Z&Mvzu)ivbHC0PB7+^Vh?0G9?|TR)MLwToHZRhid{V;#u5JLw zwJ~$W+8$fFZv^Fl!ddIjBPb%FaPTD!)l$05=2n8fmWBJJ8DuAySvaUr_f%7^7Ptx4 zpjE>Tslr#3q(KC{C;l7_F{bp>a_aXt7?5wK9=%3!A=usqzJ(>WGsmy8K)Xe?MlK&$ zQOQt>u1(N&pW=$!FxM)6`A`IhQA9d#x7{|RR<&n*P21;s+^h`!nTq{LbxdjX$M*ov zMdjr}KTZ+c#SJ$(WE0Y6`jGw+zUbORebDK(Df`(+uf3OdOc?W`=<=TM!h_A9|2O6& bPNJ5c(6DOu(zgS@11a?HKG3N~U}F9Ue#+&E diff --git a/dart/anime/multisrc/datalifeengine/src/wiflix/icon.png b/dart/anime/multisrc/datalifeengine/src/wiflix/icon.png deleted file mode 100644 index 3317e74495c1ae9d09c24688d963c4e4e25a8cf3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4635 zcmV+$66EcPP)m@ktA7z8u<0t3uz zo+kE#k-$#NZg)?&mKI5IsqHR#;H~NsMM{)dRLf&s;6fx->-nGkoLdEV<8IuIyKy(} z#@)CZcjIo{jUU?(YwjoRNC<$R`@1m!M3^#6QJX(j!q=y*eQp?lUm^Jw^3zX0z4zgV zAO3xoW&dcc{d4dAWAD$NZ~ptat6uQ``fp7fZNKmYtEj~+exx4~fWH^!LiBE%fzP25-$1l}Y7^Z(OYv$wbR-^Q4K z_}%Y*_bp&n0YR=ve0A^Mz0Upn_y66wr^1s9336~74Vz) z-g|Ew(5ui_t{@=-h(7!5vws>427h@|#A<>_n+1k;l?%L%dRmtNx5TwwDMKJP$sMa0>rEK%AAodRNdm5Q;_G@!e@d~$s)pjialauh zd0VdQZMQ#{0&ub+5p4>P)lPPMr9*B~e4AE1*XDNd7F^rT4Fhl$;@^fe#>Pj|un}&G z>u+NkLrPiA%72s+r4(9gl$xb<@;qlcol+DxHzZnrCf z3Ly|eRD@MZojFDv$MkwV;yA7VDFN8o*{J|HK0Zck&GYBa84LzwS$2EkfU8PGQ#qvi zh~t$0;|S9uH8d%O@hA+SP_ z172&QIOgHQhkX3;$9(X?2fX|4yYza!a{!boMTj?90;Lq)ZkH&Es_UDd0KHz1D2lMw z^8ER8`u#rETAXt?X#*}ty5$_ZMM2M6+SZav$*VYKEajErgtoOjNmKTWp&f2Ak&;{p zjFe2Jq^~t}I_x}nz(*f_#3!G8!q0#HbK328Wjuut$Y50K99<=Cgdopz&XrojwU&RQ zDB}J1-)A%$@x>Qk@bcwLrqk&e0In+8dL5#doZfPdwsW++M?1%sG29OTw4CE4iWo!@ zqq&P~IY-Z0y!VW?rkInE$T{vC!%wn|y*x)dN2(OLlo%lxYR#)wi>%jUYio-~j~?;< z`|tD9pZ;{I+FSO!bM8`3R!Y(7blBP1sU&6|%p0`@SryYySFGv|rCr)MpXvy7jlDLrekLg0cMFi?u` zI~`88w<)5i(&5(HjpesWl~aPXu7|dk3ew)Q9SHQ{WWqaH#uaIe-11JKo)Tq&@YVeoQFB1tLF==r8> zowXJlq_&C3c`X2>_r%7qQxrVPGTzB^wD+iBe3uEd2-|e6<$h7jh-od#Ijj))8sS#C zN$)*AaAnD%rR&*bY;hR?Hxvi>GkFXhxU}aSTczlSZG;f08X(epoDj%hU`th{yysq? zv#T|yQA8dHC%i|8xk%G`AuvDz*c$Om3D`uc+Bt_Y2Im~>c8N3^2h<5)S2e0M)By-z zQ(Zg8&@+aXbG(;jjI}10l00}zDgf1X4!MBitPmtpl1NDbXC&Y{k@{66U>(=9F%@Kh zR4Gy^aSLur1g}UtN8}ul_gEp&-qSON9b;%)OUF4LXBn@fh=ZCTmO$G%I?kaM9N&3A z0}L>M_{Nw@MJyxYynDGSF|#aVJRWm$a>8UXp(u(=!QLnUg%I?WVh}iYk&VFn8Sw)U zA^@-zxL*7Lzv z-Hr^0L%#q1d!9ah%Inv!Nz-(p$Fr>6AQys6%1ZrQBmwo`oO5JZ#$+-f%d#{3*WJuI z04FCWeDlpWJbn6<)6>&)f!o`&0Yc1X{rlWWwnNZ0k&>2kJS++x6a}&O=nxZZTT459 zHzgPPx#N3ZeYR4PXiX9f`@94!yZ(~% zJUnC)g2%VwhAwggbEU}Rm|~gB7*fDG5H%Kpwo=5c7SdYq9wh`@TJx@RO!J&Wt=S5} zR@`cVbLW!arqv>eA`&Sp2{6V~+KtCUg*Au0pBySq!L(>W7aH`zULZ2->bSfwD2 z@qu&PoEPMSVT_z(2iTPoEhTO)c2EJN`_A!>F=!yt`pkCTd#v{q-p>M|JU`>t*KNSE zTu_;)lTxC!KAT<%`rjCXQmV2MO(*smbwjNXGh-OXL`tDbf|c=rbHv8b3wpU1JR3h> z7y)AM*$PQI8PtSVXJyJbM`8?#5ZI!a*^yv`i=w!+YoSckEz1|xQw=4so8bP&N|Lz{ z43wfDMYN-c)*QjK_w0n?3_v@Gx?8|i!h2$C*$Y`x)oRTopmw8$wT$wdkuemddm4;r z-G{#}*OvSFAZ1OY95xDo1ri}hmBO@I=L#>x+{l?wU3)8!S5T@qSpNRti9f+ZYKwd%^ z8PwFWYp~u^I7c3;Zmt#u=Xp++WmP)jA`nWWJs&+=YpcxXXf$FvovvKwd@Cx*c~5E# zX;I*c;(RJ1*Z}|;l5DHi6zasU_6welvG$DqH^z`82}zPvdb@Nhml@mXbXsj+f@ZBH zO;ZjJ4>>wIVmKU91e??(_cs#<1TP^sh9b{#O2J%yz08WTKy|qqNMafB=LuI7B*6}t zT5i86iYgi|0jT$Uo~vgV!|CZMuV25W-|tsxhEf6!4i2iso0+Rezf}Mhxni~`u;E5! zjax3_Y71oHf1O|#F68`@a7Do|O&Ju$o2)5RQR`?lBF}TIwM0?0R04{kpx^JazrWA^ z{yrxsCuem3WHRCS`1p3HpbL?A4sXmXbL<>q&TU*;(D9zru$>m-d<4CK_yFD*vOFg@ zrmDo1Dku#RaouxS27q&p>2%7;$qCP%J>%fupt1$!@v%GUdPS`SWK-)C8nFQuNUbFck|37V zSW7P{RJ;-?IS9F)C&sX2Epidp*ZPH=5LhWGq6j19%nc0$E{R#{|5fc*89$WmiOX6P zZv_C0E++S$f%goI!Az%!x(!&+Dd9p4Fln`TDJ35Gvn1g`QB)leivX}fkV{DtMNFlf zr6T5HggOAL6lLl~oK@NrZ>0@zAv2j-i%U~v**Cw;_y*#g0{wOy2aJk>G)-xRhtjpSY6-W6!F(D$ke(Ms%b6Gn8i=22-_R2IR%D7 zkcI6gLNE;~WFY|F<3bNmUTb@tCs-K`CrLt@rnKAbcp;8BhI~<;Wq<}q-3NNCiL_qVV2dgGc)XKfRR#+SyNTWq^67di|Tzy zLXb*Hsw8HKOX-}eRx_q)dZ8^S3o>;Tbkjz-832L=WI|9dD;fGr>IWxE(GQC!~h;b;=%o9xrK~WS81_KTb4)EU7>2#{J!elb3?80a?;^oVieD~dVOsCV0)_!jU zfK(}7wA-jqg6tSGtAdr@PXOoJcAG&Ik%gNrf^j{FWB#wx;V6n2mjDRCL@CBfG18i` zQY31z5iaYzMN#nL#S5HsJb(V2D2mSIi2%|x<>cgqe!owi=hdRVA0zsc2tDe`_BtR*J zF^0ilP$kyNw!``}AIQ3#&w<}>Ivu^hEj59Ig%DMtrOW|&&ewz2S&6?a zz$$xw>ZQqf9bXpUH>Uf4e}guFnzvKC!-d@sn;?80fRekLINp_q*suy(_omi*LW;OJ z$Y}ccrq}k%Z!#U-qJ?TvnzUk+SUT5FiO#F@5fK8~Q>+JtSdBmB% zX@WOJoK36){*zNdn;^=c3gNE>z*T+an|x&aZ6f}aVwM%1Dh~`-Iq|A#;3m2L7IOZO z6<=qyG63HD{hK2A{IP#PgfFk{k4*tky`XF~8vS;Y1iuPlZ@aFaPN%Bg?XHUcGwt?@+B-yzqioNq|d0gpT3=>UO(-Ev0r--zTE*4porB>9h{qody>Npb*;fGM-~*R=ri zrYxsn18-BUZ!frem+&GGN@>{8`-Csv_s1*&i$33tyKy(}#@)CZcjLB?{|7sV{=(xS R%8~#8002ovPDHLkV1n}Z&2az# diff --git a/dart/anime/multisrc/datalifeengine/src/wiflix/wiflix.dart b/dart/anime/multisrc/datalifeengine/src/wiflix/wiflix.dart deleted file mode 100644 index c4682ee4..00000000 --- a/dart/anime/multisrc/datalifeengine/src/wiflix/wiflix.dart +++ /dev/null @@ -1,13 +0,0 @@ -import '../../../../../../model/source.dart'; - -Source get wiflixSource => _wiflixSource; - -Source _wiflixSource = Source( - name: "Wiflix", - baseUrl: "https://wiflix-hd.vip", - lang: "fr", - typeSource: "datalifeengine", - itemType: ItemType.anime, - iconUrl: - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/multisrc/datalifeengine/src/wiflix/icon.png", -); diff --git a/dart/anime/multisrc/dopeflix/dopeflix.dart b/dart/anime/multisrc/dopeflix/dopeflix.dart deleted file mode 100644 index 112259d8..00000000 --- a/dart/anime/multisrc/dopeflix/dopeflix.dart +++ /dev/null @@ -1,577 +0,0 @@ -import 'package:mangayomi/bridge_lib.dart'; -import 'dart:convert'; - -class DopeFlix extends MProvider { - DopeFlix({required this.source}); - - MSource source; - - final Client client = Client(); - - @override - String get baseUrl => getPreferenceValue(source.id, "preferred_domain"); - - @override - Future getPopular(int page) async { - final res = - (await client.get( - Uri.parse( - "$baseUrl/${getPreferenceValue(source.id, "preferred_popular_page")}?page=$page", - ), - )).body; - return parseAnimeList(res); - } - - @override - Future getLatestUpdates(int page) async { - final res = (await client.get(Uri.parse("$baseUrl/home"))).body; - List animeList = []; - final path = - '//section[contains(text(),"${getPreferenceValue(source.id, "preferred_latest_page")}")]/div/div[@class="film_list-wrap"]/div[@class="flw-item"]/div[@class="film-poster"]'; - final urls = xpath(res, '$path/a/@href'); - final names = xpath(res, '$path/a/@title'); - final images = xpath(res, '$path/img/@data-src'); - - for (var i = 0; i < names.length; i++) { - MManga anime = MManga(); - anime.name = names[i]; - anime.imageUrl = images[i]; - anime.link = urls[i]; - animeList.add(anime); - } - return MPages(animeList, false); - } - - @override - Future search(String query, int page, FilterList filterList) async { - final filters = filterList.filters; - String url = "$baseUrl"; - - if (query.isNotEmpty) { - url += "/search/${query.replaceAll(" ", "-")}?page=$page"; - } else { - url += "/filter/?page=$page"; - for (var filter in filters) { - if (filter.type == "TypeFilter") { - final type = filter.values[filter.state].value; - url += "${ll(url)}type=$type"; - } else if (filter.type == "QualityFilter") { - final quality = filter.values[filter.state].value; - url += "${ll(url)}quality=$quality"; - } else if (filter.type == "ReleaseYearFilter") { - final year = filter.values[filter.state].value; - url += "${ll(url)}release_year=$year"; - } else if (filter.type == "GenresFilter") { - final genre = (filter.state as List).where((e) => e.state).toList(); - if (genre.isNotEmpty) { - url += "${ll(url)}genre="; - for (var st in genre) { - url += "${st.value}-"; - } - } - } else if (filter.type == "CountriesFilter") { - final country = (filter.state as List).where((e) => e.state).toList(); - if (country.isNotEmpty) { - url += "${ll(url)}country="; - for (var st in country) { - url += "${st.value}-"; - } - } - } - } - } - - final res = (await client.get(Uri.parse(url))).body; - return parseAnimeList(res); - } - - @override - Future getDetail(String url) async { - url = getUrlWithoutDomain(url); - final res = (await client.get(Uri.parse("$baseUrl$url"))).body; - MManga anime = MManga(); - final description = xpath(res, '//div[@class="description"]/text()'); - if (description.isNotEmpty) { - anime.description = description.first.replaceAll("Overview:", ""); - } - final author = xpath(res, '//div[contains(text(),"Production")]/a/text()'); - if (author.isNotEmpty) { - anime.author = author.first; - } - anime.genre = xpath(res, '//div[contains(text(),"Genre")]/a/text()'); - List episodesList = []; - final id = xpath(res, '//div[@class="detail_page-watch"]/@data-id').first; - final dataType = - xpath(res, '//div[@class="detail_page-watch"]/@data-type').first; - if (dataType == "1") { - MChapter episode = MChapter(); - episode.name = "Movie"; - episode.url = "$baseUrl/ajax/movie/episodes/$id"; - episodesList.add(episode); - } else { - final resS = - (await client.get(Uri.parse("$baseUrl/ajax/v2/tv/seasons/$id"))).body; - - final seasonIds = xpath( - resS, - '//a[@class="dropdown-item ss-item"]/@data-id', - ); - final seasonNames = xpath( - resS, - '//a[@class="dropdown-item ss-item"]/text()', - ); - for (int i = 0; i < seasonIds.length; i++) { - final seasonId = seasonIds[i]; - final seasonName = seasonNames[i]; - - final html = - (await client.get( - Uri.parse("$baseUrl/ajax/v2/season/episodes/$seasonId"), - )).body; - - final epsHtmls = parseHtml(html).select("div.eps-item"); - - for (var epH in epsHtmls) { - final epHtml = epH.outerHtml; - final episodeId = - xpath( - epHtml, - '//div[contains(@class,"eps-item")]/@data-id', - ).first; - final epNum = - xpath(epHtml, '//div[@class="episode-number"]/text()').first; - final epName = xpath(epHtml, '//h3[@class="film-name"]/text()').first; - MChapter episode = MChapter(); - episode.name = "$seasonName $epNum $epName"; - episode.url = "$baseUrl/ajax/v2/episode/servers/$episodeId"; - episodesList.add(episode); - } - } - } - anime.chapters = episodesList.reversed.toList(); - return anime; - } - - @override - Future> getVideoList(String url) async { - url = getUrlWithoutDomain(url); - final res = (await client.get(Uri.parse("$baseUrl/$url"))).body; - - final vidsHtmls = parseHtml(res).select("ul.fss-list a.btn-play"); - - List videos = []; - for (var vidH in vidsHtmls) { - final vidHtml = vidH.outerHtml; - final id = xpath(vidHtml, '//a/@data-id').first; - final name = xpath(vidHtml, '//span/text()').first; - final resSource = - (await client.get(Uri.parse("$baseUrl/ajax/sources/$id"))).body; - - final vidUrl = substringBefore( - substringAfter(resSource, "\"link\":\""), - "\"", - ); - List a = []; - String masterUrl = ""; - String type = ""; - if (name.contains("DoodStream")) { - a = await doodExtractor(vidUrl, "DoodStream"); - } else if (["Vidcloud", "UpCloud"].contains(name)) { - final id = substringBefore(substringAfter(vidUrl, "/embed-4/"), "?"); - final serverUrl = substringBefore(vidUrl, "/embed"); - - final resServer = - (await client.get( - Uri.parse("$serverUrl/ajax/embed-4/getSources?id=$id"), - headers: {"X-Requested-With": "XMLHttpRequest"}, - )).body; - final encrypted = getMapValue(resServer, "encrypted"); - - String videoResJson = ""; - if (encrypted == "true") { - final ciphered = getMapValue(resServer, "sources"); - - List> indexPairs = await generateIndexPairs(); - - var password = ''; - String ciphertext = ciphered; - int index = 0; - for (List item in json.decode(json.encode(indexPairs))) { - int start = item.first + index; - int end = start + item.last; - String passSubstr = ciphered.substring(start, end); - password += passSubstr; - ciphertext = ciphertext.replaceFirst(passSubstr, ""); - index += item.last; - } - videoResJson = decryptAESCryptoJS(ciphertext, password); - masterUrl = - ((json.decode(videoResJson) as List>) - .first)['file']; - - type = - ((json.decode(videoResJson) as List>) - .first)['type']; - } else { - masterUrl = - ((json.decode(resServer)["sources"] as List>) - .first)['file']; - - type = - ((json.decode(resServer)["sources"] as List>) - .first)['type']; - } - - final tracks = - (json.decode(resServer)['tracks'] as List) - .where((e) => e['kind'] == 'captions' ? true : false) - .toList(); - List subtitles = []; - - for (var sub in tracks) { - try { - MTrack subtitle = MTrack(); - subtitle - ..label = sub["label"] - ..file = sub["file"]; - subtitles.add(subtitle); - } catch (_) {} - } - - subtitles = sortSubs(subtitles, source.id); - if (type == "hls") { - final masterPlaylistRes = - (await client.get(Uri.parse(masterUrl))).body; - - for (var it in substringAfter( - masterPlaylistRes, - "#EXT-X-STREAM-INF:", - ).split("#EXT-X-STREAM-INF:")) { - final quality = - "${substringBefore(substringBefore(substringAfter(substringAfter(it, "RESOLUTION="), "x"), ","), "\n")}p"; - - String videoUrl = substringBefore(substringAfter(it, "\n"), "\n"); - - if (!videoUrl.startsWith("http")) { - videoUrl = - "${(masterUrl as String).split("/").sublist(0, (masterUrl as String).split("/").length - 1).join("/")}/$videoUrl"; - } - - MVideo video = MVideo(); - video - ..url = videoUrl - ..originalUrl = videoUrl - ..quality = "$name - $quality" - ..subtitles = subtitles; - a.add(video); - } - } else { - MVideo video = MVideo(); - video - ..url = masterUrl - ..originalUrl = masterUrl - ..quality = "$name - Default" - ..subtitles = subtitles; - a.add(video); - } - } - videos.addAll(a); - } - - return sortVideos(videos, source.id); - } - - Future>> generateIndexPairs() async { - final res = - (await client.get( - Uri.parse("https://rabbitstream.net/js/player/prod/e4-player.min.js"), - )).body; - - String script = substringBefore(substringAfter(res, "const "), "()"); - script = script.substring(0, script.lastIndexOf(',')); - final list = - script - .split(",") - .map((String e) { - String value = substringAfter(e, "="); - if (value.contains("0x")) { - return int.parse(substringAfter(value, "0x"), radix: 16); - } else { - return int.parse(value); - } - }) - .toList() - .skip(1) - .toList(); - return chunked( - list, - 2, - ).map((List list) => list.reversed.toList()).toList(); - } - - List> chunked(List list, int size) { - List> chunks = []; - for (int i = 0; i < list.length; i += size) { - int end = list.length; - if (i + size < list.length) { - end = i + size; - } - chunks.add(list.sublist(i, end)); - } - return chunks; - } - - MPages parseAnimeList(String res) { - List animeList = []; - final path = - '//div[@class="film_list-wrap"]/div[@class="flw-item"]/div[@class="film-poster"]'; - final urls = xpath(res, '$path/a/@href'); - final names = xpath(res, '$path/a/@title'); - final images = xpath(res, '$path/img/@data-src'); - - for (var i = 0; i < names.length; i++) { - MManga anime = MManga(); - anime.name = names[i]; - anime.imageUrl = images[i]; - anime.link = urls[i]; - animeList.add(anime); - } - final pages = xpath( - res, - '//ul[contains(@class,"pagination")]/li/a[@title="Next"]/@title', - ); - return MPages(animeList, pages.isNotEmpty); - } - - @override - List getFilterList() { - return [ - SelectFilter("TypeFilter", "Type", 0, [ - SelectFilterOption("All", "all"), - SelectFilterOption("Movies", "movies"), - SelectFilterOption("TV Shows", "tv"), - ]), - SelectFilter("QualityFilter", "Quality", 0, [ - SelectFilterOption("All", "all"), - SelectFilterOption("HD", "HD"), - SelectFilterOption("SD", "SD"), - SelectFilterOption("CAM", "CAM"), - ]), - SelectFilter("ReleaseYearFilter", "Released at", 0, [ - SelectFilterOption("All", "all"), - SelectFilterOption("2024", "2024"), - SelectFilterOption("2023", "2023"), - SelectFilterOption("2022", "2022"), - SelectFilterOption("2021", "2021"), - SelectFilterOption("2020", "2020"), - SelectFilterOption("2019", "2019"), - SelectFilterOption("2018", "2018"), - SelectFilterOption("Older", "older-2018"), - ]), - SeparatorFilter(), - GroupFilter("GenresFilter", "Genre", [ - CheckBoxFilter("Action", "10"), - CheckBoxFilter("Action & Adventure", "24"), - CheckBoxFilter("Adventure", "18"), - CheckBoxFilter("Animation", "3"), - CheckBoxFilter("Biography", "37"), - CheckBoxFilter("Comedy", "7"), - CheckBoxFilter("Crime", "2"), - CheckBoxFilter("Documentary", "11"), - CheckBoxFilter("Drama", "4"), - CheckBoxFilter("Family", "9"), - CheckBoxFilter("Fantasy", "13"), - CheckBoxFilter("History", "19"), - CheckBoxFilter("Horror", "14"), - CheckBoxFilter("Kids", "27"), - CheckBoxFilter("Music", "15"), - CheckBoxFilter("Mystery", "1"), - CheckBoxFilter("News", "34"), - CheckBoxFilter("Reality", "22"), - CheckBoxFilter("Romance", "12"), - CheckBoxFilter("Sci-Fi & Fantasy", "31"), - CheckBoxFilter("Science Fiction", "5"), - CheckBoxFilter("Soap", "35"), - CheckBoxFilter("Talk", "29"), - CheckBoxFilter("Thriller", "16"), - CheckBoxFilter("TV Movie", "8"), - CheckBoxFilter("War", "17"), - CheckBoxFilter("War & Politics", "28"), - CheckBoxFilter("Western", "6"), - ]), - GroupFilter("CountriesFilter", "Countries", [ - CheckBoxFilter("Argentina", "11"), - CheckBoxFilter("Australia", "151"), - CheckBoxFilter("Austria", "4"), - CheckBoxFilter("Belgium", "44"), - CheckBoxFilter("Brazil", "190"), - CheckBoxFilter("Canada", "147"), - CheckBoxFilter("China", "101"), - CheckBoxFilter("Czech Republic", "231"), - CheckBoxFilter("Denmark", "222"), - CheckBoxFilter("Finland", "158"), - CheckBoxFilter("France", "3"), - CheckBoxFilter("Germany", "96"), - CheckBoxFilter("Hong Kong", "93"), - CheckBoxFilter("Hungary", "72"), - CheckBoxFilter("India", "105"), - CheckBoxFilter("Ireland", "196"), - CheckBoxFilter("Israel", "24"), - CheckBoxFilter("Italy", "205"), - CheckBoxFilter("Japan", "173"), - CheckBoxFilter("Luxembourg", "91"), - CheckBoxFilter("Mexico", "40"), - CheckBoxFilter("Netherlands", "172"), - CheckBoxFilter("New Zealand", "122"), - CheckBoxFilter("Norway", "219"), - CheckBoxFilter("Poland", "23"), - CheckBoxFilter("Romania", "170"), - CheckBoxFilter("Russia", "109"), - CheckBoxFilter("South Africa", "200"), - CheckBoxFilter("South Korea", "135"), - CheckBoxFilter("Spain", "62"), - CheckBoxFilter("Sweden", "114"), - CheckBoxFilter("Switzerland", "41"), - CheckBoxFilter("Taiwan", "119"), - CheckBoxFilter("Thailand", "57"), - CheckBoxFilter("United Kingdom", "180"), - CheckBoxFilter("United States of America", "129"), - ]), - ]; - } - - @override - List getSourcePreferences() { - return [ - if (source.name == "DopeBox") - ListPreference( - key: "preferred_domain", - title: "Preferred domain", - summary: "", - valueIndex: 0, - entries: ["dopebox.to", "dopebox.se"], - entryValues: ["https://dopebox.to", "https://dopebox.se"], - ), - if (source.name == "SFlix") - ListPreference( - key: "preferred_domain", - title: "Preferred domain", - summary: "", - valueIndex: 0, - entries: ["sflix.to", "sflix.se"], - entryValues: ["https://sflix.to", "https://sflix.se"], - ), - ListPreference( - key: "preferred_quality", - title: "Preferred Quality", - summary: "", - valueIndex: 0, - entries: ["1080p", "720p", "480p", "360p"], - entryValues: ["1080p", "720p", "480p", "360p"], - ), - ListPreference( - key: "preferred_subLang", - title: "Preferred sub language", - summary: "", - valueIndex: 1, - entries: [ - "Arabic", - "English", - "French", - "German", - "Hungarian", - "Italian", - "Japanese", - "Portuguese", - "Romanian", - "Russian", - "Spanish", - ], - entryValues: [ - "Arabic", - "English", - "French", - "German", - "Hungarian", - "Italian", - "Japanese", - "Portuguese", - "Romanian", - "Russian", - "Spanish", - ], - ), - ListPreference( - key: "preferred_latest_page", - title: "Preferred latest page", - summary: "", - valueIndex: 0, - entries: ["Movies", "TV Shows"], - entryValues: ["Latest Movies", "Latest TV Shows"], - ), - ListPreference( - key: "preferred_popular_page", - title: "Preferred popular page", - summary: "", - valueIndex: 0, - entries: ["Movies", "TV Shows"], - entryValues: ["movie", "tv-show"], - ), - ]; - } - - List sortVideos(List videos, int sourceId) { - String quality = getPreferenceValue(sourceId, "preferred_quality"); - - videos.sort((MVideo a, MVideo b) { - int qualityMatchA = 0; - if (a.quality.contains(quality)) { - qualityMatchA = 1; - } - int qualityMatchB = 0; - if (b.quality.contains(quality)) { - qualityMatchB = 1; - } - if (qualityMatchA != qualityMatchB) { - return qualityMatchB - qualityMatchA; - } - - final regex = RegExp(r'(\d+)p'); - final matchA = regex.firstMatch(a.quality); - final matchB = regex.firstMatch(b.quality); - final int qualityNumA = int.tryParse(matchA?.group(1) ?? '0') ?? 0; - final int qualityNumB = int.tryParse(matchB?.group(1) ?? '0') ?? 0; - return qualityNumB - qualityNumA; - }); - - return videos; - } - - List sortSubs(List subs, int sourceId) { - String lang = getPreferenceValue(sourceId, "preferred_subLang"); - - subs.sort((MTrack a, MTrack b) { - int langMatchA = 0; - if (a.label.toLowerCase().contains(lang.toLowerCase())) { - langMatchA = 1; - } - int langMatchB = 0; - if (b.label.toLowerCase().contains(lang.toLowerCase())) { - langMatchB = 1; - } - return langMatchB - langMatchA; - }); - return subs; - } - - String ll(String url) { - if (url.contains("?")) { - return "&"; - } - return "?"; - } -} - -DopeFlix main(MSource source) { - return DopeFlix(source: source); -} diff --git a/dart/anime/multisrc/dopeflix/sources.dart b/dart/anime/multisrc/dopeflix/sources.dart deleted file mode 100644 index 2a4c484b..00000000 --- a/dart/anime/multisrc/dopeflix/sources.dart +++ /dev/null @@ -1,23 +0,0 @@ -import '../../../../model/source.dart'; -import 'src/dopebox/dopebox.dart'; -import 'src/sflix/sflix.dart'; - -const _dopeflixVersion = "0.0.6"; -const _dopeflixSourceCodeUrl = - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/multisrc/dopeflix/dopeflix.dart"; - -List get dopeflixSourcesList => _dopeflixSourcesList; -List _dopeflixSourcesList = - [ - //DopeBox (EN) - dopeboxSource, - //SFlix (EN) - sflixSource, - ] - .map( - (e) => - e - ..sourceCodeUrl = _dopeflixSourceCodeUrl - ..version = _dopeflixVersion, - ) - .toList(); diff --git a/dart/anime/multisrc/dopeflix/src/dopebox/dopebox.dart b/dart/anime/multisrc/dopeflix/src/dopebox/dopebox.dart deleted file mode 100644 index ef8a39c7..00000000 --- a/dart/anime/multisrc/dopeflix/src/dopebox/dopebox.dart +++ /dev/null @@ -1,13 +0,0 @@ -import '../../../../../../model/source.dart'; - -Source get dopeboxSource => _dopeboxSource; - -Source _dopeboxSource = Source( - name: "DopeBox", - baseUrl: "https://dopebox.to", - lang: "en", - typeSource: "dopeflix", - itemType: ItemType.anime, - iconUrl: - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/multisrc/dopeflix/src/dopebox/icon.png", -); diff --git a/dart/anime/multisrc/dopeflix/src/dopebox/icon.png b/dart/anime/multisrc/dopeflix/src/dopebox/icon.png deleted file mode 100644 index 0e467600241cdb6cdb05e90b4d90c53951be8003..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4126 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 diff --git a/dart/anime/multisrc/dopeflix/src/sflix/icon.png b/dart/anime/multisrc/dopeflix/src/sflix/icon.png deleted file mode 100644 index afdbec537024a228fb5883ee21a326621a4f7a74..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6778 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 diff --git a/dart/anime/multisrc/dopeflix/src/sflix/sflix.dart b/dart/anime/multisrc/dopeflix/src/sflix/sflix.dart deleted file mode 100644 index c19dbd1e..00000000 --- a/dart/anime/multisrc/dopeflix/src/sflix/sflix.dart +++ /dev/null @@ -1,13 +0,0 @@ -import '../../../../../../model/source.dart'; - -Source get sflixSource => _sflixSource; - -Source _sflixSource = Source( - name: "SFlix", - baseUrl: "https://sflix.to", - lang: "en", - typeSource: "dopeflix", - itemType: ItemType.anime, - iconUrl: - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/multisrc/dopeflix/src/sflix/icon.png", -); diff --git a/dart/anime/multisrc/zorotheme/sources.dart b/dart/anime/multisrc/zorotheme/sources.dart deleted file mode 100644 index df781707..00000000 --- a/dart/anime/multisrc/zorotheme/sources.dart +++ /dev/null @@ -1,22 +0,0 @@ -import '../../../../model/source.dart'; -import 'src/hianime/hianime.dart'; -import 'src/kaido/kaido.dart'; - -const _zorothemeVersion = "0.1.75"; -const _zorothemeSourceCodeUrl = - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/multisrc/zorotheme/zorotheme.dart"; - -List get zorothemeSourcesList => _zorothemeSourcesList; -List _zorothemeSourcesList = - [ - //AniWatch.to (EN) - aniwatchSource, - //Kaido.to (EN) - kaidoSource, - ] - .map( - (e) => e - ..sourceCodeUrl = _zorothemeSourceCodeUrl - ..version = _zorothemeVersion, - ) - .toList(); diff --git a/dart/anime/multisrc/zorotheme/src/hianime/hianime.dart b/dart/anime/multisrc/zorotheme/src/hianime/hianime.dart deleted file mode 100644 index 27bc3449..00000000 --- a/dart/anime/multisrc/zorotheme/src/hianime/hianime.dart +++ /dev/null @@ -1,14 +0,0 @@ -import '../../../../../../model/source.dart'; - -Source get aniwatchSource => _aniwatchSource; - -Source _aniwatchSource = Source( - id: 814067600, - name: "HiAnime", - baseUrl: "https://hianime.to", - itemType: ItemType.anime, - lang: "en", - typeSource: "zorotheme", - iconUrl: - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/multisrc/zorotheme/src/hianime/icon.png", -); diff --git a/dart/anime/multisrc/zorotheme/src/hianime/icon.png b/dart/anime/multisrc/zorotheme/src/hianime/icon.png deleted file mode 100644 index 02dc16cf9e6b32d95f98c33ac456397b80a08b55..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5120 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 diff --git a/dart/anime/multisrc/zorotheme/src/kaido/kaido.dart b/dart/anime/multisrc/zorotheme/src/kaido/kaido.dart deleted file mode 100644 index 59929d21..00000000 --- a/dart/anime/multisrc/zorotheme/src/kaido/kaido.dart +++ /dev/null @@ -1,13 +0,0 @@ -import '../../../../../../model/source.dart'; - -Source get kaidoSource => _kaidoSource; - -Source _kaidoSource = Source( - name: "Kaido.to", - baseUrl: "https://kaido.to", - lang: "en", - itemType: ItemType.anime, - typeSource: "zorotheme", - iconUrl: - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/multisrc/zorotheme/src/kaido/icon.png", -); diff --git a/dart/anime/multisrc/zorotheme/zorotheme.dart b/dart/anime/multisrc/zorotheme/zorotheme.dart deleted file mode 100644 index 908330db..00000000 --- a/dart/anime/multisrc/zorotheme/zorotheme.dart +++ /dev/null @@ -1,710 +0,0 @@ -import 'package:mangayomi/bridge_lib.dart'; -import 'dart:convert'; - -class ZoroTheme extends MProvider { - ZoroTheme({required this.source}); - - MSource source; - - final Client client = Client(); - - @override - Future getPopular(int page) async { - final res = (await client.get( - Uri.parse("${source.baseUrl}/most-popular?page=$page"), - )).body; - - return animeElementM(res); - } - - @override - Future getLatestUpdates(int page) async { - final res = (await client.get( - Uri.parse("${source.baseUrl}/recently-updated?page=$page"), - )).body; - - return animeElementM(res); - } - - @override - Future search(String query, int page, FilterList filterList) async { - final filters = filterList.filters; - String url = "${source.baseUrl}/"; - - if (query.isEmpty) { - url += "filter?"; - } else { - url += "search?keyword=$query"; - } - - for (var filter in filters) { - if (filter.type == "TypeFilter") { - final type = filter.values[filter.state].value; - if (type.isNotEmpty) { - url += "${ll(url)}type=$type"; - } - } else if (filter.type == "StatusFilter") { - final status = filter.values[filter.state].value; - if (status.isNotEmpty) { - url += "${ll(url)}status=$status"; - } - } else if (filter.type == "RatedFilter") { - final rated = filter.values[filter.state].value; - if (rated.isNotEmpty) { - url += "${ll(url)}rated=$rated"; - } - } else if (filter.type == "ScoreFilter") { - final score = filter.values[filter.state].value; - if (score.isNotEmpty) { - url += "${ll(url)}score=$score"; - } - } else if (filter.type == "SeasonFilter") { - final season = filter.values[filter.state].value; - if (season.isNotEmpty) { - url += "${ll(url)}season=$season"; - } - } else if (filter.type == "LanguageFilter") { - final language = filter.values[filter.state].value; - if (language.isNotEmpty) { - url += "${ll(url)}language=$language"; - } - } else if (filter.type == "SortFilter") { - final sort = filter.values[filter.state].value; - if (sort.isNotEmpty) { - url += "${ll(url)}sort=$sort"; - } - } else if (filter.type == "StartYearFilter") { - final sy = filter.values[filter.state].value; - if (sy.isNotEmpty) { - url += "${ll(url)}sy=$sy"; - } - } else if (filter.type == "StartMonthFilter") { - final sm = filter.values[filter.state].value; - if (sm.isNotEmpty) { - url += "${ll(url)}sm=$sm"; - } - } else if (filter.type == "StartDayFilter") { - final sd = filter.values[filter.state].value; - if (sd.isNotEmpty) { - url += "${ll(url)}sd=$sd"; - } - } else if (filter.type == "EndYearFilter") { - final ey = filter.values[filter.state].value; - if (ey.isNotEmpty) { - url += "${ll(url)}sy=$ey"; - } - } else if (filter.type == "EndMonthFilter") { - final em = filter.values[filter.state].value; - if (em.isNotEmpty) { - url += "${ll(url)}sm=$em"; - } - } else if (filter.type == "EndDayFilter") { - final ed = filter.values[filter.state].value; - if (ed.isNotEmpty) { - url += "${ll(url)}sd=$ed"; - } - } else if (filter.type == "GenreFilter") { - final genre = (filter.state as List).where((e) => e.state).toList(); - if (genre.isNotEmpty) { - url += "${ll(url)}genre="; - for (var st in genre) { - url += "${st.value},"; - } - } - } - } - url += "${ll(url)}page=$page"; - final res = (await client.get(Uri.parse(url))).body; - - return animeElementM(res); - } - - @override - Future getDetail(String url) async { - final statusList = [ - {"Currently Airing": 0, "Finished Airing": 1}, - ]; - final res = (await client.get(Uri.parse("${source.baseUrl}$url"))).body; - MManga anime = MManga(); - final status = xpath( - res, - '//*[@class="anisc-info"]/div[contains(text(),"Status:")]/span[2]/text()', - ); - if (status.isNotEmpty) { - anime.status = parseStatus(status.first, statusList); - } - - final author = xpath( - res, - '//*[@class="anisc-info"]/div[contains(text(),"Studios:")]/span/text()', - ); - if (author.isNotEmpty) { - anime.author = author.first.replaceAll("Studios:", ""); - } - final description = xpath( - res, - '//*[@class="anisc-info"]/div[contains(text(),"Overview:")]/text()', - ); - if (description.isNotEmpty) { - anime.description = description.first.replaceAll("Overview:", ""); - } - final genre = xpath( - res, - '//*[@class="anisc-info"]/div[contains(text(),"Genres:")]/a/text()', - ); - - anime.genre = genre; - final id = substringAfterLast(url, '-'); - - final urlEp = - "${source.baseUrl}/ajax${ajaxRoute('${source.baseUrl}')}/episode/list/$id"; - - final resEp = (await client.get( - Uri.parse(urlEp), - headers: {"referer": url}, - )).body; - - final html = json.decode(resEp)["html"]; - final epElements = parseHtml(html).select("a.ep-item"); - - List? episodesList = []; - - for (var epElement in epElements) { - final number = epElement.attr("data-number"); - final title = epElement.attr("title"); - - MChapter episode = MChapter(); - episode.name = "Episode $number: $title"; - episode.url = epElement.getHref; - episodesList.add(episode); - } - - anime.chapters = episodesList.reversed.toList(); - return anime; - } - - @override - Future> getVideoList(String url) async { - final id = substringAfterLast(url, '?ep='); - - final res = (await client.get( - Uri.parse( - "${source.baseUrl}/ajax${ajaxRoute('${source.baseUrl}')}/episode/servers?episodeId=$id", - ), - headers: {"referer": "${source.baseUrl}/$url"}, - )).body; - final html = json.decode(res)["html"]; - - final serverElements = parseHtml(html).select("div.server-item"); - - List videos = []; - final hosterSelection = preferenceHosterSelection(source.id); - final typeSelection = preferenceTypeSelection(source.id); - for (var serverElement in serverElements) { - final name = serverElement.text; - final id = serverElement.attr("data-id"); - final subDub = serverElement.attr("data-type"); - - final resE = (await client.get( - Uri.parse( - "${source.baseUrl}/ajax${ajaxRoute('${source.baseUrl}')}/episode/sources?id=$id", - ), - headers: {"referer": "${source.baseUrl}/$url"}, - )).body; - String epUrl = substringBefore(substringAfter(resE, "\"link\":\""), "\""); - List a = []; - if (hosterSelection.contains(name) && typeSelection.contains(subDub)) { - if (name.contains("Vidstreaming")) { - a = await rapidCloudExtractor(epUrl, "Vidstreaming - $subDub", id); - } else if (name.contains("Vidcloud")) { - a = await rapidCloudExtractor(epUrl, "Vidcloud - $subDub", id); - } else if (name.contains("StreamTape")) { - a = await streamTapeExtractor(epUrl, "StreamTape - $subDub"); - } else if ([ - "HD-1", - "HD-2", - "HD-3", - ].any((element) => name.contains(element))) { - a = await rapidCloudExtractor(epUrl, "$name - $subDub", id); - } - - videos.addAll(a); - } - } - - return sortVideos(videos, source.id); - } - - Future> rapidCloudExtractor( - String url, - String name, - String dataID, - ) async { - try { - final headers = {'Referer': 'https://megacloud.club/'}; - final serverUrl = ['https://megacloud.tv', 'https://rapid-cloud.co']; - - final serverType = RegExp(r'https://megacloud\..*').hasMatch(url) ? 0 : 1; - final sourceUrl = [ - '/embed-2/v2/e-1/getSources?id=', - '/ajax/embed-6-v2/getSources?id=', - ]; - final sourceSpliter = ['/e-1/', '/embed-6-v2/']; - final id = url.split(sourceSpliter[serverType]).last.split('?').first; - final response = await client.get( - Uri.parse('${serverUrl[serverType]}${sourceUrl[serverType]}$id'), - headers: {"X-Requested-With": "XMLHttpRequest"}, - ); - if (response.statusCode != 200) { - return []; - } - final resServer = response.body; - - final encrypted = getMapValue(resServer, "encrypted"); - List> videoResJson = []; - List videos = []; - if (encrypted == "true") { - final key = await getWorkingKey(dataID); - if (key == null) { - return []; - } - final sources = await getSource(dataID, key); - if (sources == null || sources['sources'] == null) { - return []; - } - videoResJson = sources['sources']; - } else { - videoResJson = json.decode(resServer)["sources"]; - } - - String masterUrl = videoResJson[0]['file']; - String type = videoResJson[0]['type']; - - final tracks = (json.decode(resServer)['tracks'] as List) - .where((e) => e['kind'] == 'captions' ? true : false) - .toList(); - List subtitles = []; - - for (var sub in tracks) { - try { - MTrack subtitle = MTrack(); - subtitle - ..label = sub["label"] - ..file = sub["file"]; - subtitles.add(subtitle); - } catch (_) {} - } - - if (type == "hls") { - final masterPlaylistRes = (await client.get( - Uri.parse(masterUrl), - headers: headers, - )).body; - - for (var it in substringAfter( - masterPlaylistRes, - "#EXT-X-STREAM-INF:", - ).split("#EXT-X-STREAM-INF:")) { - final quality = - "${substringBefore(substringBefore(substringAfter(substringAfter(it, "RESOLUTION="), "x"), ","), "\n")}p"; - - String videoUrl = substringBefore(substringAfter(it, "\n"), "\n"); - - if (!videoUrl.startsWith("http")) { - videoUrl = - "${masterUrl.split("/").sublist(0, masterUrl.split("/").length - 1).join("/")}/$videoUrl"; - } - - MVideo video = MVideo(); - video - ..url = videoUrl - ..originalUrl = videoUrl - ..quality = "$name - $quality" - ..subtitles = subtitles - ..headers = headers; - videos.add(video); - } - } else { - MVideo video = MVideo(); - video - ..url = masterUrl - ..originalUrl = masterUrl - ..quality = "$name - Default" - ..subtitles = subtitles - ..headers = headers; - videos.add(video); - } - return videos; - } catch (e) { - return []; - } - } - - // credits: https://github.com/50n50/sources/blob/main/hianime/hianime.js - Future getWorkingKey(String dataID) async { - try { - final res = await client.get( - Uri.parse( - 'https://raw.githubusercontent.com/itzzzme/megacloud-keys/refs/heads/main/key.txt', - ), - ); - final key = res.body.trim(); - final sources = await getSource(dataID, key); - - if (sources != null && sources['sources'] != null) return key; - } catch (e) {} - - try { - final res = await client.get( - Uri.parse( - 'https://justarion.github.io/keys/e1-player/src/data/keys.json', - ), - ); - final jsonRes = json.decode(res.body); - final key = jsonRes['megacloud']['anime']['key']; - final sources = await getSource(dataID, key); - if (sources != null && sources['sources'] != null) return key; - } catch (e) {} - - try { - final res = await client.get( - Uri.parse( - 'https://raw.githubusercontent.com/yogesh-hacker/MegacloudKeys/refs/heads/main/keys.json', - ), - ); - final jsonRes = json.decode(res.body); - final key = jsonRes['mega']; - final sources = await getSource(dataID, key); - if (sources != null && sources['sources'] != null) return key; - } catch (e) {} - - try { - final res = await client.get( - Uri.parse( - 'https://raw.githubusercontent.com/SpencerDevs/megacloud-key-updater/refs/heads/master/key.txt', - ), - ); - final key = res.body.trim(); - final sources = await getSource(dataID, key); - if (sources != null && sources['sources'] != null) return key; - } catch (e) {} - - return null; - } - - // credits: https://github.com/50n50/sources/blob/main/hianime/hianime.js - Future?> getSource(String sourceId, String key) async { - final res1 = await client.get( - Uri.parse("${source.baseUrl}/ajax/v2/episode/sources?id=$sourceId"), - ); - final json1 = json.decode(res1.body); - final link = json1['link'] ?? ""; - final idMatch = RegExp(r'/e-1/([^/?]+)').firstMatch(link); - final streamId = idMatch?.group(1); - - if (streamId == null) return null; - - final res2 = await client.get( - Uri.parse( - 'https://megacloud.blog/embed-2/v2/e-1/getSources?id=$streamId', - ), - ); - final json2 = json.decode(res2.body); - final encrypted = json2['sources']; - - if (encrypted == null) return null; - - final result = {}; - - final sources = json.decode(decryptAESCryptoJS(encrypted, key)); - if (sources == null) return null; - - result['sources'] = sources; - return result; - } - - MPages animeElementM(String res) { - List animeList = []; - final doc = parseHtml(res); - final animeElements = doc.select('.flw-item'); - for (var element in animeElements) { - final linkElement = element.selectFirst('.film-detail h3 a'); - final imageElement = element.selectFirst('.film-poster img'); - MManga anime = MManga(); - anime.name = linkElement.attr('data-jname') ?? linkElement.text; - anime.imageUrl = imageElement.getSrc ?? imageElement.attr('data-src'); - anime.link = linkElement.getHref; - animeList.add(anime); - } - final nextPageElement = doc.selectFirst('li.page-item a[title="Next"]'); - return MPages(animeList, nextPageElement != null); - } - - String ajaxRoute(String baseUrl) { - if (baseUrl == "https://kaido.to") { - return ""; - } - return "/v2"; - } - - List yearList = [ - for (var i = 1917; i < 2026; i++) - SelectFilterOption(i.toString(), i.toString()), - SelectFilterOption("All", ""), - ]; - - @override - List getFilterList() { - return [ - SelectFilter("TypeFilter", "Type", 0, [ - SelectFilterOption("All", ""), - SelectFilterOption("Movie", "1"), - SelectFilterOption("TV", "2"), - SelectFilterOption("OVA", "3"), - SelectFilterOption("ONA", "4"), - SelectFilterOption("Special", "5"), - SelectFilterOption("Music", "6"), - ]), - SelectFilter("StatusFilter", "Status", 0, [ - SelectFilterOption("All", ""), - SelectFilterOption("Finished Airing", "1"), - SelectFilterOption("Currently Airing", "2"), - SelectFilterOption("Not yet aired", "3"), - ]), - SelectFilter("RatedFilter", "Rated", 0, [ - SelectFilterOption("All", ""), - SelectFilterOption("G", "1"), - SelectFilterOption("PG", "2"), - SelectFilterOption("PG-13", "3"), - SelectFilterOption("R", "4"), - SelectFilterOption("R+", "5"), - SelectFilterOption("Rx", "6"), - ]), - SelectFilter("ScoreFilter", "Score", 0, [ - SelectFilterOption("All", ""), - SelectFilterOption("(1) Appalling", "1"), - SelectFilterOption("(2) Horrible", "2"), - SelectFilterOption("(3) Very Bad", "3"), - SelectFilterOption("(4) Bad", "4"), - SelectFilterOption("(5) Average", "5"), - SelectFilterOption("(6) Fine", "6"), - SelectFilterOption("(7) Good", "7"), - SelectFilterOption("(8) Very Good", "8"), - SelectFilterOption("(9) Great", "9"), - SelectFilterOption("(10) Masterpiece", "10"), - ]), - SelectFilter("SeasonFilter", "Season", 0, [ - SelectFilterOption("All", ""), - SelectFilterOption("Spring", "1"), - SelectFilterOption("Summer", "2"), - SelectFilterOption("Fall", "3"), - SelectFilterOption("Winter", "4"), - ]), - SelectFilter("LanguageFilter", "Language", 0, [ - SelectFilterOption("All", ""), - SelectFilterOption("SUB", "1"), - SelectFilterOption("DUB", "2"), - SelectFilterOption("SUB & DUB", "3"), - ]), - SelectFilter("SortFilter", "Sort by", 0, [ - SelectFilterOption("All", ""), - SelectFilterOption("Default", "default"), - SelectFilterOption("Recently Added", "recently_added"), - SelectFilterOption("Recently Updated", "recently_updated"), - SelectFilterOption("Score", "score"), - SelectFilterOption("Name A-Z", "name_az"), - SelectFilterOption("Released Date", "released_date"), - SelectFilterOption("Most Watched", "most_watched"), - ]), - SelectFilter( - "StartYearFilter", - "Start year", - 0, - yearList.reversed.toList(), - ), - SelectFilter("StartMonthFilter", "Start month", 0, [ - SelectFilterOption("All", ""), - for (var i = 1; i < 13; i++) - SelectFilterOption(i.toString(), i.toString()), - ]), - SelectFilter("StartDayFilter", "Start day", 0, [ - SelectFilterOption("All", ""), - for (var i = 1; i < 32; i++) - SelectFilterOption(i.toString(), i.toString()), - ]), - SelectFilter("EndYearFilter", "End year", 0, yearList.reversed.toList()), - SelectFilter("EndmonthFilter", "End month", 0, [ - SelectFilterOption("All", ""), - for (var i = 1; i < 32; i++) - SelectFilterOption(i.toString(), i.toString()), - ]), - SelectFilter("EndDayFilter", "End day", 0, [ - SelectFilterOption("All", ""), - for (var i = 1; i < 32; i++) - SelectFilterOption(i.toString(), i.toString()), - ]), - GroupFilter("GenreFilter", "Genre", [ - CheckBoxFilter("Action", "1"), - CheckBoxFilter("Adventure", "2"), - CheckBoxFilter("Cars", "3"), - CheckBoxFilter("Comedy", "4"), - CheckBoxFilter("Dementia", "5"), - CheckBoxFilter("Demons", "6"), - CheckBoxFilter("Drama", "8"), - CheckBoxFilter("Ecchi", "9"), - CheckBoxFilter("Fantasy", "10"), - CheckBoxFilter("Game", "11"), - CheckBoxFilter("Harem", "35"), - CheckBoxFilter("Historical", "13"), - CheckBoxFilter("Horror", "14"), - CheckBoxFilter("Isekai", "44"), - CheckBoxFilter("Josei", "43"), - CheckBoxFilter("Kids", "15"), - CheckBoxFilter("Magic", "16"), - CheckBoxFilter("Martial Arts", "17"), - CheckBoxFilter("Mecha", "18"), - CheckBoxFilter("Military", "38"), - CheckBoxFilter("Music", "19"), - CheckBoxFilter("Mystery", "7"), - CheckBoxFilter("Parody", "20"), - CheckBoxFilter("Police", "39"), - CheckBoxFilter("Psychological", "40"), - CheckBoxFilter("Romance", "22"), - CheckBoxFilter("Samurai", "21"), - CheckBoxFilter("School", "23"), - CheckBoxFilter("Sci-Fi", "24"), - CheckBoxFilter("Seinen", "42"), - CheckBoxFilter("Shoujo", "25"), - CheckBoxFilter("Shoujo Ai", "26"), - CheckBoxFilter("Shounen", "27"), - CheckBoxFilter("Shounen Ai", "28"), - CheckBoxFilter("Slice of Life", "36"), - CheckBoxFilter("Space", "29"), - CheckBoxFilter("Sports", "30"), - CheckBoxFilter("Super Power", "31"), - CheckBoxFilter("Supernatural", "37"), - CheckBoxFilter("Thriller", "41"), - CheckBoxFilter("Vampire", "32"), - CheckBoxFilter("Yaoi", "33"), - CheckBoxFilter("Yuri", "34"), - ]), - ]; - } - - @override - List getSourcePreferences() { - return [ - ListPreference( - key: "preferred_quality", - title: "Preferred Quality", - summary: "", - valueIndex: 1, - entries: ["1080p", "720p", "480p", "360p"], - entryValues: ["1080", "720", "480", "360"], - ), - if (source.name == "HiAnime") - ListPreference( - key: "preferred_server2", - title: "Preferred server", - summary: "", - valueIndex: 0, - entries: ["HD-1", "HD-2", "HD-3", "StreamTape"], - entryValues: ["HD-1", "HD-2", "HD-3", "StreamTape"], - ), - if (source.name != "HiAnime") - ListPreference( - key: "preferred_server2", - title: "Preferred server", - summary: "", - valueIndex: 0, - entries: ["Vidstreaming", "VidCloud", "StreamTape"], - entryValues: ["Vidstreaming", "VidCloud", "StreamTape"], - ), - ListPreference( - key: "preferred_type1", - title: "Preferred Type", - summary: "", - valueIndex: 0, - entries: ["Sub", "Dub"], - entryValues: ["sub", "dub"], - ), - if (source.name != "HiAnime") - MultiSelectListPreference( - key: "hoster_selection2", - title: "Enable/Disable Hosts", - summary: "", - entries: ["Vidstreaming", "VidCloud", "StreamTape"], - entryValues: ["Vidstreaming", "VidCloud", "StreamTape"], - values: ["Vidstreaming", "VidCloud", "StreamTape"], - ), - if (source.name == "HiAnime") - MultiSelectListPreference( - key: "hoster_selection2", - title: "Enable/Disable Hosts", - summary: "", - entries: ["HD-1", "HD-2", "HD-3", "StreamTape"], - entryValues: ["HD-1", "HD-2", "HD-3", "StreamTape"], - values: ["HD-1", "HD-2", "HD-3", "StreamTape"], - ), - MultiSelectListPreference( - key: "type_selection_1", - title: "Enable/Disable Types", - summary: "", - entries: ["Sub", "Dub", "Raw"], - entryValues: ["sub", "dub", "raw"], - values: ["sub", "dub", "raw"], - ), - ]; - } - - List sortVideos(List videos, int sourceId) { - String quality = getPreferenceValue(sourceId, "preferred_quality"); - String server = getPreferenceValue(sourceId, "preferred_server2"); - String type = getPreferenceValue(sourceId, "preferred_type1"); - videos.sort((MVideo a, MVideo b) { - int qualityMatchA = 0; - - if (a.quality.contains(quality) && - a.quality.toLowerCase().contains(type.toLowerCase()) && - a.quality.toLowerCase().contains(server.toLowerCase())) { - qualityMatchA = 1; - } - int qualityMatchB = 0; - if (b.quality.contains(quality) && - b.quality.toLowerCase().contains(type.toLowerCase()) && - b.quality.toLowerCase().contains(server.toLowerCase())) { - qualityMatchB = 1; - } - if (qualityMatchA != qualityMatchB) { - return qualityMatchB - qualityMatchA; - } - - final regex = RegExp(r'(\d+)p'); - final matchA = regex.firstMatch(a.quality); - final matchB = regex.firstMatch(b.quality); - final int qualityNumA = int.tryParse(matchA?.group(1) ?? '0') ?? 0; - final int qualityNumB = int.tryParse(matchB?.group(1) ?? '0') ?? 0; - return qualityNumB - qualityNumA; - }); - return videos; - } - - List preferenceHosterSelection(int sourceId) { - return getPreferenceValue(sourceId, "hoster_selection2"); - } - - List preferenceTypeSelection(int sourceId) { - return getPreferenceValue(sourceId, "type_selection_1"); - } - - String ll(String url) { - if (url.contains("?")) { - return "&"; - } - return "?"; - } -} - -ZoroTheme main(MSource source) { - return ZoroTheme(source: source); -} diff --git a/dart/anime/src/all/animeworldindia/animeworldindia.dart b/dart/anime/src/all/animeworldindia/animeworldindia.dart deleted file mode 100644 index 8256bd54..00000000 --- a/dart/anime/src/all/animeworldindia/animeworldindia.dart +++ /dev/null @@ -1,430 +0,0 @@ -import 'package:mangayomi/bridge_lib.dart'; -import 'dart:convert'; - -class AnimeWorldIndia extends MProvider { - AnimeWorldIndia({required this.source}); - - MSource source; - - final Client client = Client(); - - @override - Future getPopular(int page) async { - final res = - (await client.get( - Uri.parse( - "${source.baseUrl}/advanced-search/page/$page/?s_lang=${source.lang}&s_orderby=viewed", - ), - )).body; - - return parseAnimeList(res); - } - - @override - Future getLatestUpdates(int page) async { - final res = - (await client.get( - Uri.parse( - "${source.baseUrl}/advanced-search/page/$page/?s_lang=${source.lang}&s_orderby=update", - ), - )).body; - - return parseAnimeList(res); - } - - @override - Future search(String query, int page, FilterList filterList) async { - final filters = filterList.filters; - String url = - "${source.baseUrl}/advanced-search/page/$page/?s_keyword=$query&s_lang=${source.lang}"; - for (var filter in filters) { - if (filter.type == "TypeFilter") { - final type = filter.values[filter.state].value; - url += "${ll(url)}s_type=$type"; - } else if (filter.type == "StatusFilter") { - final status = filter.values[filter.state].value; - url += "${ll(url)}s_status=$status"; - } else if (filter.type == "StyleFilter") { - final style = filter.values[filter.state].value; - url += "${ll(url)}s_sub_type=$style"; - } else if (filter.type == "YearFilter") { - final year = filter.values[filter.state].value; - url += "${ll(url)}s_year=$year"; - } else if (filter.type == "SortFilter") { - final sort = filter.values[filter.state].value; - url += "${ll(url)}s_orderby=$sort"; - } else if (filter.type == "GenresFilter") { - final genre = (filter.state as List).where((e) => e.state).toList(); - url += "${ll(url)}s_genre="; - if (genre.isNotEmpty) { - for (var st in genre) { - String value = st.value; - url += value.toLowerCase().replaceAll(" ", "-"); - if (genre.length > 1) { - url += "%2C"; - } - } - if (genre.length > 1) { - url = substringBeforeLast(url, '%2C'); - } - } - } - } - - final res = (await client.get(Uri.parse(url))).body; - return parseAnimeList(res); - } - - @override - Future getDetail(String url) async { - final res = (await client.get(Uri.parse(url))).body; - MManga anime = MManga(); - final document = parseHtml(res); - final isMovie = - document.xpath('//li/a[contains(text(),"Movie")]/text()').isNotEmpty; - if (isMovie) { - anime.status = MStatus.completed; - } else { - final eps = xpath( - res, - '//ul/li/a[contains(@href,"${source.baseUrl}/watch")]/text()', - ); - if (eps.isNotEmpty) { - final epParts = eps.first - .substring(3) - .replaceAll(" ", "") - .replaceAll("\n", "") - .split('/'); - if (epParts.length == 2) { - if (epParts[0].compareTo(epParts[1]) == 0) { - anime.status = MStatus.completed; - } else { - anime.status = MStatus.ongoing; - } - } - } - } - anime.description = document.selectFirst("div[data-synopsis]")?.text ?? ""; - anime.author = document - .xpath('//li[contains(text(),"Producers:")]/span/a/text()') - .join(', '); - anime.genre = document.xpath( - '//span[@class="leading-6"]/a[contains(@class,"border-opacity-30")]/text()', - ); - final seasonsJson = - json.decode( - substringBeforeLast( - substringBefore( - substringAfter(res, "var season_list = "), - "var season_label =", - ), - ";", - ), - ) - as List>; - bool isSingleSeason = seasonsJson.length == 1; - List? episodesList = []; - for (var i = 0; i < seasonsJson.length; i++) { - final seasonJson = seasonsJson[i]; - final seasonName = isSingleSeason ? "" : "Season ${i + 1}"; - final episodesJson = - (seasonJson["episodes"]["all"] as List>).reversed - .toList(); - for (var j = 0; j < episodesJson.length; j++) { - final episodeJson = episodesJson[j]; - final episodeTitle = episodeJson["metadata"]["title"] ?? ""; - String episodeName = ""; - if (isMovie) { - episodeName = "Movie"; - } else { - if (seasonName.isNotEmpty) { - episodeName = "$seasonName - "; - } - episodeName += "Episode ${j + 1} "; - if (episodeTitle.isNotEmpty) { - episodeName += "- $episodeTitle"; - } - } - MChapter episode = MChapter(); - episode.name = episodeName; - - episode.dateUpload = - "${int.parse(episodeJson["metadata"]["released"] ?? "0") * 1000}"; - episode.url = "/wp-json/kiranime/v1/episode?id=${episodeJson["id"]}"; - episodesList.add(episode); - } - } - - anime.chapters = episodesList.reversed.toList(); - return anime; - } - - @override - Future> getVideoList(String url) async { - final res = (await client.get(Uri.parse("${source.baseUrl}$url"))).body; - var resJson = substringBefore( - substringAfterLast(res, "\"players\":"), - ",\"noplayer\":", - ); - var streams = - (json.decode(resJson) as List>) - .where( - (e) => - (e["type"] == "stream" ? true : false) && - (e["url"] as String).isNotEmpty, - ) - .toList() - .where( - (e) => - language(source.lang).isEmpty || - language(source.lang) == e["language"] - ? true - : false, - ) - .toList(); - List videos = []; - for (var stream in streams) { - String videoUrl = stream["url"]; - final language = stream["language"]; - final video = await mystreamExtractor(videoUrl, language); - videos.addAll(video); - } - - return sortVideos(videos, source.id); - } - - MPages parseAnimeList(String res) { - List animeList = []; - final document = parseHtml(res); - - for (var element in document.select("div.col-span-1")) { - MManga anime = MManga(); - anime.name = - element.selectFirst("div.font-medium.line-clamp-2.mb-3").text; - anime.link = element.selectFirst("a").getHref; - anime.imageUrl = - "${source.baseUrl}${getUrlWithoutDomain(element.selectFirst("img").getSrc)}"; - animeList.add(anime); - } - final hasNextPage = - xpath( - res, - '//li/span[@class="page-numbers current"]/parent::li//following-sibling::li/a/@href', - ).isNotEmpty; - return MPages(animeList, hasNextPage); - } - - String language(String lang) { - final languages = { - "all": "", - "bn": "bengali", - "en": "english", - "hi": "hindi", - "ja": "japanese", - "ml": "malayalam", - "mr": "marathi", - "ta": "tamil", - "te": "telugu", - }; - return languages[lang] ?? ""; - } - - Future> mystreamExtractor(String url, String language) async { - List videos = []; - final res = (await client.get(Uri.parse(url))).body; - final streamCode = substringBefore( - substringAfter(substringAfter(res, "sniff("), ", \""), - '"', - ); - - final streamUrl = - "${substringBefore(url, "/watch")}/m3u8/$streamCode/master.txt?s=1&cache=1"; - final masterPlaylistRes = (await client.get(Uri.parse(streamUrl))).body; - - List audios = []; - for (var it in substringAfter( - masterPlaylistRes, - "#EXT-X-MEDIA:TYPE=AUDIO", - ).split("#EXT-X-MEDIA:TYPE=AUDIO")) { - final line = substringBefore( - substringAfter(it, "#EXT-X-MEDIA:TYPE=AUDIO"), - "\n", - ); - final audioUrl = substringBefore(substringAfter(line, "URI=\""), "\""); - MTrack audio = MTrack(); - audio - ..label = substringBefore(substringAfter(line, "NAME=\""), "\"") - ..file = audioUrl; - audios.add(audio); - } - - for (var it in substringAfter( - masterPlaylistRes, - "#EXT-X-STREAM-INF:", - ).split("#EXT-X-STREAM-INF:")) { - final quality = - "${substringBefore(substringBefore(substringAfter(substringAfter(it, "RESOLUTION="), "x"), ","), "\n")}p"; - - String videoUrl = substringBefore(substringAfter(it, "\n"), "\n"); - - MVideo video = MVideo(); - video - ..url = videoUrl - ..originalUrl = videoUrl - ..quality = "[$language] MyStream - $quality" - ..audios = audios; - videos.add(video); - } - return videos; - } - - @override - List getFilterList() { - return [ - SelectFilter("TypeFilter", "Type", 0, [ - SelectFilterOption("Any", "all"), - SelectFilterOption("TV", "tv"), - SelectFilterOption("Movie", "movies"), - ]), - SelectFilter("StatusFilter", "Status", 0, [ - SelectFilterOption("Any", "all"), - SelectFilterOption("Currently Airing", "airing"), - SelectFilterOption("Finished Airing", "completed"), - ]), - SelectFilter("StyleFilter", "Style", 0, [ - SelectFilterOption("Any", "all"), - SelectFilterOption("Anime", "anime"), - SelectFilterOption("Cartoon", "cartoon"), - ]), - SelectFilter("YearFilter", "Year", 0, [ - SelectFilterOption("Any", "all"), - SelectFilterOption("2024", "2024"), - SelectFilterOption("2023", "2023"), - SelectFilterOption("2022", "2022"), - SelectFilterOption("2021", "2021"), - SelectFilterOption("2020", "2020"), - SelectFilterOption("2019", "2019"), - SelectFilterOption("2018", "2018"), - SelectFilterOption("2017", "2017"), - SelectFilterOption("2016", "2016"), - SelectFilterOption("2015", "2015"), - SelectFilterOption("2014", "2014"), - SelectFilterOption("2013", "2013"), - SelectFilterOption("2012", "2012"), - SelectFilterOption("2011", "2011"), - SelectFilterOption("2010", "2010"), - SelectFilterOption("2009", "2009"), - SelectFilterOption("2008", "2008"), - SelectFilterOption("2007", "2007"), - SelectFilterOption("2006", "2006"), - SelectFilterOption("2005", "2005"), - SelectFilterOption("2004", "2004"), - SelectFilterOption("2003", "2003"), - SelectFilterOption("2002", "2002"), - SelectFilterOption("2001", "2001"), - SelectFilterOption("2000", "2000"), - SelectFilterOption("1999", "1999"), - SelectFilterOption("1998", "1998"), - SelectFilterOption("1997", "1997"), - SelectFilterOption("1996", "1996"), - SelectFilterOption("1995", "1995"), - SelectFilterOption("1994", "1994"), - SelectFilterOption("1993", "1993"), - SelectFilterOption("1992", "1992"), - SelectFilterOption("1991", "1991"), - SelectFilterOption("1990", "1990"), - ]), - SelectFilter("SortFilter", "Sort", 0, [ - SelectFilterOption("Default", "default"), - SelectFilterOption("Ascending", "title_a_z"), - SelectFilterOption("Descending", "title_z_a"), - SelectFilterOption("Updated", "update"), - SelectFilterOption("Published", "date"), - SelectFilterOption("Most Viewed", "viewed"), - SelectFilterOption("Favourite", "favorite"), - ]), - GroupFilter("GenresFilter", "Genres", [ - CheckBoxFilter("Action", "Action"), - CheckBoxFilter("Adult Cast", "Adult Cast"), - CheckBoxFilter("Adventure", "Adventure"), - CheckBoxFilter("Animation", "Animation"), - CheckBoxFilter("Comedy", "Comedy"), - CheckBoxFilter("Detective", "Detective"), - CheckBoxFilter("Drama", "Drama"), - CheckBoxFilter("Ecchi", "Ecchi"), - CheckBoxFilter("Family", "Family"), - CheckBoxFilter("Fantasy", "Fantasy"), - CheckBoxFilter("Isekai", "Isekai"), - CheckBoxFilter("Kids", "Kids"), - CheckBoxFilter("Martial Arts", "Martial Arts"), - CheckBoxFilter("Mecha", "Mecha"), - CheckBoxFilter("Military", "Military"), - CheckBoxFilter("Mystery", "Mystery"), - CheckBoxFilter("Otaku Culture", "Otaku Culture"), - CheckBoxFilter("Reality", "Reality"), - CheckBoxFilter("Romance", "Romance"), - CheckBoxFilter("School", "School"), - CheckBoxFilter("Sci-Fi", "Sci-Fi"), - CheckBoxFilter("Seinen", "Seinen"), - CheckBoxFilter("Shounen", "Shounen"), - CheckBoxFilter("Slice of Life", "Slice of Life"), - CheckBoxFilter("Sports", "Sports"), - CheckBoxFilter("Super Power", "Super Power"), - CheckBoxFilter("SuperHero", "SuperHero"), - CheckBoxFilter("Supernatural", "Supernatural"), - CheckBoxFilter("TV Movie", "TV Movie"), - ]), - ]; - } - - @override - List getSourcePreferences() { - return [ - ListPreference( - key: "preferred_quality", - title: "Preferred Quality", - summary: "", - valueIndex: 0, - entries: ["1080p", "720p", "480p", "360p", "240p"], - entryValues: ["1080", "720", "480", "360", "240"], - ), - ]; - } - - List sortVideos(List videos, int sourceId) { - String quality = getPreferenceValue(sourceId, "preferred_quality"); - videos.sort((MVideo a, MVideo b) { - int qualityMatchA = 0; - - if (a.quality.contains(quality)) { - qualityMatchA = 1; - } - int qualityMatchB = 0; - if (b.quality.contains(quality)) { - qualityMatchB = 1; - } - if (qualityMatchA != qualityMatchB) { - return qualityMatchB - qualityMatchA; - } - - final regex = RegExp(r'(\d+)p'); - final matchA = regex.firstMatch(a.quality); - final matchB = regex.firstMatch(b.quality); - final int qualityNumA = int.tryParse(matchA?.group(1) ?? '0') ?? 0; - final int qualityNumB = int.tryParse(matchB?.group(1) ?? '0') ?? 0; - return qualityNumB - qualityNumA; - }); - return videos; - } - - String ll(String url) { - if (url.contains("?")) { - return "&"; - } - return "?"; - } -} - -AnimeWorldIndia main(MSource source) { - return AnimeWorldIndia(source: source); -} diff --git a/dart/anime/src/all/animeworldindia/icon.png b/dart/anime/src/all/animeworldindia/icon.png deleted file mode 100644 index 0426e29dfb699517e03b740f2d6fce7ee3ac2d91..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7536 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 diff --git a/dart/anime/src/all/animeworldindia/sources.dart b/dart/anime/src/all/animeworldindia/sources.dart deleted file mode 100644 index 0840b4e2..00000000 --- a/dart/anime/src/all/animeworldindia/sources.dart +++ /dev/null @@ -1,37 +0,0 @@ -import '../../../../../model/source.dart'; - -const _animeworldindiaVersion = "0.0.35"; -const _animeworldindiaSourceCodeUrl = - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/src/all/animeworldindia/animeworldindia.dart"; - -String _iconUrl = - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/src/all/animeworldindia/icon.png"; - -List _languages = [ - "all", - "en", - "bn", - "hi", - "ja", - "ml", - "mr", - "ta", - "te", -]; - -List get animeworldindiaSourcesList => _animeworldindiaSourcesList; -List _animeworldindiaSourcesList = - _languages - .map( - (e) => Source( - name: 'AnimeWorld India', - baseUrl: "https://anime-world.in", - lang: e, - typeSource: "multiple", - iconUrl: _iconUrl, - version: _animeworldindiaVersion, - itemType: ItemType.anime, - sourceCodeUrl: _animeworldindiaSourceCodeUrl, - ), - ) - .toList(); diff --git a/dart/anime/src/all/nyaa/icon.png b/dart/anime/src/all/nyaa/icon.png deleted file mode 100644 index b57dba5f8a55647122a8b6f046ccc72e8177105a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3187 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 getPopular(int page) async { - final res = (await client.get( - Uri.parse( - "${getBaseUrl()}/?f=0&c=${getPreferenceValue(source.id, "preferred_categorie_page")}&q=&s=downloads&o=desc&p=$page", - ), - )).body; - return parseAnimeList(res); - } - - @override - Future getLatestUpdates(int page) async { - final res = (await client.get( - Uri.parse( - "${getBaseUrl()}/?f=0&c=${getPreferenceValue(source.id, "preferred_categorie_page")}&q=$page", - ), - )).body; - return parseAnimeList(res); - } - - @override - Future search(String query, int page, FilterList filterList) async { - final filters = filterList.filters; - String url = ""; - url = - "${getBaseUrl()}/?f=0&c=${getPreferenceValue(source.id, "preferred_categorie_page")}&q=${query.replaceAll(" ", "+")}&p=$page"; - for (var filter in filters) { - if (filter.type == "SortFilter") { - url += "${ll(url)}s=${filter.values[filter.state.index].value}"; - final asc = filter.state.ascending ? "&o=asc" : "&o=desc"; - url += "${ll(url)}$asc"; - } - } - final res = (await client.get(Uri.parse(url))).body; - return parseAnimeList(res); - } - - String extractPanelBody(MDocument document) { - final panelBody = document.selectFirst('.panel-body'); - if (panelBody == null) return ""; - - final rows = panelBody.select('.row'); - - final Map info = {}; - for (var row in rows) { - final labels = row.select('.col-md-1'); - for (var label in labels) { - final key = label.text.replaceAll(":", "").trim(); - final valueDiv = label.nextElementSibling; - if (valueDiv == null) continue; - - final links = valueDiv.select('a'); - String value; - if (links.isNotEmpty) { - value = links.map((a) => a.text.trim()).join(' - '); - } else { - value = valueDiv.text.trim(); - } - - info[key] = value; - } - } - - final buffer = StringBuffer(); - buffer.writeln("Torrent Info:\n"); - info.forEach((k, v) { - buffer.writeln("${k.padRight(11)}: $v"); - }); - if (getPreferenceValue(source.id, "torrent_description_visible")) { - buffer.writeln("\n\n"); - buffer.writeln("Torrent Description: \n"); - buffer.writeln( - document - .select("#torrent-description") - .map((e) => e.text.trim()) - .join("\n\n"), - ); - } - - return buffer.toString(); - } - - @override - Future getDetail(String url) async { - MManga anime = MManga(); - final res = (await client.get(Uri.parse(url))).body; - final document = parseHtml(res); - - anime.description = extractPanelBody(document); - - List chapters = []; - chapters.add( - MChapter( - name: "Torrent", - url: "${getBaseUrl()}/download/${substringAfterLast(url, '/')}.torrent", - ), - ); - anime.chapters = chapters; - - return anime; - } - - @override - Future> getVideoList(String url) async { - var video = MVideo(); - video - ..url = url - ..originalUrl = url - ..quality = ""; - return [video]; - } - - @override - List getFilterList() { - return [ - SortFilter("SortFilter", "Sort by", SortState(0, true), [ - SelectFilterOption("None", ""), - SelectFilterOption("Size", "size"), - SelectFilterOption("Date", "id"), - SelectFilterOption("Seeders", "seeders"), - SelectFilterOption("Leechers", "leechers"), - SelectFilterOption("Download", "downloads"), - ]), - ]; - } - - @override - List getSourcePreferences() { - return [ - ListPreference( - key: "preferred_categorie_page", - title: "Preferred categorie page", - summary: "", - valueIndex: 0, - entries: ["Anime", "Live Action"], - entryValues: ["1_0", "4_0"], - ), - SwitchPreferenceCompat( - key: "torrent_description_visible", - title: "Display Torrent Description", - summary: - "Enable to show the full torrent description in the details view.", - value: false, - ), - EditTextPreference( - key: "domain_url", - title: 'Edit URL', - summary: "", - value: source.baseUrl, - dialogTitle: "URL", - dialogMessage: "", - ), - ]; - } - - String getBaseUrl() { - final baseUrl = getPreferenceValue(source.id, "domain_url")?.trim(); - - if (baseUrl == null || baseUrl.isEmpty) { - return source.baseUrl; - } - - return baseUrl.endsWith("/") - ? baseUrl.substring(0, baseUrl.length - 1) - : baseUrl; - } - - MPages parseAnimeList(String res) { - List animeList = []; - final document = parseHtml(res); - - final values = document.select( - "body > div > div.table-responsive > table > tbody > tr", - ); - for (var value in values) { - MManga anime = MManga(); - anime.imageUrl = - "${getBaseUrl()}${getUrlWithoutDomain(value.selectFirst("td:nth-child(1) > a > img").getSrc)}"; - MElement firstElement = value - .select("td > a") - .where( - (MElement e) => - e.outerHtml.contains("/view/") && - !e.outerHtml.contains("#comments"), - ) - .toList() - .first; - anime.link = - "${getBaseUrl()}${getUrlWithoutDomain(firstElement.getHref)}"; - anime.name = firstElement.attr("title"); - animeList.add(anime); - } - - final hasNextPage = xpath( - res, - '//ul[@class="pagination"]/li[contains(text(),"»")]/a/@href', - ).isNotEmpty; - return MPages(animeList, hasNextPage); - } - - String ll(String url) { - if (url.contains("?")) { - return "&"; - } - return "?"; - } -} - -Nyaa main(MSource source) { - return Nyaa(source: source); -} diff --git a/dart/anime/src/all/nyaa/source.dart b/dart/anime/src/all/nyaa/source.dart deleted file mode 100644 index 59168bfe..00000000 --- a/dart/anime/src/all/nyaa/source.dart +++ /dev/null @@ -1,20 +0,0 @@ -import '../../../../../model/source.dart'; - -const _nyaaVersion = "0.0.4"; -const _nyaaSourceCodeUrl = - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/src/all/nyaa/nyaa.dart"; - -String _iconUrl = - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/src/all/nyaa/icon.png"; - -Source get nyaaSource => _nyaaSource; -Source _nyaaSource = Source( - name: 'Nyaa', - baseUrl: "https://nyaa.si", - lang: "all", - typeSource: "torrent", - iconUrl: _iconUrl, - version: _nyaaVersion, - itemType: ItemType.anime, - sourceCodeUrl: _nyaaSourceCodeUrl, -); diff --git a/dart/anime/src/ar/okanime/icon.png b/dart/anime/src/ar/okanime/icon.png deleted file mode 100644 index 6057076dc1e1a427fe1da1b1d3c159a3ff0d78e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5358 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 M07*qoM6N<$g8Y getPopular(int page) async { - final res = (await client.get(Uri.parse(source.baseUrl))).body; - List animeList = []; - String path = - '//div[@class="section" and contains(text(),"افضل انميات")]/div[@class="section-content"]/div/div/div[contains(@class,"anime-card")]'; - final urls = xpath(res, '$path/div[@class="anime-title")]/h4/a/@href'); - final names = xpath(res, '$path/div[@class="anime-title")]/h4/a/text()'); - final images = xpath(res, '$path/div[@class="anime-image")]/img/@src'); - - for (var i = 0; i < names.length; i++) { - MManga anime = MManga(); - anime.name = names[i]; - anime.imageUrl = images[i]; - anime.link = urls[i]; - animeList.add(anime); - } - return MPages(animeList, false); - } - - @override - Future getLatestUpdates(int page) async { - final res = - (await client.get( - Uri.parse("${source.baseUrl}/espisode-list?page=$page"), - )).body; - List animeList = []; - String path = '//*[contains(@class,"anime-card")]'; - final urls = xpath(res, '$path/div[@class="anime-title")]/h4/a/@href'); - final names = xpath(res, '$path/div[@class="anime-title")]/h4/a/text()'); - final images = xpath(res, '$path/div[@class="episode-image")]/img/@src'); - - for (var i = 0; i < names.length; i++) { - MManga anime = MManga(); - anime.name = names[i]; - anime.imageUrl = images[i]; - anime.link = urls[i]; - animeList.add(anime); - } - final nextPage = xpath( - res, - '//li[@class="page-item"]/a[@rel="next"]/@href', - ); - return MPages(animeList, nextPage.isNotEmpty); - } - - @override - Future search(String query, int page, FilterList filterList) async { - String url = "${source.baseUrl}/search/?s=$query"; - if (page > 1) { - url += "&page=$page"; - } - - final res = (await client.get(Uri.parse(url))).body; - - List animeList = []; - String path = '//*[contains(@class,"anime-card")]'; - final urls = xpath(res, '$path/div[@class="anime-title")]/h4/a/@href'); - final names = xpath(res, '$path/div[@class="anime-title")]/h4/a/text()'); - final images = xpath(res, '$path/div[@class="anime-image")]/img/@src'); - - for (var i = 0; i < names.length; i++) { - MManga anime = MManga(); - anime.name = names[i]; - anime.imageUrl = images[i]; - anime.link = urls[i]; - animeList.add(anime); - } - final nextPage = xpath( - res, - '//li[@class="page-item"]/a[@rel="next"]/@href', - ); - return MPages(animeList, nextPage.isNotEmpty); - } - - @override - Future getDetail(String url) async { - final statusList = [ - {"يعرض الان": 0, "مكتمل": 1}, - ]; - final res = (await client.get(Uri.parse(url))).body; - MManga anime = MManga(); - final status = xpath( - res, - '//*[@class="full-list-info" and contains(text(),"حالة الأنمي")]/small/a/text()', - ); - if (status.isNotEmpty) { - anime.status = parseStatus(status.first, statusList); - } - anime.description = xpath(res, '//*[@class="review-content"]/text()').first; - - anime.genre = xpath(res, '//*[@class="review-author-info"]/a/text()'); - final epUrls = - xpath( - res, - '//*[contains(@class,"anime-card")]/div[@class="anime-title")]/h5/a/@href', - ).reversed.toList(); - final names = - xpath( - res, - '//*[contains(@class,"anime-card")]/div[@class="anime-title")]/h5/a/text()', - ).reversed.toList(); - - List? episodesList = []; - for (var i = 0; i < epUrls.length; i++) { - MChapter episode = MChapter(); - episode.name = names[i]; - episode.url = epUrls[i]; - episodesList.add(episode); - } - - anime.chapters = episodesList; - return anime; - } - - @override - Future> getVideoList(String url) async { - final res = (await client.get(Uri.parse(url))).body; - final urls = xpath(res, '//*[@id="streamlinks"]/a/@data-src'); - final qualities = xpath(res, '//*[@id="streamlinks"]/a/span/text()'); - final hosterSelection = preferenceHosterSelection(source.id); - List videos = []; - for (var i = 0; i < urls.length; i++) { - final url = urls[i]; - final quality = getQuality(qualities[i]); - List a = []; - - if (url.contains("https://doo") && hosterSelection.contains("Dood")) { - a = await doodExtractor(url, "DoodStream - $quality"); - } else if (url.contains("mp4upload") && - hosterSelection.contains("Mp4upload")) { - a = await mp4UploadExtractor(url, null, "", ""); - } else if (url.contains("ok.ru") && hosterSelection.contains("Okru")) { - a = await okruExtractor(url); - } else if (url.contains("voe.sx") && hosterSelection.contains("Voe")) { - a = await voeExtractor(url, "VoeSX $quality"); - } else if (containsVidBom(url) && hosterSelection.contains("VidBom")) { - a = await vidBomExtractor(url); - } - videos.addAll(a); - } - return sortVideos(videos, source.id); - } - - @override - List getSourcePreferences() { - return [ - ListPreference( - key: "preferred_quality", - title: "Preferred Quality", - summary: "", - valueIndex: 1, - entries: ["1080p", "720p", "480p", "360p"], - entryValues: ["1080", "720", "480", "360"], - ), - MultiSelectListPreference( - key: "hoster_selection", - title: "Enable/Disable Hosts", - summary: "", - entries: ["Dood", "Voe", "Mp4upload", "VidBom", "Okru"], - entryValues: ["Dood", "Voe", "Mp4upload", "VidBom", "Okru"], - values: ["Dood", "Voe", "Mp4upload", "VidBom", "Okru"], - ), - ]; - } - - List sortVideos(List videos, int sourceId) { - String quality = getPreferenceValue(sourceId, "preferred_quality"); - - videos.sort((MVideo a, MVideo b) { - int qualityMatchA = 0; - if (a.quality.contains(quality)) { - qualityMatchA = 1; - } - int qualityMatchB = 0; - if (b.quality.contains(quality)) { - qualityMatchB = 1; - } - if (qualityMatchA != qualityMatchB) { - return qualityMatchB - qualityMatchA; - } - - final regex = RegExp(r'(\d+)p'); - final matchA = regex.firstMatch(a.quality); - final matchB = regex.firstMatch(b.quality); - final int qualityNumA = int.tryParse(matchA?.group(1) ?? '0') ?? 0; - final int qualityNumB = int.tryParse(matchB?.group(1) ?? '0') ?? 0; - return qualityNumB - qualityNumA; - }); - - return videos; - } - - List preferenceHosterSelection(int sourceId) { - return getPreferenceValue(sourceId, "hoster_selection"); - } - - String getQuality(String quality) { - quality = quality.replaceAll(" ", ""); - if (quality == "HD") { - return "720p"; - } else if (quality == "FHD") { - return "1080p"; - } else if (quality == "SD") { - return "480p"; - } - return "240p"; - } - - bool containsVidBom(String url) { - url = url; - final list = ["vidbam", "vadbam", "vidbom", "vidbm"]; - for (var n in list) { - if (url.contains(n)) { - return true; - } - } - return false; - } -} - -OkAnime main(MSource source) { - return OkAnime(source: source); -} diff --git a/dart/anime/src/ar/okanime/source.dart b/dart/anime/src/ar/okanime/source.dart deleted file mode 100644 index 1587a4da..00000000 --- a/dart/anime/src/ar/okanime/source.dart +++ /dev/null @@ -1,17 +0,0 @@ -import '../../../../../model/source.dart'; - -Source get okanimeSource => _okanimeSource; -const _okanimeVersion = "0.0.6"; -const _okanimeSourceCodeUrl = - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/src/ar/okanime/okanime.dart"; -Source _okanimeSource = Source( - name: "Okanime", - baseUrl: "https://www.okanime.xyz", - lang: "ar", - typeSource: "single", - iconUrl: - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/src/ar/okanime/icon.png", - sourceCodeUrl: _okanimeSourceCodeUrl, - version: _okanimeVersion, - itemType: ItemType.anime, -); diff --git a/dart/anime/src/de/animetoast/animetoast.dart b/dart/anime/src/de/animetoast/animetoast.dart deleted file mode 100644 index 6df66300..00000000 --- a/dart/anime/src/de/animetoast/animetoast.dart +++ /dev/null @@ -1,250 +0,0 @@ -import 'package:mangayomi/bridge_lib.dart'; - -class AnimeToast extends MProvider { - AnimeToast({required this.source}); - - MSource source; - - final Client client = Client(); - - @override - bool get supportsLatest => false; - - @override - String get baseUrl => source.baseUrl; - - @override - Future getPopular(int page) async { - final res = (await client.get(Uri.parse(baseUrl))).body; - final document = parseHtml(res); - final elements = document.select("div.row div.col-md-4 div.video-item"); - List animeList = []; - for (var element in elements) { - MManga anime = MManga(); - anime.name = element.selectFirst("div.item-thumbnail a").attr("title"); - anime.link = getUrlWithoutDomain( - element.selectFirst("div.item-thumbnail a").attr("href"), - ); - anime.imageUrl = element - .selectFirst("div.item-thumbnail a img") - .attr("src"); - animeList.add(anime); - } - return MPages(animeList, false); - } - - @override - Future search(String query, int page, FilterList filterList) async { - final res = - (await client.get(Uri.parse("$baseUrl/page/$page/?s=$query"))).body; - final document = parseHtml(res); - final elements = document.select("div.item-thumbnail a[href]"); - List animeList = []; - for (var element in elements) { - MManga anime = MManga(); - anime.name = element.attr("title"); - anime.link = getUrlWithoutDomain(element.attr("href")); - anime.imageUrl = element.selectFirst("a img").attr("src"); - animeList.add(anime); - } - return MPages( - animeList, - document.selectFirst("li.next a")?.attr("href") != null, - ); - } - - @override - Future getDetail(String url) async { - MManga anime = MManga(); - final res = (await client.get(Uri.parse("$baseUrl$url"))).body; - final document = parseHtml(res); - anime.imageUrl = document.selectFirst(".item-content p img").attr("src"); - anime.genre = - (document.xpathFirst('//p[contains(text(),"Genre:")]/text()') ?? "") - .replaceAll("Genre:", "") - .split(","); - anime.description = document.selectFirst("div.item-content div + p").text; - final categoryTag = document.xpath('//*[@rel="category tag"]/text()'); - if (categoryTag.isNotEmpty) { - if (categoryTag.contains("Airing")) { - anime.status = MStatus.ongoing; - } else { - anime.status = MStatus.completed; - } - } - List? episodesList = []; - if (categoryTag.contains("Serie")) { - List elements = []; - if (document.selectFirst("#multi_link_tab0")?.attr("id") != null) { - elements = document.select("#multi_link_tab0"); - } else { - elements = document.select("#multi_link_tab1"); - } - - for (var element in elements) { - final episodeElement = element.selectFirst("a"); - final epT = episodeElement.text; - if (epT.contains(":") || epT.contains("-")) { - final url = episodeElement.attr("href"); - final document = parseHtml((await client.get(Uri.parse(url))).body); - final nUrl = document.selectFirst("#player-embed a").attr("href"); - final nDoc = parseHtml((await client.get(Uri.parse(nUrl))).body); - final nEpEl = nDoc.select("div.tab-pane a"); - for (var epElement in nEpEl) { - MChapter ep = MChapter(); - ep.name = epElement.text; - ep.url = getUrlWithoutDomain(epElement.attr("href")); - episodesList.add(ep); - } - } else { - final episodeElements = element.select("a"); - for (var epElement in episodeElements) { - MChapter ep = MChapter(); - ep.name = epElement.text; - ep.url = getUrlWithoutDomain(epElement.attr("href")); - episodesList.add(ep); - } - } - } - } else { - MChapter ep = MChapter(); - ep.name = document.selectFirst("h1.light-title")?.text ?? "Film"; - ep.url = getUrlWithoutDomain( - document.selectFirst("link[rel=canonical]").attr("href"), - ); - episodesList.add(ep); - } - anime.chapters = episodesList.reversed.toList(); - return anime; - } - - List preferenceHosterSelection() { - return getPreferenceValue(source.id, "hoster_selection"); - } - - @override - Future> getVideoList(String url) async { - final res = (await client.get(Uri.parse("$baseUrl$url"))).body; - final document = parseHtml(res); - final fEp = document.selectFirst("div.tab-pane"); - List videos = []; - List ep = []; - int epcu = 100; - - if (fEp.text.contains(":") || fEp.text.contains("-")) { - final tx = document.select("div.tab-pane"); - - for (var e in tx) { - final sUrl = e.selectFirst("a").attr("href"); - final doc = parseHtml((await client.get(Uri.parse(sUrl))).body); - final nUrl = doc.selectFirst("#player-embed a").attr("href"); - final nDoc = parseHtml((await client.get(Uri.parse(nUrl))).body); - epcu = - int.tryParse( - substringAfter( - document.selectFirst("div.tab-pane a.current-link")?.text ?? "", - "Ep.", - ), - ) ?? - 100; - ep = nDoc.select("div.tab-pane a"); - } - } else { - epcu = - int.tryParse( - substringAfter( - document.selectFirst("div.tab-pane a.current-link")?.text ?? "", - "Ep.", - ), - ) ?? - 100; - ep = document.select("div.tab-pane a"); - } - final hosterSelection = preferenceHosterSelection(); - for (var e in ep) { - if (int.tryParse(substringAfter(e.text, "Ep.")) == epcu) { - final epUrl = e.attr("href"); - final newdoc = parseHtml((await client.get(Uri.parse(epUrl))).body); - final elements = newdoc.select("#player-embed"); - for (var element in elements) { - final link = element.selectFirst("a").getHref ?? ""; - if (link.contains("https://voe.sx") && - hosterSelection.contains("voe")) { - videos.addAll(await voeExtractor(link, "Voe")); - } - } - for (var element in elements) { - List a = []; - final link = element.selectFirst("iframe").getSrc ?? ""; - if ((link.contains("https://dood") || - link.contains("https://ds2play") || - link.contains("https://d0")) && - hosterSelection.contains("dood")) { - a = await doodExtractor(link, "DoodStream"); - } else if (link.contains("filemoon") && - hosterSelection.contains("filemoon")) { - a = await filemoonExtractor(link, "", ""); - } else if (link.contains("mp4upload") && - hosterSelection.contains("mp4upload")) { - a = await mp4UploadExtractor(url, null, "", ""); - } - videos.addAll(a); - } - } - } - return sortVideos(videos); - } - - List sortVideos(List videos) { - String server = getPreferenceValue(source.id, "preferred_hoster"); - - videos.sort((MVideo a, MVideo b) { - int qualityMatchA = 0; - if (a.quality.toLowerCase().contains(server)) { - qualityMatchA = 1; - } - int qualityMatchB = 0; - if (b.quality.toLowerCase().contains(server)) { - qualityMatchB = 1; - } - if (qualityMatchA != qualityMatchB) { - return qualityMatchB - qualityMatchA; - } - - final regex = RegExp(r'(\d+)p'); - final matchA = regex.firstMatch(a.quality); - final matchB = regex.firstMatch(b.quality); - final int qualityNumA = int.tryParse(matchA?.group(1) ?? '0') ?? 0; - final int qualityNumB = int.tryParse(matchB?.group(1) ?? '0') ?? 0; - return qualityNumB - qualityNumA; - }); - - return videos; - } - - @override - List getSourcePreferences() { - return [ - ListPreference( - key: "preferred_hoster", - title: "Standard-Hoster", - summary: "", - valueIndex: 0, - entries: ["Voe", "DoodStream", "Filemoon", "Mp4upload"], - entryValues: ["voe", "doodStream", "filemoon", "mp4upload"], - ), - MultiSelectListPreference( - key: "hoster_selection", - title: "Hoster auswählen", - summary: "", - entries: ["Voe", "DoodStream", "Filemoon", "Mp4upload"], - entryValues: ["voe", "dood", "filemoon", "mp4upload"], - values: ["voe", "dood", "filemoon", "mp4upload"], - ), - ]; - } -} - -AnimeToast main(MSource source) { - return AnimeToast(source: source); -} diff --git a/dart/anime/src/de/animetoast/icon.png b/dart/anime/src/de/animetoast/icon.png deleted file mode 100644 index 172ddf3b39ffbf9a567165659797927a0715c81e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5171 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 _animetoast; -const _animetoastVersion = "0.0.25"; -const _animetoastCodeUrl = - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/src/de/animetoast/animetoast.dart"; -Source _animetoast = Source( - name: "AnimeToast", - baseUrl: "https://animetoast.cc", - lang: "de", - typeSource: "single", - iconUrl: - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/src/de/animetoast/icon.png", - sourceCodeUrl: _animetoastCodeUrl, - version: _animetoastVersion, - itemType: ItemType.anime, -); diff --git a/dart/anime/src/en/animepahe/animepahe.dart b/dart/anime/src/en/animepahe/animepahe.dart deleted file mode 100644 index 71d6ea23..00000000 --- a/dart/anime/src/en/animepahe/animepahe.dart +++ /dev/null @@ -1,415 +0,0 @@ -import 'package:mangayomi/bridge_lib.dart'; -import 'dart:convert'; -import 'dart:math'; - -class AnimePahe extends MProvider { - AnimePahe(this.source); - - final MSource source; - - final Client client = Client(); - - @override - String get baseUrl => getPreferenceValue(source.id, "preferred_domain"); - - @override - Map get headers => {'cookie': '__ddg1_=;__ddg2_=;'}; - - @override - Future getPopular(int page) async { - return await getLatestUpdates(page); - } - - @override - Future getLatestUpdates(int page) async { - final res = (await client.get( - Uri.parse("$baseUrl/api?m=airing&page=$page"), - headers: headers, - )).body; - final jsonResult = json.decode(res); - final hasNextPage = jsonResult["current_page"] < jsonResult["last_page"]; - List animeList = []; - for (var item in jsonResult["data"]) { - MManga anime = MManga(); - anime.name = item["anime_title"]; - anime.imageUrl = item["snapshot"]; - anime.link = "/anime/?anime_id=${item["id"]}&name=${item["anime_title"]}"; - anime.artist = item["fansub"]; - animeList.add(anime); - } - return MPages(animeList, hasNextPage); - } - - @override - Future search(String query, int page, FilterList filterList) async { - final res = (await client.get( - Uri.parse("$baseUrl/api?m=search&l=8&q=$query"), - headers: headers, - )).body; - final jsonResult = json.decode(res); - List animeList = []; - for (var item in jsonResult["data"]) { - MManga anime = MManga(); - anime.name = item["title"]; - anime.imageUrl = item["poster"]; - anime.link = "/anime/?anime_id=${item["id"]}&name=${item["title"]}"; - animeList.add(anime); - } - return MPages(animeList, false); - } - - @override - Future getDetail(String url) async { - final statusList = [ - {"Currently Airing": 0, "Finished Airing": 1}, - ]; - MManga anime = MManga(); - final id = substringBefore(substringAfterLast(url, "?anime_id="), "&name="); - final name = substringAfterLast(url, "&name="); - final session = await getSession(name, id); - final res = (await client.get( - Uri.parse("$baseUrl/anime/$session?anime_id=$id"), - headers: headers, - )).body; - final document = parseHtml(res); - final status = - (document.xpathFirst('//div/p[contains(text(),"Status:")]/text()') ?? - "") - .replaceAll("Status:\n", "") - .trim(); - anime.status = parseStatus(status, statusList); - - anime.name = document.selectFirst("div.title-wrapper > h1 > span").text; - anime.author = - (document.xpathFirst('//div/p[contains(text(),"Studio:")]/text()') ?? - "") - .replaceAll("Studio:\n", "") - .trim(); - anime.imageUrl = document.selectFirst("div.anime-poster a").attr("href"); - anime.genre = xpath( - res, - '//*[contains(@class,"anime-genre")]/ul/li/text()', - ); - final synonyms = - (document.xpathFirst('//div/p[contains(text(),"Synonyms:")]/text()') ?? - "") - .replaceAll("Synonyms:\n", "") - .trim(); - anime.description = document.selectFirst("div.anime-summary").text; - if (synonyms.isNotEmpty) { - anime.description += "\n\n$synonyms"; - } - final epUrl = "$baseUrl/api?m=release&id=$session&sort=episode_desc&page=1"; - final resEp = (await client.get(Uri.parse(epUrl), headers: headers)).body; - final episodes = await recursivePages(epUrl, resEp, session); - - anime.chapters = episodes; - return anime; - } - - Future> recursivePages( - String url, - String res, - String session, - ) async { - final jsonResult = json.decode(res); - final page = jsonResult["current_page"]; - final hasNextPage = page < jsonResult["last_page"]; - List animeList = []; - for (var item in jsonResult["data"]) { - MChapter episode = MChapter(); - episode.name = "Episode ${item["episode"]}"; - episode.url = "/play/$session/${item["session"]}"; - episode.dateUpload = parseDates( - [item["created_at"]], - "yyyy-MM-dd HH:mm:ss", - "en", - )[0]; - animeList.add(episode); - } - if (hasNextPage) { - final newUrl = "${substringBeforeLast(url, "&page=")}&page=${page + 1}"; - final newRes = (await client.get( - Uri.parse(newUrl), - headers: headers, - )).body; - animeList.addAll(await recursivePages(newUrl, newRes, session)); - } - return animeList; - } - - Future getSession(String title, String animeId) async { - final noRedirect = Client( - source, - json.encode({"followRedirects": false, "useDartHttpClient": true}), - ); - - final res = await noRedirect.get( - Uri.parse("$baseUrl/a/$animeId"), - headers: headers, - ); - - final location = - "https://${substringAfterLast(getMapValue(json.encode(res.headers), "location"), "https://")}"; - - if (location == '$baseUrl/anime') { - final res = (await client.get( - Uri.parse("$baseUrl/api?m=search&q=$title"), - headers: headers, - )).body; - return substringBefore( - substringAfter( - substringAfter(res, "\"id\":$animeId"), - "\"session\":\"", - ), - "\"", - ); - } - return substringAfterLast(location, '/'); - } - - @override - Future> getVideoList(String url) async { - //by default we use rhttp package but it does not support `followRedirects` - //so setting `useDartHttpClient` to true allows us to use a Dart http package that supports `followRedirects` - final client = Client(source, json.encode({"useDartHttpClient": true})); - final res = (await client.get(Uri.parse("$baseUrl$url"), headers: headers)); - final document = parseHtml(res.body); - final downloadLinks = document.select("div#pickDownload > a"); - final buttons = document.select("div#resolutionMenu > button"); - List videos = []; - - for (var i = 0; i < buttons.length; i++) { - final btn = buttons[i]; - final audio = btn.attr( - "data-audio", - ); // Get audio type (jpn/eng). Japanese or Dubbed. - final kwikLink = btn.attr("data-src"); - final quality = btn.text; - final paheWinLink = downloadLinks[i].attr("href"); - - if (getPreferenceValue(source.id, "preffered_link_type")) { - final noRedirectClient = Client( - source, - json.encode({"followRedirects": false, "useDartHttpClient": true}), - ); - final kwikHeaders = (await noRedirectClient.get( - Uri.parse("${paheWinLink}/i"), - )).headers; - final kwikUrl = - "https://${substringAfterLast(getMapValue(json.encode(kwikHeaders), "location"), "https://")}"; - final reskwik = (await client.get( - Uri.parse(kwikUrl), - headers: {"Referer": "https://kwik.cx/"}, - )); - final matches = RegExp( - r'\("(\S+)",\d+,"(\S+)",(\d+),(\d+)', - ).firstMatch(reskwik.body); - final token = decrypt( - matches!.group(1)!, - matches.group(2)!, - matches.group(3)!, - int.parse(matches.group(4)!), - ); - final url = RegExp(r'action="([^"]+)"').firstMatch(token)!.group(1)!; - final tok = RegExp(r'value="([^"]+)"').firstMatch(token)!.group(1)!; - var code = 419; - var tries = 0; - String location = ""; - - while (code != 302 && tries < 20) { - String cookie = getMapValue( - json.encode(res.request.headers), - "cookie", - ); - cookie += - "; ${getMapValue(json.encode(reskwik.headers), "set-cookie").replaceAll("path=/;", "")}"; - final resNo = - await Client( - source, - json.encode({ - "followRedirects": false, - "useDartHttpClient": true, - }), - ).post( - Uri.parse(url), - headers: { - "referer": reskwik.request.url.toString(), - "cookie": cookie, - "user-agent": getMapValue( - json.encode(res.request.headers), - "user-agent", - ), - }, - body: {"_token": tok}, - ); - code = resNo.statusCode; - tries++; - location = getMapValue(json.encode(resNo.headers), "location"); - } - if (tries > 19) { - throw ("Failed to extract the stream uri from kwik."); - } - MVideo video = MVideo(); - video - ..url = location - ..originalUrl = location - ..quality = quality; - videos.add(video); - } else { - final ress = (await client.get( - Uri.parse(kwikLink), - headers: {"Referer": "https://animepahe.com"}, - )); - final script = substringAfterLast( - xpath( - ress.body, - '//script[contains(text(),"eval(function")]/text()', - ).first, - "eval(function(", - ); - final videoUrl = substringBefore( - substringAfter( - unpackJsAndCombine("eval(function($script"), - "const source=\\'", - ), - "\\';", - ); - MVideo video = MVideo(); - video - ..url = videoUrl - ..originalUrl = videoUrl - ..quality = quality - ..headers = {"referer": "https://kwik.cx"}; - videos.add(video); - } - } - return sortVideos(videos); - } - - String getString(String ctn, int sep) { - int b = 10; - String cm = - "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ+/"; - final n = cm.substring(0, b); - double mx = 0; - for (var index = 0; index < ctn.length; index++) { - mx += - (int.tryParse(ctn[ctn.length - index - 1], radix: 10) ?? 0.0) - .toInt() * - (pow(sep, index)); - } - var m = ''; - while (mx > 0) { - m = n[(mx % b).toInt()] + m; - mx = (mx - (mx % b)) / b; - } - return m.isNotEmpty ? m : '0'; - } - - String decrypt(String fS, String key, String v1, int v2) { - var html = ""; - var i = 0; - final ld = int.parse(v1); - while (i < fS.length) { - var s = ""; - while (fS[i] != key[v2]) { - s += fS[i]; - i++; - } - for (var index = 0; index < key.length; index++) { - s = s.replaceAll(key[index], index.toString()); - } - html += String.fromCharCode(int.parse(getString(s, v2)) - ld); - i++; - } - - return html; - } - - List sortVideos(List videos) { - String quality = getPreferenceValue(source.id, "preferred_quality"); - String preferredAudio = getPreferenceValue( - source.id, - "preferred_audio", - ); // get user's audio preference - - videos.sort((MVideo a, MVideo b) { - // Prioritize audio first. - // Preferred Audio: Videos with matching preferred audio are ranked highest. - int audioMatchA = a.quality.contains(preferredAudio) ? 1 : 0; - int audioMatchB = b.quality.contains(preferredAudio) ? 1 : 0; - if (audioMatchA != audioMatchB) { - return audioMatchB - audioMatchA; - } - - // quality prioritized next - // Preferred Video Quality: If audio matches, videos with preferred video quality are ranked higher. - int qualityMatchA = 0; - if (a.quality.contains(quality)) { - qualityMatchA = 1; - } - int qualityMatchB = 0; - if (b.quality.contains(quality)) { - qualityMatchB = 1; - } - if (qualityMatchA != qualityMatchB) { - return qualityMatchB - qualityMatchA; - } - - final regex = RegExp(r'(\d+)p'); - final matchA = regex.firstMatch(a.quality); - final matchB = regex.firstMatch(b.quality); - final int qualityNumA = int.tryParse(matchA?.group(1) ?? '0') ?? 0; - final int qualityNumB = int.tryParse(matchB?.group(1) ?? '0') ?? 0; - return qualityNumB - qualityNumA; - }); - - return videos; - } - - @override - List getSourcePreferences() { - return [ - ListPreference( - key: "preferred_domain", - title: "Preferred domain", - summary: "", - valueIndex: 1, - entries: ["animepahe.com", "animepahe.ru", "animepahe.org"], - entryValues: [ - "https://animepahe.com", - "https://animepahe.ru", - "https://animepahe.org", - ], - ), - SwitchPreferenceCompat( - key: "preffered_link_type", - title: "Use HLS links", - summary: "Enable this if you are having Cloudflare issues.", - value: false, - ), - ListPreference( - key: "preferred_quality", - title: "Preferred Quality", - summary: "", - valueIndex: 0, - entries: ["1080p", "720p", "360p"], - entryValues: ["1080", "720", "360"], - ), - - ListPreference( - key: "preferred_audio", // Add new preference for audio - title: "Preferred Audio", - summary: "Select your preferred audio language (Japanese or English).", - valueIndex: 0, // Default to Japanese (or whichever you prefer) - entries: ["Japanese", "English"], - entryValues: ["jpn", "eng"], - ), - ]; - } -} - -AnimePahe main(MSource source) { - return AnimePahe(source); -} diff --git a/dart/anime/src/en/animepahe/icon.png b/dart/anime/src/en/animepahe/icon.png deleted file mode 100644 index 4c3b0098ef33a9f6b2a15ea2a15ea7b605af17e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1934 zcmYjSX;f3!7QP`N31p%P8Axt!5+Knq2qiM97={1|G7|`c$V{OEb*?x-EItL)Dk_rJ z!lF_Y1raJ#T?}Fwj35F*K*a)56l_7XP?tmCy#xMvd#$_gx6iltclJ4Z-E|9s1AR%x zY-0$5ND8?u6uje?A3PfPL7$_5KtsX)N^cPUzZn@BK@gotq|j(IfX&$OXO>E5GFLFn zGY2bVGWj#0GMFIbAbbXEITPjyXbctrR4VYME0kbahl2o2BoY}6h8c`dD5e~)fDI$Y z#>Oxrpi&ut1q7FCL8o(QG!}(IHG_Ff=CU}@1PUM-U|=i`0!k3X5&#e~nLIN23y?z~ z5Lg@zolXahNhA^uB4EK>HrJfT<1yJ>4##q(8nUzmz?j1mfHpuT*afTuz+$oZd_D}r zpb&%<3I+Jj6wEhA5D_>6jPR*cDwD}wk#Yw+a(U()WH}8Ohsy_Tv|+*}9I?jOw}jy9 z!?F)zIQ;$hOu3Pw4;6i?==ARxG<5z)Kn;lqTa6kB*z0P{X5MTaJr52%fg>X$;i{hcQ} zb8~YAB(L`Nj%LHKB$|tp>xRarrXGXH!NI{Fe=41rm>3-$YiYToMMvb3JjTYx?Ilj> z)O8KN{q_~rbxVArgk#0yS;Uw+rhT2Umm*E3xkS<(H%dKaK8nGiAwU11;83N7NW9lX zI)I8kkfR2d`E^ECGR^fzf;^w>mHEZ`UoKwqQEXbp6`3QJzAU>dIR8sV{@vXV9`^Qj z8AK-0T&Jg}`4+;iuI{r0U!871L-2LtSS6>Xd3np#WcRI^->h?!DkCBrupv84+=Pgw zNNjCu?~uLk0GMD$M`x*#JT@*NCN}QK(Sl;4Zzw~;=JErAL&NE7cbm9XUb%XlBvUZ$ z8|yW%!SJ$ng$9PPt;9_H24a}g`X_5}m!Da_HI4a;bP20}L0l>)Sdk1DITIYZ-CN1i z*K228F_Sj-j;aM))S}BQg}yLj^@b&g?3JA(el*k{`y`lzAu}91Z{WkcV2N%*U3#o~ zLVI(_{NG0|HbRU~&pg_oOXrjVzQSIG%tM(rI{P$z7cJZr_r`cNf0K0;fn`$Mpq@}Z zkp+JjVU|2LT$mv#G)QO&cA~GgjjRs#u5-s3*!DpQ>CtHl`I?)ag5AetML@Do=ZX5V z>2Oj(@;aOOj~(+%Q3b@O_z7C*!M zcFzN{_mY||7yZ#tLMvGWJB$@85*B{DCJl*T4*au$?r zOzS?shp@Wt;_2Ri;ml7PL$U8(J6X=XC-jWm6pFstlj^5Ab*ulBe*e=Wo`2+QzB64C z_opqs77MNU*{uK`r%>LwnN@pzx;Z&6565T+V}gX`uC8d?(;aBJYqE0Mvn^Vscg{D8 zqw%wzsLE3A7w(=ja0yV~dK7-@SR>y#l`>O5b`5ur)~`35h!78;HO&?dI}__<=Uz1> zW8RbIQ5lnuilx+iNSKCp^YKD1pmoLS#gJ7!$MD;turB7dCyyULZ3ETiZ+~<0)q}uZ z_U+~XQ7cuQ)|`W#6hlXMm6Rr1WsghJcZ&-82`=LUcLeL)260+!WQN6dYpCktfAXEX zpc)0CX%oH{H-*mlKwWBQsk8rUpdqMCZcJG@-j@5_C>uODan`VQTV4k%rwIC9y#1Gw z^ZfMhk@!7g_pT4w533zT7mbNKBqNo#A|#0Qyy>Q`iq zBi$kbb)d;+U+m#6Qr?XPsh~4Zl&KBH^rZ{!zKU|bHt-_$!s8j!GgFy|OP_82(6Xv} zv*+`KsmvYO8w0wz8pfI4oc@*3kLRKmO3+Vr)#b&+zFMJMd3Ko8-L&lB$x%jk#fe2| z%fQkJN<)xNlUw;N@AA{F`aM6d4XWRJ$(_U2$x}Q%8w{_-)r9p@#*y@YCf2LcmD~P( z8y!&gQva<%9*=OKIjcw2w(iIk`MuhytwS1<$AZYzs-mjV^|jH1U9m^2{D!+ID#A=` z>6sB5x^*~gU-P?{Ran9^bz!mW!|ay8f%xQ-EvT!ys%|ZoUGspuJrF-s>0jGgmn*ba b@5nNEb)?b(AET^Y{v{~917$Uy@!$OqQYX%U diff --git a/dart/anime/src/en/animepahe/source.dart b/dart/anime/src/en/animepahe/source.dart deleted file mode 100644 index 028c1b76..00000000 --- a/dart/anime/src/en/animepahe/source.dart +++ /dev/null @@ -1,17 +0,0 @@ -import '../../../../../model/source.dart'; - -Source get animepaheSource => _animepaheSource; -const _animepaheVersion = "0.0.75"; -const _animepaheSourceCodeUrl = - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/src/en/animepahe/animepahe.dart"; -Source _animepaheSource = Source( - name: "AnimePahe", - baseUrl: "https://www.animepahe.ru", - lang: "en", - typeSource: "single", - iconUrl: - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/src/en/animepahe/icon.png", - sourceCodeUrl: _animepaheSourceCodeUrl, - version: _animepaheVersion, - itemType: ItemType.anime, -); diff --git a/dart/anime/src/en/donghuastream/donghuastream.dart b/dart/anime/src/en/donghuastream/donghuastream.dart deleted file mode 100644 index afed2002..00000000 --- a/dart/anime/src/en/donghuastream/donghuastream.dart +++ /dev/null @@ -1,241 +0,0 @@ -import 'package:mangayomi/bridge_lib.dart'; -import 'dart:convert'; - -class DonghuaStream extends MProvider { - DonghuaStream({required this.source}); - - MSource source; - - final Client client = Client(source); - - @override - bool get supportsLatest => true; - - @override - Map get headers => {}; - - @override - Future getPopular(int page) async { - final res = (await client.get(Uri.parse("${source.baseUrl}/anime?page=${page}&sub=&order=popular"))).body; - List animeList = []; - final urls = xpath(res, '//article[@class="bs"]/div/a/@href'); - final names = xpath(res, '//article[@class="bs"]/div/a/@title'); - final images = xpath(res, '//article[@class="bs"]/div/a/div/img/@data-src'); - for (var i = 0; i < names.length; i++) { - MManga anime = MManga(); - anime.name = names[i]; - anime.imageUrl = images[i]; - anime.link = urls[i]; - animeList.add(anime); - } - final nextPage = xpath(res, '//a[@class="r"]/@href'); - return MPages(animeList, nextPage.isNotEmpty); - } - - @override - Future getLatestUpdates(int page) async { - final res = (await client.get(Uri.parse("${source.baseUrl}/anime?page=${page}&sub=&order=update"))).body; - List animeList = []; - final urls = xpath(res, '//article[@class="bs"]/div/a/@href'); - final names = xpath(res, '//article[@class="bs"]/div/a/@title'); - final images = xpath(res, '//article[@class="bs"]/div/a/div/img/@data-src'); - for (var i = 0; i < names.length; i++) { - MManga anime = MManga(); - anime.name = names[i]; - anime.imageUrl = images[i]; - anime.link = urls[i]; - animeList.add(anime); - } - final nextPage = xpath(res, '//a[@class="r"]/@href'); - return MPages(animeList, nextPage.isNotEmpty); - } - - @override - Future search(String query, int page, FilterList filterList) async { - final res = (await client.get(Uri.parse("${source.baseUrl}/page/${page}/?s=${query}"))).body; - List animeList = []; - final urls = xpath(res, '//article[@class="bs"]/div/a/@href'); - final names = xpath(res, '//article[@class="bs"]/div/a/@title'); - final images = xpath(res, '//article[@class="bs"]/div/a/div/img/@src'); - for (var i = 0; i < names.length; i++) { - MManga anime = MManga(); - anime.name = names[i]; - anime.imageUrl = images[i]; - anime.link = urls[i]; - animeList.add(anime); - } - final nextPage = xpath(res, '//a[@class="next page-numbers"]/@href'); - return MPages(animeList, nextPage.isNotEmpty); - } - - @override - Future getDetail(String url) async { - final res = (await client.get(Uri.parse(url))).body; - MManga anime = MManga(); - var genre = xpath(res,'//div[@class="genxed"]/a/text()'); - genre.remove('MY FAVOURITE'); - anime.genre = genre; - anime.description = xpath(res,'//div[@class="entry-content"]/p/text()').join("\n"); - - final statusList = [{"Status: Ongoing": 0, "Status: Completed": 1}]; - final infoContent = xpath(res,'//div[@class="info-content"]/div[@class="spe"]/span/text()'); - anime.status = parseStatus(infoContent[0], statusList); - anime.author = infoContent[1].replaceFirst('Network: ','').replaceFirst('Donghua Stream, ',''); - anime.artist = infoContent[2].replaceFirst('Studio: ',''); - final epElements = parseHtml(res).select('div.eplister > ul > li >a'); - List? episodesList = []; - - for (var epElement in epElements) { - final number = epElement.selectFirst("div.epl-num").text; - final title = epElement.selectFirst("div.epl-title").text; - final dateString = epElement.selectFirst("div.epl-date").text; - MChapter episode = MChapter(); - episode.name = "Episode $number"; - episode.url = epElement.getHref; - episode.dateUpload = parseDates([dateString],"MMMM d, yyyy","en",)[0]; - episodesList.add(episode); - } - anime.chapters = episodesList; - return anime; - } - - - // For anime episode video list - @override - Future> getVideoList(String url) async { - final res = (await client.get(Uri.parse(url))).body; - var servers = parseHtml(res).select('select.mirror > option[data-index]'); - if(servers.length==0){ - final src_data = parseHtml(res).selectFirst('article[id] > script').attr('src').replaceAll ('data:text/javascript;base64,',''); - final src_function = utf8.decode(base64Url.decode(src_data)); - final html_data = RegExp(r'"html":"(.*?)","autoplayIndex"').firstMatch(src_function).group(1); - servers = parseHtml(html_data.replaceAll(r'\t', '\t').replaceAll(r'\n', '\n').replaceAll(r'\"', '"').replaceAll(r'\/', '/')).select('select.mirror > option[data-index]'); - } - List videos = []; - for (var i = 0; i < servers.length; i++) { - String name = '${servers[i].attr("data-index")}: ${servers[i].text}'; - String valueHtml = utf8.decode(base64Url.decode(servers[i].attr('value'))); - final serverUrlList = xpath(valueHtml,'//iframe/@src'); - if (serverUrlList.length>0){ - String serverUrl = serverUrlList[0]; - if(serverUrl.contains('https://geo.dailymotion.com/player')){ - String videoId = RegExp(r'[?&]video=([a-zA-Z0-9]+)').firstMatch(serverUrl).group(1); - videos.addAll(await dailymotionVideosFetcher(videoId,name)); - }else if(serverUrl.contains('//play.streamplay.co.in/')){ - String videoId = serverUrl.split('/embed/')[1]; - videos.addAll(await streamplayVideosFetcher(videoId,name)); - } - } - } - return videos; - } - - Future> dailymotionVideosFetcher(String videoID, String name) async { - String metaDataUrl = 'https://www.dailymotion.com/player/metadata/video/$videoID'; - final res = (await client.get(Uri.parse(metaDataUrl))).body; - final jsonRes = json.decode(res); - String masterUrl = jsonRes["qualities"]["auto"][0]["url"]; - return m3u8extractor(masterUrl, name); - } - - Future> streamplayVideosFetcher(String videoID, String name) async { - String url = 'https://play.streamplay.co.in/embed/'+videoID; - final res = (await client.get(Uri.parse(url))).body; - final match = RegExp(r"eval\(function\(p,a,c,k,e,d\)\{[\s\S]*?\}\((.*?)\)").firstMatch(res); - if (match == null) { - return []; - } - final argsStr = match.group(1); - final argsPattern = RegExp(r"'(.*?)',(.*?),(.*?),'(.*?)'\.split"); - final argsMatches = argsPattern.firstMatch(argsStr); - final arg_p = argsMatches.group(1); - final arg_a =int.parse(argsMatches.group(2)); - final arg_c =int.parse(argsMatches.group(3)); - final arg_k =argsMatches.group(4).split('|').toList(); - final unpacked_js = unpack(arg_p,arg_a,arg_c,arg_k); - final kakenMatch = RegExp(r'window\.kaken\s*=\s*"([^"]+)"').firstMatch(unpacked_js); - if (kakenMatch == null) { - return []; - } - final kakenValue = kakenMatch.group(1); - final apiUrl = 'https://play.streamplay.co.in/api/?$kakenValue'; - final apiRes = (await client.get(Uri.parse(apiUrl))).body; - final jsonRes = json.decode(apiRes); - String masterUrl = jsonRes['sources'][0]['file']; - List subtitles = []; - for (final track in jsonRes['tracks']){ - MTrack subtitle = MTrack(); - subtitle.label = name + ' - ' + track['label']; - subtitle.file = track['file']; - subtitles.add(subtitle); - } - List videos = await m3u8extractor(masterUrl, name); - if(videos.length>0){ - videos[0].subtitles = subtitles; - } - return videos; - } - - String unpack(String p, int a, int c, List k) { - for (int i = c - 1; i >= 0; i--) { - String word = (i < k.length) ? k[i] : baseN(i, a); - String pattern = r'\b' + baseN(i, a) + r'\b'; - p = p.replaceAll(RegExp(pattern), word); - } - return p; - } - - String baseN(int num, int base) { - const digits = '0123456789abcdefghijklmnopqrstuvwxyz'; - if (num == 0) return '0'; - String result = ''; - while (num > 0) { - result = digits[num % base] + result; - num ~/= base; - } - return result; - } - - Future> m3u8extractor(String masterUrl, String name) async { - List videos = []; - List subtitles = []; - final masterPlaylistRes = (await client.get(Uri.parse(masterUrl), headers: headers)).body; - final subtitleRegExp = RegExp(r'#EXT-X-MEDIA:TYPE=SUBTITLES.*?NAME="(.*?)".*?URI="(.*?)"', dotAll: true); - for (final match in subtitleRegExp.allMatches(masterPlaylistRes)) { - MTrack subtitle = MTrack(); - subtitle.label = name + ' - ' + match.group(1) ?? 'Subtitle'; - subtitle.file = match.group(2) ?? ''; - subtitles.add(subtitle); - } - - for (var it in substringAfter( - masterPlaylistRes, - "#EXT-X-STREAM-INF:", - ).split("#EXT-X-STREAM-INF:")) { - final quality = - "${substringBefore(substringBefore(substringAfter(substringAfter(it, "RESOLUTION="), "x"), ","), "\n")}p"; - - String videoUrl = substringBefore(substringAfter(it, "\n"), "\n"); - - if (!videoUrl.startsWith("http")) { - videoUrl = - "${masterUrl.split("/").sublist(0, masterUrl.split("/").length - 1).join("/")}/$videoUrl"; - } - - MVideo video = MVideo(); - video - ..url = videoUrl - ..originalUrl = videoUrl - ..quality = "$name - $quality"; - videos.add(video); - } - if(videos.length>0){ - videos[0].subtitles = subtitles; - } - return videos; - } -} - -DonghuaStream main(MSource source) { - return DonghuaStream(source:source); -} \ No newline at end of file diff --git a/dart/anime/src/en/donghuastream/icon.png b/dart/anime/src/en/donghuastream/icon.png deleted file mode 100644 index 7340cd6234982fd15bc3ac2e8fed440a7d33067c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 83031 zcmV*4Ky|-~P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGmbN~PnbOGLGA9w%&|D{PpK~#8Nl>K#7 z9a^&QkM1|#8~5FN&S~2g7u?<5-QC?n0wj|v|yyA7|9VTlA=`XuZPkA5RRYP2_oTROEjHW9iG!~E0TylfP(i_y5+@h}d zCbgGuQFrAw4aK*pzjBktqDh*s+@!tq7M&G$X}WZS_L4hvRo$nxc#QM=>e-rqge`e{ z*)DZBz}D2Y6vQuQcg|M!=4@p{{0cTDuH;bm zR(2(=Vu^b^8^f}s?TF3g*uwQ(S+keQjYlXeJiwK8`zTs_nBz-!vLk5~dEUwFOj${u zPdpoiOt&(a6FVu6P;2?vS z+o|4tk?Uuhq(60?ZsK137&j_Lm@FS=vV4@AmE+v5y(#TRm`$1y*xliQ7`S6`e-fc zqpfI=){hdJjS8h>Va+{ixd(u9;DFM*W{hC1ufENuz zy!{aXez{@k+ElW?aHU9(!*?U+Lw~Dlo zY@%IbSP+=b%7lD2WvpXM#(K6d*ub7en>ny}J4cuAW&e_G9LU|l(Pg{Yld*x7feXm< zOk}lx8oT22DGbe|ASj*P2}`-Oau+pQj!FQWU$KK-sjJu$mruT58modcNU;r~Fglyv zX)8FgxPUzw%UBbZNV=03@m7u`+qtsP-J4v$AeIG&vNkxDg3x%@hb2f`6A~*yu)xKK zBzrd^EFB56b|Jvb83!E;4Cd&eIa3GSc}5tkS)esj57lW}%>P1-nZHn$0GK^flX*&d zD61PWS6NR2LD#?%ZEaI#&s5{{pUsp2P@k{Q{JFY(^|=ba_~|@mPSZqF)eIdCOVs8X zGUsbeW`ChBZSLplD1W7e&Rk=xv>k9Z@x;yC3rlS)3{?%$oUM)8Oii@r>Y}S;fc88+ z)Mu)rF-@63TQ>sC?8y(0Wm|G4r}9>EdF49#PF~_hc^hThPEon@EaT)SPRdYiEV4`A-iL#+j0JvE*!tMG=?ls-ve(M7swm)IA z?(P%-?o0vTHhpEcrT{QOSIID4C4*Bo%+-=1I!Z>QPqvhdQC~Dd?d36QizcYOa)X-U zo79xvp|<1>wPkntOq~4pY6p2(H_Ws8VO}>3^R7t%V3cp0$M{wI4Swjl%WwN1@m=3T zo^{-0ymo+r@@{%7`ng&%Kv%^C*UHCfx;#Yvr9qmC$7Lj_zjA}7;+vnWwd5vkB{yj; z8l(Q~0F}pk*s;8bO?l_ovHTLJcGOdGvWvP4Jv3dqPIFNgP3KxE*V13vk)&!)>Q-76j5(NP%?1;|cc-A^D zuinMwH9I)6Xce1d7O~Vffo%5}Y2xG$*0E=6LM~@kY-M-)QfUGJ;#5y_^pK~1j<-K6 zLnA4SOJZAG2AiT%BnVaqMX}s3j2w4=((TvdVKM@vIK#ax&`JYt{CXrp{8Vv@>~PvPSg4Xg85%+qB>m{?Kwu6s9R&L z=YWx_nLPbfr)e_l=kuBKxiTuVv{9X{h4OS2=KOpno~90X8`_ZM>`h^8D#vn`u|6z{ z%8k3|KVMD#-t&}hK1#>Yaz;z9^00Y~AI4uJ4%eGigG^QoN=KJKs1zWWkU+RmHO^Rh zKNFSx+^GI103Nj5<4NZeo?m~#MC~mmYVSw@3|HM{pz=0-#H22r+kdgl2O{O3`u{KnaPzgnu;fBD85NU=`HF?Z_`kEoBFale0INXh==uqJgFbz zdE*donuhtNd6@5-NBF*Fl<(Wd_`YL;U-#VOhk-}D@4meR5r(? zupuIWl>uR7xp&yZNHwgq01%eE%a8l93YMwS$Du$S=8lyK$2jyQVq5P#9N?)il z?{gLAexbtL>FP4YQB^jODUUq$XRGt`pU&VX|Nb>!{CpNOzL>|1U(DsppU!03S1Qb( zXMmxeJ(gzf80kBpu40P1vI%-x)+o)?m8p;bfYNjwlxOIo^pzHBGxX3^GDdfvp*-!C zzE4slAqfKE{5Pw|rcxh;O;!zX zvv!pG&9`~n`H*K_&zPvY!FbJ0Mrv*`Tz!+ls$29|+@P;~lD_hBMr$V-t(#z^W`e=$ zF$sw7vQZfc+KY!}dfr+(PHX8TEv1t*m*4sq`|NS!FpnDtrSrdP5~u$V-?j|#earAC z`>u7EUtYVxZwDXn%Yg?x@0{RPT_3}hJq%S3Gv0WU(fS))7wJ$@pZvicC1W%d4O4$% zh{j7pv|JjdRXm>Sr{Q!L^(Q*1JJChsxiRWak5GSRgqBOAbQF)%RW?p<#kl;1#u{$W zTh>S0`F2`PHPdmnjn4BOTs_@R+wpo@j+8TSu|fU^6hveaZ{kk6wGXR(;#eP$z=5P( zPG_yX1m*ghsJ0Jc^Am@lyaurZ7B?wLy`r^baP_)0Zq~cWH~=eF@Mpz(-Rb zS2aBx)%0=IHp4~FN&-P^ni?vfE2I3S3aVeLp*BN9rXi}cHBgzOh0|db-xwSbJhYaH zG@15=GBdwWL0N!qmJYMOP-Vu?m6-FT8XB{8(VU|IfN=hw{m^;Z}il#6&h3yGx6hM#JGruPKNDr`bQ~+?UTr@& zs(P8M>|>%_*Z|`d158v5bE9fhp7;|2Ahm-`)(kLS)z8hkVIH;J;c3@Ho?Lsxc|%nyCH`OVM+ zzUjHcbYdBbiiWvbJT{fDjdJbsFkP1i>A5^a zPw^N-H4o`3y+hljF*+`Z*BIw|@i12}_Rw~wosM%?>A8HJq4GXy16Quof4Q5{@la5iTxr?XaaI5m$QQE6-nOJsdeEK5Cu zNwaYy#>jys9%00rxyi@1AxZ2^&Sq6mEQb~?W4V7gtAZm~7aqg<$T$k4r!RJ4nBU3Q}00R{xrvJ|`uvFG3Ga!-}YZo>rq_aCElfuY&3Zs%Zym&d+j-97w z=MfI)tf6l2X}Zr;$^V-h zhZ!mpHcI=s0eXrj8Lhc5EB>*{n~anWGgLCbP;s|3kw-pgoRF--Xh}EM&$QBUyn&7r zwe*~+;6UawG97$a;u^%x*h~(mF5y5@HU||QHe_?b28=_)A0bqS(6sv+m$ny$d zp_2#ME*`823S(1v6f1rFNw=~k+R&H;GYfLP{m2grBgN635MvvHOziMCw8l~02;#bO#hFsnfKLPW`915nLnR}$_!PEHBGQFu#qS8+^7eH>v~xdKDn3>i=~5Pt^4@Qq|3H<#q0~jPtzb0Z+T` zbGvDr@wySlYKIxC8I?9#Eu39pBUQtURS$i#(W*gd;`72pM38`~5!u9q1Vew-qy$5E z<+!xZUbl`ROaS10>j>YpiIiuM@7sm*_e=Y(t&b0_eSFtB#BT>~^ZSu|eA6|~{krSi zu2mp+xU5^|=N}O`P%)waLCFx^#e?(;r>+=btZJOe>TxEj#uzOh=0WpA?lwH&M)hq; zi;b5KbE9mC8>PKWmUQ!^euM|r1KcU^;Z9{A_iKi^Q#rtJ(N(%n)vzfhos|I*Eb|JM zjxC&gPy7Oor{{7hcP*zfmvJ_01&2~|*bo%M5@%l)*twHp=|qgNHJMJ{#F{#=)F+%| zYZp>%Tv_57#O~BAG8{bQf9|H(B(}sSNdOc?M9arj!C_>(dy!~mFZ2Bs{=saDiep_! z7&%U^WZ2lU$ia~;XIGZ{`m@;6hgeHnVyzrWbM+&}))gmp101zXu+cEYLPZyYxteIt zP(kg>xy=9hOy>P;CbNDz9nD#4n5vs#u4yJ8h4bsq*F}An7V~FoGk3PO1b~`~5n38% z(sZ;eWE%9vFXqWQVa_ZqSuhI#%=k)G!8T1-mj$oJJbkp33{jn{D+}wdKc6qbAW|%i zIhyFqQpaGXie!Q|CM_U8FoILdR&X|d6-TmjIJS5RtAoPmK5>qwJ%`wpvWU8!M;N_Q z&sb?QljR-UsOsisbsrOzA_DX>CLXK$xY;GgZuZ@VcE*0I{b zDI5M|qcubF#FvgQU#DL_AFmmfCP45p8i>?LMvj^>nNo{lS=6n<#6kVp+x7{hwT|(& zZG`u&Lwsl*kPiP%OAqgxuJfU}i+3&EeB05_Z~G?s!^j)aeyI_W z4wZ;#(8pl;5dG!D^0XH=Ts|TlUYIC^B>h!3#9hJrR*o`W+|THx>)a{n<5}$puNy{r zSvSc2l1`pfb@Qr0P_%>GDeL6w!7H50-^K2fd~#gf8 z+}T<(T@nn_^siO;>WleI`$9>kKf=+ql=RV3F+h2?CbPa$V)oa94bntomIf{+cFg)8 zKfzW-i=7J>vn?fqlezg+ZQe@7#!Vc{&S8K00!}Z>r~AYi$~J9hPg)K)%A4pqT}J!S zVxC{U!AMCbw`zsc_A*$~#m%}Q#%lT*s=Cf_bvF|Y157pyGhR2yMEwxAn#Xw2^N5=b zqY@0GB5H{5uO5(&ED9Kh1L>pU^?HNFZvp1WCN?dHR#)>`snP5UEaXM44O5j~BRkk?!oyA`c(Z9h^zEagZQb6%fRR&@gr-B(gU- zh0W3NY>iE1XHo`BJOc^QHz(A@8gC;rT=Y$_P}aa`rZW1|=ArqE8R$<_!b#f{FB1o8 zE(SK3sTiO=T^;qWRbw=V~!`x-xU7DWN=54FhFe+)QoJ_GVGaz|E#n34lAz6Y^_?^Zye7gEB=DY1BW{DMb_* zsT`0%5C9mf{#Ou)$neobg!t@f!zfQ1hI!f`m>^;Oylm>>W%G4jH+Atw0HC#p_iep= zXz%0uYeW3dGsdsG$N2WzICrY9bF<>Qi~|1|0K*l7()s^80NgC=m8s3W@^0>yc5&x& zI}fjP@Urq6A8LB|rnZ~AXDaC4ahwZ_*04D!k)mDIHu(|GjGR0UQ9LDB| zXtqVhOWPWez?SfM4yG*PK=ML11jmx){xOAlb=X6`8=|fKd5wp{7J@H4i+)7T6LEnN)0o{iSezs6oo2VWy= zTr`dF(6hwX*Z~g%JFHcWFrBB5nTio6N(N}o)L_O>XQMe^Pdf6K|1pEvUnS^Rd!4 z!qdzKI}L3-wDnmZ7tgtst2mLJL+AeeG;H0<^}`3~K75#q%U5uA*>Wm2?cn^1^_*U| zp3dW!87gX|=X?XV>j&kjFP#5I{n!)$1{kdFWvHf~(fT3A8iwWLc-;^;8b^81ev2FR zBcGgHm`HnsBH>>11UDPTrPGTPNI1O0=@m7>kDq_64`hu{Iq=CoyI(oTz3KrT*7WnJ zwvWg4Jv?dX=2_!)o;P*zvZb3hZ9Tl}=#u~t_Fd;7KU^Q<*S$C7_uQ)NW~{7B0${YP zhmkVD*oYsXaDD{<2BnRc^-lqyPXa)6pG8_TexZ>Y7aMq1*1@aFtK2_V#o*pET*_R* z;n++z`NgotD~xpkv8)eCWL-!SD+6OB6R|!lLOR^Kzz{Zt$FM&sL#9DjR;=e#)-pCn z#FJs`MwFo?5ynS`u#QNSa50v?yyw38H8VJDC!RI$=v}A_o^NWLJC=yAzVxm6XPg zgcQ~UN0MUgOr)WetOsJ8TyfUY#ZFZNM>TC}!KSuE+qmGSVML&@Jsvt1k~I<_2(tFZ z&(Z@6Wh3VNWG2)9Z3fzNby5CWmFfR66ZM&zXw24T&gb)Gkt~=Z)w$Zto1rF~XVX8Q zD*-TbnzCe+)Mu%nIZGMsIjZQZ=wP6xhpw{7{nb#JJ{Ly=GrY_!2(+*!z{rRdAt4m6 zU(fFNcp5fu1s~pt>*ZWHI#2TECJAYs+y-Ax25w6 z{}9eOQa#9U&5(3{@i*ej$J_&+% zts)Zi^XslrSr7{f^>$Scqovm*07Qj9THgO(06-A|ehh#c<-Ob}yT+aJYdomB&Xd}1 zo>g3B^jI+!OEqsimNXPLf+uwO|*kMp;nFrTi6q6 z=SrfRFG=ox#5sErXl9GEhCa4R+Bm7};i_efm%atT7LJk^4>EU<-xFYDMYN3*3*3BU z-5~Tb+Y?gQot!RHpDi&7vR{zv8AzI~E2-A5q&m2h;OvU!{Q0sS+JT-i@BP%=bini{iy zHU~XrL&@TZh#)$<4^gi9V({vQVC4k3=e@uzv-@XXC}aOqBFUXS^+V*xDW* zH1_bQxrZms-8^gU`j+kv~h>X_hGO|L9)MoOJXM19jbhNbrp=3LHkZ5L0ro9Jornb`gGhKa& zw{w>aOp=Qa39dfGyZI1d?@EBVE&gUUgxk3g=ju(QgF^per=p9=3}vk5Y2u<~jEk13 zlm!G?IOA(U_J^k(Z~tYjpCp!9_@W?B|#&C!uS5Zzu85vKoqjsgUq&tvA# zXP`G%1tTR@OjOh{Q`f>u+W;#)1I)B^Fj7&$+0YPQQ&XbtZOHU+V_kR|u35wdj?fQQ+VyhKzW)&bipcQ4r$nEPT>Fr2mp*!jsA!Q`X>NnH&C?3MR%~Ohw+N5^q#4q zdh2m1SrAREgK>*F5SzuW@N`zVhLB?FN`|c;D?^jnl#<8VxGZvmVp$)P!191VG96t> zva}`L#+f`1e+t7B*qN|Eiq+EW+)1={lMdypYe9gK4M{G3q<98N0EE~&<85Mtr;!x_ zmX3tjy2_7j)eJD7r-i|EWo%USan-ZHLBkYJLp%Jcvj z+SnvEC#I6+=1rQdqb!VJloZmCGLSNaStZa#0K-})5#3gUSnP1nLq#YBqjw5Drf zG~W;lElad#>tLvAEE`%v+A!@uW-{$(vn2pTf5BkB3TA5RSZZovsjZE*jz0E=hS(Vx zV5Oyvi-A6&w$>!MI

p2LgMxPEvqJ0pYG65>novRnp_9%1D4Z96Gjx0$l_ zJJ=qd#j3z$cBikQ?N~MaMOV2|Gsbx3sAL62hgVRO!}Sx4)J-rj#n6Z-AWm;lq>4jS zIPQ4mAY&B+QadE|L!zrJJ|{VTMbk^D5u_wy>U9MDDF7k9=6{a_isJaQ;Vaz?m-I*g zObP(h_j9jlfJdzZJZ|sjS^EG_TY7le*2mk<0p495kWoPN1Vm@}L-%dj@*cXZI@3J?rR8dQKlkuG&|?QAtwJ5F+b#Wqf4ujOF!61D^;vfR<1js7td2E?!_ESVh% z+3Zfwr!XO#9RE1t>^w=ZaUjFqnI#@RtP74}YfLJ;5;NHmzkn?<8ElA5A*Agog z11V+jG`7c7$c2^kBv7Iq73q?wAGT#=vBWP(Ql;@0wvu(q_YIapxnyf+;>{fh);2-+ zfBlRUHxE)hJ&1R5VS$eyt776<;ORrSiIr5I3We$JUV2uz=~>I} ztSE{F5Uf>9uvIfd?`w5T=IY_3YlEe_sf-Gy>Sh?JnMm67tACp=i)8_Td0))IR7nkM zbq(ybb+OaZ!CprXS3_gm42*Eq)y2m^mn3Hgvb|k7zbcQ4^{W^?bBvu)p)7N;=WI?E zT?Y?x{m>BxPoClG-osp8Uci-=o7kV4%Z~WPtPV-%;@U$}w>5CNi@S|N@;uJ1#v3vM z27$jSj8zHH3`?7+8d1omYer-w5#Ki~PW@T|A|aI+lRYTG`-{k+ zkWvT`{O3rZu+K(HyCr`wczgkXo3*{%uJ7e;LofFldw6kmgct3D5&$w4YU@=L#GM0t zdu^0&u1!h?>1KHslV#VXvQHpW06>^P-^Vv0!k$EQ#gIg^_?f+z8YtU-loLxgaB|67 zj%4JqIXI32uOPMsL~=MLm9o4w)U4aewf!dJ%iX1 zoyxIAt2wk_6`P{7Sm+i`l%*HGh7Ne?+eu2%&(@tlM{fe`J>_ZdV{D1Pg#-2)2KbrV zW2>fzy_PYCv(-@ld=^f6=Gf_)W1_5!laY<&#m&?V6;N?YD2J@HNJYrL|IuA zXKl$+Uk?_$+Hr2lLMqnf)3#$X_lhsE+S`*@Lj!iCBy()(Qu@!HW4x$@&V5HXpRg=~plL`mTx)^p`C%@vONK|>$US_h@QXzAxgYp((To&9`sZIJJ-k9-2a?J@-bgyut}LE@zU z7zIAQ8Sz{c#^R03@KxE%)zg)nU%!)GX?g5QS|mHRCo^&=Te^ylO*^=E`Xa*zj`Q?N zHKQjka$?~!7Q6ZrXW~SzM+l3Zd|2ln&W@Ng4y7&O^pbU)UAmbaiFstZM-gt~L9mG% z{wA)t8#rL2Wrl-+HNFmBM0f-dWa}cGSDgAbstSj&RMEytO&`4(%4kiWkDab5R$3;Q zs_NrlY$MH3bZ+NqV>VYGcO7dy^~~|mH6lMUnx$c3gqfS-tF42NhK`g#h@9R{6q#Sn zz)?vZM`cwat?Ws1_9V>QRx(X1;u7&SHX+E&l$GIOH168N-q-}zx_MLR89=>SX(E;Ol?SZ@|5+5>~Aj20+j5K>)m<`e zz9BV0{Zsk)u;Qezo?xP8QUYMI=8lxcj8#oaP$*2$r&GmjjVPMOWCR&+xbeyPMN|=B z`o98zU~a~K6amC=jCgbR>Uz0f-^=5sKAtxA@w};*7tKAq7CnKh1AKpNnD4KT^UbxJ zJgFb}7XS#FN&rAGK_ZMv$FCZdg^2)w2t%Tv5#T#lu#e-*HgG&|JtYO(>DY6Ok>lrh zaIu6}Wwm@$+rsPeI-Xpv;^N|!EOzuJ)yjnoJ0B@)-jk5Y@yuLK=d9#(&MHpktl@Cx zYSxD@Ak8tDFjEiwja=|Cbiz@~3R7i$thLSXvUMlSEdXB&N8AmpWPUI5c^h>Dnf90~ z>!CAE8Ke2y*l3$#scDRbh7nFiw%F=gpgT_s?U`y=DjDIRVTO~2A+B2bY+107bWcxw zbhYu+)FQ&vQl9!j`exYAQI#iuyn`ztf?71Oz~9K6oS<;hyaNa{x57EyrKwq*EGgM&4e_UAY!dOiM8{^ z&%_aDeJdHc^yX`${M9_EHJbnVJgn6X@Ha9e$JdW^7Z27&$FnXbmQ4u>kD5Hsf~2XstImXPcm6`gYk+9`KU1Q zd_p>{NPR?6EM*Tu6ZBCiC*%%OY1GGvGEy<}$@%|F0DN?Q5t3vIRNW`XBSl_+zqXgB zjRO(@&l(gUc-7o1Yk+UB4)fjBF+OzOkN^;L=0vIJ2rI-+BV_}MZg82Pq^7F!ib3i8 zLh~)C((dyuoLje-@@+@BdaQ`sWlg+k>f*cBZoX@{DxLqq`C@)(?WQ$) z(a;8WD;M0&on-pptYe0)su4yrRi!vhf-Tgp-_HKn1#Aybk`Z8uTL4G0R#UP4C_B@Zb9(hI%D10pu((4( zYf6S^M3EYok1|m?E}eh0Y>XS#H>Yfp8#NPCHpUGhr4~{LQAGd9@%t-=qF&(Xz1Nl!YlvzY^SdX~88S>vQ-j@dk23}>pN`?U(jv$Zgst%?3jb?imqt6_qj zjs;EzHdtwy%G5`1j;1tQ4Rghi%RCL-^^DlOa1rj>T6kz_$i`8Ki8;>78l=1VlIHG9 zl(hqHn!0%F84zl1Lx`0vw#sVQsi+g@;Ka$5t5^{b$YOgZb_9mA+Qx-KM^DbjFW}zE zi`1^&Ec+V^-F!)L^^%P{XEklv$qqHJV6lgSVcL_ngo4NvGTejYM4G>eE!HY}n9Wkh ze71&s3^KK1b$B@ER^)Sb`EqJ@ZsY9Ad`{*sCez7^%d2v@c3>kthc_~DelNpkcG9?O z4Gnt=NOv~Je*Sc<=FBEDAefbraU5E-ltby+)NkHRaee_SJOicrHq*h2ZSh&O9WCP2 z@@GxM}NB~ThbTM9XU9w4nrjox*X}^2}9|0hKNudK5zjW{UHabt$Gg{Wpt*UF> ztL@@`RR@nM+jvoXm3Q^mcwc{2TH}VDtnm!uM8*;hBxgzG=g~#W*c6$>&bU-|$EC47 zI#ou76@F1V}891%_X!VKG}UHD*|<7)$A~xw;YdMm91MIO|)>JXz3+rb3VZ zrIG}I-V8O2=W63>Y>&03DUSNq^0_$u_2+6~tgI)&BqD%?iUG!RRPnd8AwMn-2Q^g! zO^paPHN{`wh%j>-*2E@Hb(`&Q(bC0DM;9jzP1ywV(9p<-jBT+gR2FRI>aN4G zHWQ7=#qR!WiCaL`_9I+ayNB-cwOl<}#ksWy={Q+W|7AsgK={jGale$qe+0lp<)n-V z(xmf>R7s>vQyt!#(N6#nCY=7G$&~y51b|x=14ygvmnMX1Qg%EAfG4$sJgMp9S#=-J zYI=ED+t2IzemOV%PDrRbZt=KoSW1`wcK`_a!!RRLQV1~#B=r5=XItn!)56H*4mmU- zG~;)wJ9%8!#f!#X-Zb{`vZjM4rHzapFJfy*tTdtU6hgOE{$cVDEjp`0=vEjUO|FX{ z$resT8QBtIV28J+B~Hr57<{QFPk$$EYwR>Fq@YaH03w$c#jyCCU`lkSX-a_TPE*HR z$xwD$g>(B@xM2Gu00^fS+I>+>Tc{afrD}qik{*V$l!bQM+g< zH+CK2hsqYNZQRM0z-TGzOR#Vt%-Ebra|_8h2@R4M%vtLf#_{yU)D&zZ&&7{i_W?#Fr(^#CsyA(*b^l&2tXjePh%m|gq}Z5nX+;*D`!_Lu zem}iOw^Fh`o2?0f>{t**l#L;lbG}CF=U+&bXtsYSyVA3zD)&UzQppCLShz$sBy-&S zSQnPa$z_F{U$dK@vo(xd7Q^&sDBg0G_7ioC3Sp$6Jxj&dO{MZ;`Lrsz(oLMRtsGxUiL8k3!uiEei*SDNTuPwJ2jt1$akQGg zb1gE}de}I?1EKb;>g0Z9Cy%PTcwBjvJD2O3I8#dHnr*D}36}+x2&qfm{Wy@ih#VJh z*;vYT_9n;HjdTkq63rZlH+Le+%msgaJDk)^@i1_}Mb{PwZ7XcFEM(dva(`D-2kF3~ zd1N}z5RK1Ouu-?bV5XLId;tPCLk9wEJR|@d^sI0(vXcNXRne1x5UG*)I@9^O=+Br> zvTp!!Zf>~i>X72$il31o;g;6ySh$#-i*iZz@WpEOe3|lS{p{!Xn3xc0Z-=j;9=_UI z_^YeS)F*WIJl5Db)3`lvNTXYhQ+xO70Z8tfto@Cg&lII=5;ha?zZP-iW{)>!WX{YaE3n!NErEY(z z>_v&}Kpc{a(|JNVy#Rs26iw8RjWCgBkBWLz7Q!OmS2+Kt2{EBU_`d;wNPk2PAO@Fj zRS!uJ+$ingPMN3y2Dnw+#hub_?hD~sbw4j^hon~jebWT*TW%uMq<5wMkLAHceP(A3+d8u&Ho}>cj8U#h%~liWq2y))6|Ku^}$Bf zR64)Ct~Iv0f(^07)6zvcvjBjlx;aWenl4!nG_k~8 zOXT5mu~SjSMN1PqrMdX&>kwmRN}#eb;mWFgE>j2}&&al+hnYCVlEOBrn%fXdR(TNln zZ07RXjZ%^=y5vQxHgJCVYAJ2rle$0-{F|^dF;XIGgq|t8 z&QPghRCb`eS22uL-X|$l0SYObs2o)2hpLBV^Gr6-s{YkJlN0-u{c`N^c8wTT?w6;z zNNMht_j9YHM*`qpc|VUT2Y6aD%Ik)4-ZtLkP4g|D)Q!oAp#Z?3Tzw&sDrFC10_-Dl zOZz@K|LwAF#e`S+bt$L5Rnf^q&slp%Hh+4i0+^9mu^)`L(}Cp>hl@HTdo>5Vw~ZFDTL*0zuZ zuox^6MXg9>jOQCl02m5B-_&^u0HzWE!uh?-9I;X}#9rGBHzR9F9olH><7{9iC%Hr; z%tA>Y<$wQzL=PXL92|+Tv1UndAVEgPY)#MP)S3-sdIsR6tcmR$WlX-FDH$IDkYGc7 z+~?0BR8xZjUmwcymNI$p2yZW!^1is7Z!7EQ-LZ$&?%rgW+mc{vLztc!3!Qyf;OHsG zF4qJEvf9g+bJbCgdXqy7 zmqClq02w7q4Jv`ZAgi7SVscQIaMDMIBV_ zE~0eXdHODi(Mgf&49V3glY$MJN_|F42NYJ;Cu_*zk}d{Iu1Ve5U`5|200qdc!0 z=VikUUNzq2k$537>3;%1IQ~S%sC?5>|5Mg4K_Vi{-7*EJ?v!>hUev;~mJ#k% zUT5G;Eq$k|soZ#!gBfc$wy=PcIqPZNb6Re4$Z_#yM{E+u7v*pve>ul87jZ0g5i8yN zWdvC17eTzG3rKEAK6 z|f|w*Z{}5;EMv$>J_VYC41`E-+ zE8et?gNt%l?BPk0l{GOIRz#ZFusdft0cMWaX_%n?r84vWZ3Y@Yn~kr&B|B0V$??dg zUf$Gf+d}(+gX~OAA;-g;?I{b{m9dn@{TJvvThC3=2`;@(|D|@$tvN#Tp=!BFZuoL9 zkDBhuMOtE`+=QqFN)@|>M1~=E4T)Zp=wVd|+091*X1}5?m^%3-0H*9#^?z-jNqx3h zTOrb&`Vl!+CTYy#>x>t7Gg;b;kW33FzgIEHgQ{T(f~U2UJgb}Fo(L=D{Sp9DpdLu*k!UV@p?%>l=dGd`&FA zoQ3tYIatq}hr>K&oaW4vY0ue33%PabG%qe+=9g8~d{b7=!_#NDd-e>q>kCM=u_D#p zjyM}z+|{+@U{0i&Es=(nEOqxG%f_C%f{lFN)K2Zn_3R3cVws%_3oUHf5EMa{iwDUL zE>dHZ>ElO&lMAu-j*>8nw{nCBRiiwtn&4se7h+viqz z`m-lGfv3fl4DCNgN!Bv92ZXcG*oMWnE@U}*5@BM2kDh^SzD3wM5^QCQuZcN+rWSG% z%~nGfJ52*rfA%$YnnqF%k`)rgBL5IM`4*sSNT{Ky+;5cP?8n|EYY8xQ!+f3*y0i3T z1l9Un8COm5H3o8X#&TajPAtjc%<^2ScWh;6N-70WiEK|@LfermvT-Vu1A+(H!q|cOnHdNUw0U-8$it#i70x^6n0Z=a1SSX~+0(}Y)j7YmvF)B@bPMrQ9 zL)4D}Ao4izc>$1HWrMP&5D`EC;9*%8_sXtuyY#9|gT!XK;qy(LTd|M&U6+_BzDDET zOVn&V$%cpwMb|f90e~y3*Ki^`i&NRzG6mWc7)8E&pxpD5>gY|JlOGztm;l#6D8C~c zS3d@T+@>&F1I_6w=uTHfXNH>W=9;J*VybE&wLZFYRHY_fe~t>Ft{yn(>J#MPfR~vm z7OL}c(bpls+6-3%T`cA*;izhi;V+ah`)WREu0AroSm5f8r;;-9W>zGa+v4!`T=f3m zKSAsN^=~-MP$Edzgb)K0$=uvHdYpHci}__)Ip19=;nx+Fytr_IwhaXwNlzq1Uz2DD zOAKd!g{jgU0xT@>GB76C$eIWPOY+@)xqG3Q=cUy$^{L8R%@*GfGEHqsHL=2LzB(a> zrUaRqfZoj6n5k)EtfG$6=hLL_$-~r|WS<~>jm+`T)FaT) z1b-bP0`*K;5)jR%)TIQOdtfwM5A9j{Xw1--^sz{b%)Xq(GQU7p2M4nwF`m=;ODNg6 zo}-JGkmc#imZWUDPF2X^tATUPG71PK@mN_m)w_#mIb6fN`UwUuUgwVJ`c5s^70xfR z5@8~3l8YEByLsMqpI3cPcsKBjm)#E~AY@di>{o1>s~Y?lyIuLO_Stal0R5Fc^i^~# z<}!uAs7iEkMK`xkAwd`M&_bqw?!Ks_3HsR5dSKMtRmaLi>SI>UI_}e6fwuq7E4asF>r9-)Cm|!zg2a_-6%0f5KKUi||eroFEdicl<6s|LrG5fbKarkPUoJo!`x0C6_ zzT`9>ojK2&a~JqSRV{yOXy(nib6j1whW%0DWZIhJpfm$FeRcF^e~GQ0Ccc&yIBIAU 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 W<)#*9e=*Jg0000 _donghuastreamSource; -const _donghuastreamVersion = "0.0.2"; -const _donghuastreamSourceCodeUrl = - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/src/en/donghuastream/donghuastream.dart"; -Source _donghuastreamSource = Source( - name: "DonghuaStream", - baseUrl: "https://donghuastream.org", - lang: "en", - typeSource: "single", - iconUrl: - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/src/en/donghuastream/icon.png", - sourceCodeUrl: _donghuastreamSourceCodeUrl, - version: _donghuastreamVersion, - itemType: ItemType.anime, -); diff --git a/dart/anime/src/en/gogoanime/gogoanime.dart b/dart/anime/src/en/gogoanime/gogoanime.dart deleted file mode 100644 index d9aff598..00000000 --- a/dart/anime/src/en/gogoanime/gogoanime.dart +++ /dev/null @@ -1,1149 +0,0 @@ -import 'package:mangayomi/bridge_lib.dart'; -import 'dart:convert'; - -class GogoAnime extends MProvider { - GogoAnime({required this.source}); - - MSource source; - - final Client client = Client(); - - @override - String get baseUrl => - getPreferenceValue(source.id, "override_baseurl_v${source.id}"); - - @override - Future getPopular(int page) async { - final res = - (await client.get(Uri.parse("$baseUrl/popular.html?page=$page"))).body; - - List animeList = []; - final urls = xpath(res, '//*[@class="img"]/a/@href'); - final names = xpath(res, '//*[@class="img"]/a/@title'); - final images = xpath(res, '//*[@class="img"]/a/img/@src'); - - for (var i = 0; i < names.length; i++) { - MManga anime = MManga(); - anime.name = names[i]; - anime.imageUrl = images[i]; - anime.link = urls[i]; - animeList.add(anime); - } - - return MPages(animeList, true); - } - - @override - Future getLatestUpdates(int page) async { - String url = baseUrl; - if (baseUrl.toLowerCase().contains("gogo")) { - url = url + "/?page=$page"; - } else { - url = url + "/home.html?page=$page"; - } - final res = (await client.get(Uri.parse(url))).body; - final document = parseHtml(res); - final elements = document.select("div.img a"); - List animeList = []; - - for (var element in elements) { - var anime = MManga(); - anime.name = element.attr("title"); - anime.imageUrl = element.selectFirst("img")?.attr("src") ?? ""; - final slug = substringBefore(element.attr("href"), "-episode-"); - anime.link = "/category/$slug"; - animeList.add(anime); - } - - return MPages(animeList, true); - } - - @override - Future search(String query, int page, FilterList filterList) async { - final filters = filterList.filters; - String filterStr = ""; - String url = ""; - - String genre = ""; - String recent = ""; - String season = ""; - - for (var filter in filters) { - if (filter.type == "SortFilter") { - final sort = filter.values[filter.state].value; - filterStr += "&sort=$sort"; - } else if (filter.type == "GenreFilter") { - final genre = (filter.state as List).where((e) => e.state).toList(); - if (genre.isNotEmpty) { - for (var st in genre) { - filterStr += "&genre[]=${st.value}"; - } - } - } else if (filter.type == "CountryFilter") { - final country = (filter.state as List).where((e) => e.state).toList(); - if (country.isNotEmpty) { - for (var st in country) { - filterStr += "&country[]=${st.value}"; - } - } - } else if (filter.type == "SeasonFilter") { - final season = (filter.state as List).where((e) => e.state).toList(); - if (season.isNotEmpty) { - for (var st in season) { - filterStr += "&season[]=${st.value}"; - } - } - } else if (filter.type == "YearFilter") { - final year = (filter.state as List).where((e) => e.state).toList(); - if (year.isNotEmpty) { - for (var st in year) { - filterStr += "&year[]=${st.value}"; - } - } - } else if (filter.type == "TypeFilter") { - final type = (filter.state as List).where((e) => e.state).toList(); - if (type.isNotEmpty) { - for (var st in type) { - filterStr += "&type[]=${st.value}"; - } - } - } else if (filter.type == "StatusFilter") { - final status = (filter.state as List).where((e) => e.state).toList(); - if (status.isNotEmpty) { - for (var st in status) { - filterStr += "&status[]=${st.value}"; - } - } - } else if (filter.type == "LanguageFilter") { - final language = (filter.state as List).where((e) => e.state).toList(); - if (language.isNotEmpty) { - for (var st in language) { - filterStr += "&language[]=${st.value}"; - } - } - } - if (filter.type == "GenreIFilter") { - genre = filter.values[filter.state].value; - } else if (filter.type == "RecentFilter") { - recent = filter.values[filter.state].value; - } else if (filter.type == "SeasonIFilter") { - season = filter.values[filter.state].value; - } - } - if (genre.isNotEmpty) { - url = "$baseUrl/genre/$genre?page=$page"; - } else if (recent.isNotEmpty) { - url = - "https://ajax.gogo-load.com/ajax/page-recent-release.html?page=$page&type=$recent"; - } else if (season.isNotEmpty) { - url = "$baseUrl/$season?page=$page"; - } else { - url = "$baseUrl/filter.html?keyword=$query$filterStr&page=$page"; - } - - final res = (await client.get(Uri.parse(url))).body; - - List animeList = []; - final urls = xpath(res, '//*[@class="img"]/a/@href'); - final names = xpath(res, '//*[@class="img"]/a/@title'); - final images = xpath(res, '//*[@class="img"]/a/img/@src'); - - for (var i = 0; i < names.length; i++) { - MManga anime = MManga(); - anime.name = names[i]; - anime.imageUrl = images[i]; - anime.link = urls[i]; - animeList.add(anime); - } - - return MPages(animeList, true); - } - - @override - Future getDetail(String url) async { - final statusList = [ - {"Ongoing": 0, "Completed": 1}, - ]; - - final res = (await client.get(Uri.parse("$baseUrl$url"))).body; - MManga anime = MManga(); - final status = xpath( - res, - '//*[@class="anime_info_body_bg"]/p[@class="type"][5]/text()', - ).first.replaceAll("Status: ", ""); - anime.description = - parseHtml( - res, - ).selectFirst("div.anime_info_body_bg > div.description")?.text ?? - ""; - anime.status = parseStatus(status, statusList); - anime.genre = xpath( - res, - '//*[@class="anime_info_body_bg"]/p[@class="type"][3]/text()', - ).first.replaceAll("Genre: ", "").split(","); - - final id = xpath(res, '//*[@id="movie_id"]/@value').first; - final urlEp = - "https://ajax.gogocdn.net/ajax/load-list-episode?ep_start=0&ep_end=4000&id=$id"; - - final resEp = (await client.get(Uri.parse(urlEp))).body; - - final epUrls = xpath(resEp, '//*[@id="episode_related"]/li/a/@href'); - final names = xpath( - resEp, - '//*[@id="episode_related"]/li/a/div[@class="name"]/text()', - ); - List episodes = []; - - for (var a in names) { - episodes.add("Episode ${substringAfterLast(a, ' ')}"); - } - List? episodesList = []; - for (var i = 0; i < episodes.length; i++) { - MChapter episode = MChapter(); - episode.name = episodes[i]; - episode.url = epUrls[i]; - episodesList.add(episode); - } - - anime.chapters = episodesList; - return anime; - } - - @override - Future> getVideoList(String url) async { - final res = (await client.get(Uri.parse("$baseUrl$url"))).body; - final serverUrls = xpath( - res, - '//*[@class="anime_muti_link"]/ul/li/a/@data-video', - ); - final serverNames = xpath( - res, - '//*[@class="anime_muti_link"]/ul/li/@class', - ); - List videos = []; - final hosterSelection = preferenceHosterSelection(source.id); - for (var i = 0; i < serverNames.length; i++) { - final name = serverNames[i]; - final url = serverUrls[i]; - List a = []; - if (hosterSelection.contains(name)) { - if (name.contains("anime")) { - a = await gogoCdnExtractor(url); - } else if (name.contains("vidcdn")) { - a = await gogoCdnExtractor(url); - } else if (name.contains("doodstream")) { - a = await doodExtractor(url); - } else if (name.contains("mp4upload")) { - a = await mp4UploadExtractor(url, null, "", ""); - } else if (name.contains("filelions")) { - a = await streamWishExtractor(url, "FileLions"); - } else if (name.contains("streamwish")) { - a = await streamWishExtractor(url, "StreamWish"); - } - videos.addAll(a); - } - } - - return sortVideos(videos, source.id); - } - - @override - List getFilterList() { - return [ - HeaderFilter("Advanced search"), - GroupFilter("GenreFilter", "Genre", [ - { - "type": "CheckBox", - "filter": {"name": "Action", "value": "action"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Adult Cast", "value": "adult-cast"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Adventure", "value": "adventure"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Anthropomorphic", "value": "anthropomorphic"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Avant Garde", "value": "avant-garde"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Boys Love", "value": "shounen-ai"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Cars", "value": "cars"}, - }, - { - "type": "CheckBox", - "filter": {"name": "CGDCT", "value": "cgdct"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Childcare", "value": "childcare"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Comedy", "value": "comedy"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Comic", "value": "comic"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Crime", "value": "crime"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Crossdressing", "value": "crossdressing"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Delinquents", "value": "delinquents"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Dementia", "value": "dementia"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Demons", "value": "demons"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Detective", "value": "detective"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Drama", "value": "drama"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Dub", "value": "dub"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Ecchi", "value": "ecchi"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Erotica", "value": "erotica"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Family", "value": "family"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Fantasy", "value": "fantasy"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Gag Humor", "value": "gag-humor"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Game", "value": "game"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Gender Bender", "value": "gender-bender"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Gore", "value": "gore"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Gourmet", "value": "gourmet"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Harem", "value": "harem"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Hentai", "value": "hentai"}, - }, - { - "type": "CheckBox", - "filter": {"name": "High Stakes Game", "value": "high-stakes-game"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Historical", "value": "historical"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Horror", "value": "horror"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Isekai", "value": "isekai"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Iyashikei", "value": "iyashikei"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Josei", "value": "josei"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Kids", "value": "kids"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Magic", "value": "magic"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Magical Sex Shift", "value": "magical-sex-shift"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Mahou Shoujo", "value": "mahou-shoujo"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Martial Arts", "value": "martial-arts"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Mecha", "value": "mecha"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Medical", "value": "medical"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Military", "value": "military"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Music", "value": "music"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Mystery", "value": "mystery"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Mythology", "value": "mythology"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Organized Crime", "value": "organized-crime"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Parody", "value": "parody"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Performing Arts", "value": "performing-arts"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Pets", "value": "pets"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Police", "value": "police"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Psychological", "value": "psychological"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Racing", "value": "racing"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Reincarnation", "value": "reincarnation"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Romance", "value": "romance"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Romantic Subtext", "value": "romantic-subtext"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Samurai", "value": "samurai"}, - }, - { - "type": "CheckBox", - "filter": {"name": "School", "value": "school"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Sci-Fi", "value": "sci-fi"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Seinen", "value": "seinen"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Shoujo", "value": "shoujo"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Shoujo Ai", "value": "shoujo-ai"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Shounen", "value": "shounen"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Showbiz", "value": "showbiz"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Slice of Life", "value": "slice-of-life"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Space", "value": "space"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Sports", "value": "sports"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Strategy Game", "value": "strategy-game"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Super Power", "value": "super-power"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Supernatural", "value": "supernatural"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Survival", "value": "survival"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Suspense", "value": "suspense"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Team Sports", "value": "team-sports"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Thriller", "value": "thriller"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Time Travel", "value": "time-travel"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Vampire", "value": "vampire"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Visual Arts", "value": "visual-arts"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Work Life", "value": "work-life"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Workplace", "value": "workplace"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Yaoi", "value": "yaoi"}, - }, - { - "type": "CheckBox", - "filter": {"name": "Yuri", "value": "yuri"}, - }, - ]), - GroupFilter("CountryFilter", "Country", [ - CheckBoxFilter("China", "5"), - CheckBoxFilter("Japan", "2"), - ]), - GroupFilter("SeasonFilter", "Season", [ - CheckBoxFilter("Fall", "fall"), - CheckBoxFilter("Summer", "summer"), - CheckBoxFilter("Spring", "spring"), - CheckBoxFilter("Winter", "winter"), - ]), - GroupFilter("YearFilter", "Year", [ - CheckBoxFilter("2024", "2024"), - CheckBoxFilter("2023", "2023"), - CheckBoxFilter("2022", "2022"), - CheckBoxFilter("2021", "2021"), - CheckBoxFilter("2020", "2020"), - CheckBoxFilter("2019", "2019"), - CheckBoxFilter("2018", "2018"), - CheckBoxFilter("2017", "2017"), - CheckBoxFilter("2016", "2016"), - CheckBoxFilter("2015", "2015"), - CheckBoxFilter("2014", "2014"), - CheckBoxFilter("2013", "2013"), - CheckBoxFilter("2012", "2012"), - CheckBoxFilter("2011", "2011"), - CheckBoxFilter("2010", "2010"), - CheckBoxFilter("2009", "2009"), - CheckBoxFilter("2008", "2008"), - CheckBoxFilter("2007", "2007"), - CheckBoxFilter("2006", "2006"), - CheckBoxFilter("2005", "2005"), - CheckBoxFilter("2004", "2004"), - CheckBoxFilter("2003", "2003"), - CheckBoxFilter("2002", "2002"), - CheckBoxFilter("2001", "2001"), - CheckBoxFilter("2000", "2000"), - CheckBoxFilter("1999", "1999"), - ]), - GroupFilter("LanguageFilter", "Language", [ - CheckBoxFilter("Sub & Dub", "subdub"), - CheckBoxFilter("Sub", "sub"), - CheckBoxFilter("Dub", "dub"), - ]), - GroupFilter("TypeFilter", "Type", [ - CheckBoxFilter("Movie", "3"), - CheckBoxFilter("TV", "1"), - CheckBoxFilter("OVA", "26"), - CheckBoxFilter("ONA", "30"), - CheckBoxFilter("Special", "2"), - CheckBoxFilter("Music", "32"), - ]), - GroupFilter("StatusFilter", "Status", [ - CheckBoxFilter("Not Yet Aired", "Upcoming"), - CheckBoxFilter("Ongoing", "Ongoing"), - CheckBoxFilter("Completed", "Completed"), - ]), - SelectFilter("SortFilter", "Sort by", 0, [ - SelectFilterOption("Name A-Z", "title_az"), - SelectFilterOption("Recently updated", "recently_updated"), - SelectFilterOption("Recently added", "recently_added"), - SelectFilterOption("Release date", "release_date"), - ]), - SeparatorFilter(), - HeaderFilter("Select sub-page"), - HeaderFilter("Note: Ignores search & other filters"), - SelectFilter("GenreIFilter", "Genre", 0, [ - { - "type": "SelectOption", - "filter": {"name": "", "value": ""}, - }, - { - "type": "SelectOption", - "filter": {"name": "Action", "value": "action"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Adult Cast", "value": "adult-cast"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Adventure", "value": "adventure"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Anthropomorphic", "value": "anthropomorphic"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Avant Garde", "value": "avant-garde"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Boys Love", "value": "shounen-ai"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Cars", "value": "cars"}, - }, - { - "type": "SelectOption", - "filter": {"name": "CGDCT", "value": "cgdct"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Childcare", "value": "childcare"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Comedy", "value": "comedy"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Comic", "value": "comic"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Crime", "value": "crime"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Crossdressing", "value": "crossdressing"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Delinquents", "value": "delinquents"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Dementia", "value": "dementia"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Demons", "value": "demons"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Detective", "value": "detective"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Drama", "value": "drama"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Dub", "value": "dub"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Ecchi", "value": "ecchi"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Erotica", "value": "erotica"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Family", "value": "family"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Fantasy", "value": "fantasy"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Gag Humor", "value": "gag-humor"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Game", "value": "game"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Gender Bender", "value": "gender-bender"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Gore", "value": "gore"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Gourmet", "value": "gourmet"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Harem", "value": "harem"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Hentai", "value": "hentai"}, - }, - { - "type": "SelectOption", - "filter": {"name": "High Stakes Game", "value": "high-stakes-game"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Historical", "value": "historical"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Horror", "value": "horror"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Isekai", "value": "isekai"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Iyashikei", "value": "iyashikei"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Josei", "value": "josei"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Kids", "value": "kids"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Magic", "value": "magic"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Magical Sex Shift", "value": "magical-sex-shift"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Mahou Shoujo", "value": "mahou-shoujo"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Martial Arts", "value": "martial-arts"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Mecha", "value": "mecha"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Medical", "value": "medical"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Military", "value": "military"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Music", "value": "music"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Mystery", "value": "mystery"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Mythology", "value": "mythology"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Organized Crime", "value": "organized-crime"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Parody", "value": "parody"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Performing Arts", "value": "performing-arts"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Pets", "value": "pets"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Police", "value": "police"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Psychological", "value": "psychological"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Racing", "value": "racing"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Reincarnation", "value": "reincarnation"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Romance", "value": "romance"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Romantic Subtext", "value": "romantic-subtext"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Samurai", "value": "samurai"}, - }, - { - "type": "SelectOption", - "filter": {"name": "School", "value": "school"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Sci-Fi", "value": "sci-fi"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Seinen", "value": "seinen"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Shoujo", "value": "shoujo"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Shoujo Ai", "value": "shoujo-ai"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Shounen", "value": "shounen"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Showbiz", "value": "showbiz"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Slice of Life", "value": "slice-of-life"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Space", "value": "space"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Sports", "value": "sports"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Strategy Game", "value": "strategy-game"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Super Power", "value": "super-power"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Supernatural", "value": "supernatural"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Survival", "value": "survival"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Suspense", "value": "suspense"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Team Sports", "value": "team-sports"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Thriller", "value": "thriller"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Time Travel", "value": "time-travel"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Vampire", "value": "vampire"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Visual Arts", "value": "visual-arts"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Work Life", "value": "work-life"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Workplace", "value": "workplace"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Yaoi", "value": "yaoi"}, - }, - { - "type": "SelectOption", - "filter": {"name": "Yuri", "value": "yuri"}, - }, - ]), - SelectFilter("RecentFilter", "Recent", 0, [ - SelectFilterOption("", ""), - SelectFilterOption("Recent Release", "1"), - SelectFilterOption("Recent Dub", "2"), - SelectFilterOption("Recent Chinese", "3"), - ]), - SelectFilter("SeasonIFilter", "Season", 0, [ - SelectFilterOption("", ""), - SelectFilterOption("Latest season", "new-season.html"), - SelectFilterOption("Summer 2024", "sub-category/summer-2024-anime"), - SelectFilterOption("Spring 2024", "sub-category/spring-2024-anime"), - SelectFilterOption("Winter 2024", "sub-category/winter-2024-anime"), - SelectFilterOption("Summer 2023", "sub-category/summer-2023-anime"), - SelectFilterOption("Spring 2023", "sub-category/spring-2023-anime"), - SelectFilterOption("Winter 2023", "sub-category/winter-2023-anime"), - SelectFilterOption("Fall 2022", "sub-category/fall-2022-anime"), - SelectFilterOption("Summer 2022", "sub-category/summer-2022-anime"), - SelectFilterOption("Spring 2022", "sub-category/spring-2022-anime"), - SelectFilterOption("Winter 2022", "sub-category/winter-2022-anime"), - SelectFilterOption("Fall 2021", "sub-category/fall-2021-anime"), - SelectFilterOption("Summer 2021", "sub-category/summer-2021-anime"), - SelectFilterOption("Spring 2021", "sub-category/spring-2021-anime"), - SelectFilterOption("Winter 2021", "sub-category/winter-2021-anime"), - SelectFilterOption("Fall 2020", "sub-category/fall-2020-anime"), - SelectFilterOption("Summer 2020", "sub-category/summer-2020-anime"), - SelectFilterOption("Spring 2020", "sub-category/spring-2020-anime"), - SelectFilterOption("Winter 2020", "sub-category/winter-2020-anime"), - SelectFilterOption("Fall 2019", "sub-category/fall-2019-anime"), - SelectFilterOption("Summer 2019", "sub-category/summer-2019-anime"), - SelectFilterOption("Spring 2019", "sub-category/spring-2019-anime"), - SelectFilterOption("Winter 2019", "sub-category/winter-2019-anime"), - SelectFilterOption("Fall 2018", "sub-category/fall-2018-anime"), - SelectFilterOption("Summer 2018", "sub-category/summer-2018-anime"), - SelectFilterOption("Spring 2018", "sub-category/spring-2018-anime"), - SelectFilterOption("Winter 2018", "sub-category/winter-2018-anime"), - SelectFilterOption("Fall 2017", "sub-category/fall-2017-anime"), - SelectFilterOption("Summer 2017", "sub-category/summer-2017-anime"), - SelectFilterOption("Spring 2017", "sub-category/spring-2017-anime"), - SelectFilterOption("Winter 2017", "sub-category/winter-2017-anime"), - SelectFilterOption("Fall 2016", "sub-category/fall-2016-anime"), - SelectFilterOption("Summer 2016", "sub-category/summer-2016-anime"), - SelectFilterOption("Spring 2016", "sub-category/spring-2016-anime"), - SelectFilterOption("Winter 2016", "sub-category/winter-2016-anime"), - SelectFilterOption("Fall 2015", "sub-category/fall-2015-anime"), - SelectFilterOption("Summer 2015", "sub-category/summer-2015-anime"), - SelectFilterOption("Spring 2015", "sub-category/spring-2015-anime"), - SelectFilterOption("Winter 2015", "sub-category/winter-2015-anime"), - SelectFilterOption("Fall 2014", "sub-category/fall-2014-anime"), - SelectFilterOption("Summer 2014", "sub-category/summer-2014-anime"), - SelectFilterOption("Spring 2014", "sub-category/spring-2014-anime"), - SelectFilterOption("Winter 2014", "sub-category/winter-2014-anime"), - ]), - ]; - } - - @override - List getSourcePreferences() { - return [ - EditTextPreference( - key: "override_baseurl_v${source.id}", - title: "Override BaseUrl", - summary: - "For temporary uses. Updating the extension will erase this setting.", - value: "https://anitaku.to", - dialogTitle: "Override BaseUrl", - dialogMessage: "Default: https://anitaku.to", - text: "https://anitaku.to", - ), - ListPreference( - key: "preferred_quality", - title: "Preferred quality", - summary: "", - valueIndex: 0, - entries: ["1080p", "720p", "480p", "360p"], - entryValues: ["1080", "720", "480", "360"], - ), - ListPreference( - key: "preferred_server", - title: "Preferred server", - summary: "", - valueIndex: 0, - entries: [ - "Gogostream", - "Vidstreaming", - "Doodstream", - "StreamWish", - "Mp4upload", - "FileLions", - ], - entryValues: [ - "Gogostream", - "Vidstreaming", - "Doodstream", - "StreamWish", - "Mp4upload", - "FileLions", - ], - ), - MultiSelectListPreference( - key: "hoster_selection", - title: "Enable/Disable Hosts", - summary: "", - entries: [ - "Gogostream", - "Vidstreaming", - "Doodstream", - "StreamWish", - "Mp4upload", - "FileLions", - ], - entryValues: [ - "vidcdn", - "anime", - "doodstream", - "streamwish", - "mp4upload", - "filelions", - ], - values: [ - "vidcdn", - "anime", - "doodstream", - "streamwish", - "mp4upload", - "filelions", - ], - ), - ]; - } - - List preferenceHosterSelection(int sourceId) { - return getPreferenceValue(sourceId, "hoster_selection"); - } - - List sortVideos(List videos, int sourceId) { - String quality = getPreferenceValue(sourceId, "preferred_quality"); - String server = getPreferenceValue(sourceId, "preferred_server"); - - videos.sort((MVideo a, MVideo b) { - int qualityMatchA = 0; - if (a.quality.contains(quality) && a.quality.contains(server)) { - qualityMatchA = 1; - } - int qualityMatchB = 0; - if (b.quality.contains(quality) && b.quality.contains(server)) { - qualityMatchB = 1; - } - if (qualityMatchA != qualityMatchB) { - return qualityMatchB - qualityMatchA; - } - - final regex = RegExp(r'(\d+)p'); - final matchA = regex.firstMatch(a.quality); - final matchB = regex.firstMatch(b.quality); - final int qualityNumA = int.tryParse(matchA?.group(1) ?? '0') ?? 0; - final int qualityNumB = int.tryParse(matchB?.group(1) ?? '0') ?? 0; - return qualityNumB - qualityNumA; - }); - - return videos; - } -} - -GogoAnime main(MSource source) { - return GogoAnime(source: source); -} diff --git a/dart/anime/src/en/gogoanime/icon.png b/dart/anime/src/en/gogoanime/icon.png deleted file mode 100644 index 29abaec0eb81ae15a78bd9fa68e7663fb7f8103d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2993 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 _gogoanimeSource; -const _gogoanimeVersion = "0.1.2"; -const _gogoanimeSourceCodeUrl = - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/src/en/gogoanime/gogoanime.dart"; -Source _gogoanimeSource = Source( - name: "Gogoanime", - baseUrl: "https://anitaku.to", - lang: "en", - typeSource: "single", - iconUrl: - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/src/en/gogoanime/icon.png", - sourceCodeUrl: _gogoanimeSourceCodeUrl, - version: _gogoanimeVersion, - itemType: ItemType.anime, -); diff --git a/dart/anime/src/en/kisskh/icon.png b/dart/anime/src/en/kisskh/icon.png deleted file mode 100644 index 5c440d80beb67f246591a19b6f9998f557522039..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3012 zcmV;#3p@0QP)-L?2!s%fBtUo=fdD~bj1UY|5UaGbG`y4`g~iJcD4&EX zP!Z8GXer9eq(bB+5(w`k2uU;#NJuL0u&>PS?7X`B`k`lMr*}5ld35*AE_14;cDDQW z>D&Kv?*E*7=5{w!r7BgaN>!>-m8w*wDpmQsiSYTjkuK6pAVtnc$@yLt8+Zv=Ip3w5 z2IvJ{-Tch#i%uGE+!fU2bVZmA1sh(U*4|=RS=Z*FRR=0NtR<$hHv>Y&U zj8V1$1fT-i{#Rz-H@>0kPRwqQMvnes0rb)U#T@J6d6gh2K@LY7A00by%Q7Ghn1dNX zDbVw^cmFzT(fIndJ25&yrjG%BxwKiX_YV=>TM00ZFecLa!*`!Jx1!WMT0-AKy=S>nrgex0|FW97Udd1 z1+-8gIk9MUl-3v+zUa}HB*cVa!2j2_tuOxPoUXB1+=83(U zH+V@Q-a3O)QQ-SR7t#X<7?K#^L1#-crO5O zVOe63ECc)@`OTr?vLH8sFBg1Srsw+a{ociZl70+#6MQ%34gLgcmt%m(;JXE!C*D8Q z6S0z)fD{3KNxVN4Rad_ZP*xF5($=N$*y;%JRNvMq6Vlu;w+8^zf_2*hytqD$VLJ6J zo)c$mlgV$NuO(&lc1JR8Qkv_&5(gljgx5X_vwnMkWV-jPww`&jl3X}7$?n4{tKJK9 zpiRl?nMBv%r;DS6bm{5LS@Q<;!o2?8C+bo2Q>$1qv|alxv_&YTT-M9!P?D1 z2WUdTrDxg0>7@<9EclmxDZ#iVE9?D{kYw5`7){zo)O>)hJan5K-`4T_8 zod+DHP1+DVwmOoxT~XlvCvC6n1y)lfOXtV<-dAI&qK_+{eXGU+KETZjVhCYxn|fl3 z^&bZSIMCL+#1(cQQrX+8F{Uw1Q=O!vTVR-i-G}<9>Zv!ve0N^AOWD(q)Pj!P_CSY1 zdw2edy$^Q;9H5SGws`E8b|z0S9J&s6sO(@k{4-Qxmk?J@i~1e}1*rp|e-@q_Js6MJ&$!(HOeo%7ATd z`Fd9gWs8cB0d|`MZ7ToX7&Ki((H|0UJJ|*d5x;^AEz}ar?W_`f4&rbbJ9{heM zr)eha6L7qhr{}eep}f&^`iW^Y)z+g2BrET0%j;V>C^;@-FR{ONPK*WT_T*(y$3-l{ zLCZ6+hdc%treOKM>hi!>6___O&i&U%QFbb%4-1qgiF&+KS0W{Nc!e`~3n95_L3j3a ziUAYrje#j7dGzr6(=sP ziWvO<0hiTp45WnQ@ZqRr}`4UTq1HcY*(SJCrwiE}xmmHnUpoZKi}p&o^?z zOZB|IH^61jHu2C0waj19$gOMYK}uHd3Ucu?&FqTW>8Z3NGA4YZ9+wPI;7#FD5{(I7 z{ZA+_@4sSJ0-4CyAx(+QNyQI!sJyVwHefIK0S%U1Y}b9P{U8k+!1oX8Z12=)iz_U9 zBf{P1#F*M_u%}z&wi&k4zi$gOzE*N#ec!FTqTce2dPI{B9^~WLpjMNokUZa52>5`v{Q50pIT;UfK}KOFOT>*v>>0ePE-R z?IOGBh4uNV>%#NmHkZdm*85xI3NP>0IeT0R!-9`HH1>3#Av@GyaO6tNEr%ud}eqi8ZrOht9vn9YM`<;Vz zT(gx8zQ(@35%knHyFj;edYo+?8t)#|`ODTYAysnQj2J&ZuM16)EIc_ubI8mDV2P-e zzEY2GzXwPOcRvwvl#~JPSQI53w7FmCnRKMTy0op}k(K#%qh(h`(G-caz}lx|f!Wfb zG5@3_Ee$3oL<|o12o6cXHzvoa2}riKYc%KZ1vJTpXC$-fqcRrEgLd0TE{bN`u3p%g*Y8uC z4gR^Xy>A{7fWQ>#EAKnzF@x+^fiTc0*Ea1bC0{ycQ$`G}RT5t|}n( zfroojo$S5)eBkp6Y#J*CKkq^F4X{aB- z4^QxYiUGJ(;2L@0dm95>Udrgs1g`R)cc=LexEsK`<@G}get8D)?9pUp7-pD(Uz`D? zn@^qc3;4N`bCt?e9>wmJD{$pce{!Wl~Pt5p92=9W2xU=9` getPopular(int page) async { - final res = - (await client.get( - Uri.parse( - "${source.baseUrl}/api/DramaList/List?page=$page&type=0&sub=0&country=0&status=0&order=1&pageSize=40", - ), - )).body; - final jsonRes = json.decode(res); - final datas = jsonRes["data"]; - List animeList = []; - - for (var data in datas) { - var anime = MManga(); - anime.name = data["title"]; - anime.imageUrl = data["thumbnail"] ?? ""; - anime.link = - "${source.baseUrl}/api/DramaList/Drama/${data["id"]}?isq=false"; - animeList.add(anime); - } - - int lastPage = jsonRes["totalCount"]; - int pages = jsonRes["page"]; - return MPages(animeList, pages < lastPage); - } - - @override - Future getLatestUpdates(int page) async { - final res = - (await client.get( - Uri.parse( - "${source.baseUrl}/api/DramaList/List?page=$page&type=0&sub=0&country=0&status=0&order=12&pageSize=40", - ), - )).body; - final jsonRes = json.decode(res); - final datas = jsonRes["data"]; - - List animeList = []; - - for (var data in datas) { - var anime = MManga(); - anime.name = data["title"]; - anime.imageUrl = data["thumbnail"] ?? ""; - anime.link = - "${source.baseUrl}/api/DramaList/Drama/${data["id"]}?isq=false"; - animeList.add(anime); - } - - int lastPage = jsonRes["totalCount"]; - int pages = jsonRes["page"]; - return MPages(animeList, pages < lastPage); - } - - @override - Future search(String query, int page, FilterList filterList) async { - final res = - (await client.get( - Uri.parse("${source.baseUrl}/api/DramaList/Search?q=$query&type=0"), - )).body; - final jsonRes = json.decode(res); - List animeList = []; - for (var data in jsonRes) { - var anime = MManga(); - anime.name = data["title"]; - anime.imageUrl = data["thumbnail"] ?? ""; - anime.link = - "${source.baseUrl}/api/DramaList/Drama/${data["id"]}?isq=false"; - animeList.add(anime); - } - return MPages(animeList, false); - } - - @override - Future getDetail(String url) async { - final statusList = [ - {"Ongoing": 0, "Completed": 1}, - ]; - final res = (await client.get(Uri.parse(url))).body; - var anime = MManga(); - final jsonRes = json.decode(res); - final status = jsonRes["status"] ?? ""; - anime.description = jsonRes["description"]; - anime.status = parseStatus(status, statusList); - anime.imageUrl = jsonRes["thumbnail"]; - var episodes = jsonRes["episodes"]; - String type = jsonRes["type"]; - final episodesCount = jsonRes["episodesCount"] as int; - final containsAnime = type.contains("Anime"); - final containsTVSeries = type.contains("TVSeries"); - final containsHollywood = type.contains("Hollywood"); - final containsMovie = type.contains("Movie"); - List? episodesList = []; - - for (var a in episodes) { - MChapter episode = MChapter(); - String number = (a["number"] as double).toString().replaceAll(".0", ""); - final id = a["id"]; - if (containsAnime || containsTVSeries) { - episode.name = "Episode $number"; - } else if (containsHollywood && episodesCount == 1 || containsMovie) { - episode.name = "Movie"; - } else if (containsHollywood && episodesCount > 1) { - episode.name = "Episode $number"; - } - episode.url = - "${source.baseUrl}/api/DramaList/Episode/$id.png?err=false&ts=&time="; - episodesList.add(episode); - } - - anime.chapters = episodesList; - return anime; - } - - @override - Future> getVideoList(String url) async { - final res = (await client.get(Uri.parse(url))).body; - final id = substringAfter(substringBefore(url, ".png"), "Episode/"); - final jsonRes = json.decode(res); - - final subRes = - (await client.get(Uri.parse("${source.baseUrl}/api/Sub/$id"))).body; - var jsonSubRes = json.decode(subRes); - List subtitles = []; - - for (var sub in jsonSubRes) { - final subUrl = sub["src"] as String; - final label = sub["label"]; - if (subUrl.endsWith("txt")) { - var subtitle = await getSubtitle(subUrl, label); - subtitles.add(subtitle); - } else { - var subtitle = MTrack(); - subtitle - ..label = label - ..file = subUrl; - subtitles.add(subtitle); - } - } - final videoUrl = jsonRes["Video"]; - var video = MVideo(); - video - ..url = videoUrl - ..originalUrl = videoUrl - ..quality = "kisskh" - ..subtitles = subtitles - ..headers = { - "referer": "https://kisskh.me/", - "origin": "https://kisskh.me", - }; - return [video]; - } - - Future getSubtitle(String subUrl, String subLang) async { - final response = await client.get( - Uri.parse(subUrl), - headers: {"referer": "https://kisskh.me/", "origin": "https://kisskh.me"}, - ); - final subtitleData = response.body; - String decrypted = "\n"; - for (String line in subtitleData.split('\n')) { - decrypted += "${decrypt(line.trim())}\n"; - } - var subtitle = MTrack(); - subtitle - ..label = subLang - ..file = decrypted; - return subtitle; - } - - String decrypt(String data) { - final key = utf8.decode([ - 56, - 48, - 53, - 54, - 52, - 56, - 51, - 54, - 52, - 54, - 51, - 50, - 56, - 55, - 54, - 51, - ]); - final iv = utf8.decode([ - 54, - 56, - 53, - 50, - 54, - 49, - 50, - 51, - 55, - 48, - 49, - 56, - 53, - 50, - 55, - 51, - ]); - return cryptoHandler(data, iv, key, false); - } -} - -KissKh main(MSource source) { - return KissKh(source: source); -} diff --git a/dart/anime/src/en/kisskh/source.dart b/dart/anime/src/en/kisskh/source.dart deleted file mode 100644 index 42142091..00000000 --- a/dart/anime/src/en/kisskh/source.dart +++ /dev/null @@ -1,17 +0,0 @@ -import '../../../../../model/source.dart'; - -Source get kisskhSource => _kisskhSource; -const _kisskhVersion = "0.0.7"; -const _kisskhSourceCodeUrl = - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/src/en/kisskh/kisskh.dart"; -Source _kisskhSource = Source( - name: "KissKH", - baseUrl: "https://kisskh.co", - lang: "en", - typeSource: "single", - iconUrl: - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/src/en/kisskh/icon.png", - sourceCodeUrl: _kisskhSourceCodeUrl, - version: _kisskhVersion, - itemType: ItemType.anime, -); diff --git a/dart/anime/src/en/nineanimetv/icon.png b/dart/anime/src/en/nineanimetv/icon.png deleted file mode 100644 index e57234ee0c6cbd70c221ed2a2f4e729b0fc5d3ac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6623 zcmcJU^;Z<$)5oa=k#6adZjff_lx{&lSm_1nT5?ekSVEDMSbC9k>28oNmrm&p>5?y> z|KWLlxOdK+Ge69k`#!I^XC_)tM~&b)&2uy~Gy)BEWrHVs_jH_}VL#mvbq@I_gYIRZ zrifNCO1JyuU^ysgE1;nv6Y%bB08c)yySkYd8XBqhe+PZpp3xr-joMp7S;5HP>M#q( zpS<_(*UI@9RY&G?me+Wk7%?Dp<-#Zea+RMC3O$i|vlPuNVn)g;#HSqLES%b_BqYjQ z3XoI=^Dv`Hug3eU=HY>@hJ|$PBmT|hgfZFr>deNa)`!s+*DVYX2ow`-lg6!^<8Sw( zD5e|a@InsSJ1Q800n4(v$D)+(zQ*PCjXWiLbAZ3j@pG2CPuChL5)1G6zYHvXB}Ym^ zZIJ=$rqwrclu`MFDsVg$mEknmuXufFiatL@K8LsC-RUt{T?nrH#mV~k^YXhE;L_!k zKk`(LyKEM-=20=6g{#6`Q%ax?CnCbRiyw0bOULfG0O+L2wUDA%w-$6NfWOXYq>fa> zn#vLL`B0R05=l5dGv49(<38sZUt$P$*}&$nR>9qCrFE9tLt^MS^_k34mxIn1+Z{Em%#bQ)3?DS+}*op^v;|>^4#v zv^=m;nD7pG_{{b4r8ylJV+`!jTjD*%p_XOAz!HDFu+~(rMK1$mx;!8FqVVVH3y*?( zjj<(N+C+q5E>MlmCapxFF$x%l!6nNAou59`g`#(^IrcKwGeu0(XDBwR?5;iQHVPS3 zIUvZFGRSCnt5OOg&2i-+jDO!LVvG$p9T$z+Q!d|Id}&TWbsmz!or9>3S6+T0S1na#1Y1LxvO8~pHI|z6B+o}-HCHD)e!bA~G1a^o17$w}y6cYfbdswo#-Q4Nq38yp=(#G>eK zFPcYcE)#<1iw)}ZsT;2@)DQ-*ml-@hdEk8dw+#<9IGnHT{pzKmtz9@>{?^dSDqEuK z8Ur5H>VaZIaaWv&K&-9NeA=3*EvM?)d{9;&!>5!8(tkA81a<0|O9e{POMYRGH%D}& zsDR^j3M^=G4u)Tdf1m@NbYSLfX75)t$4{4;v6{yUoHWgT#8CPH{`i%g0Tj%lDUYU~ z1rhRI+2Q$NSZ}}PxZD3*>&^_$G1*0(QLHC&rP=*;*r(x0qeJSc)cLxyH_A1O)gcd%ri=3Y~r|r@cdjYSccs@Outs)H_dq;>L04bj@|=>feua5 z!@*FdT$Zx2u{popuQZIK5iMA_*@g@Js~n7onQgz_BN-DS}0cGS1pBn z1T=FI;YuwcTmpIM$YFyqWM7GY3fEE3S5x5UoyO>zXa>mrYaV-{?ui@K94&63!L^!QNMZulhFLzoPh4;{K{4Q+I!RmY)prR5lDtXH1lu z3Ls4b`bS0zVf;<%L>&YSGHKcVYq-Em_bFpjmgr*y58O)e?73kW4@IWj*l*0YJZar3@m>CD?YDR(5@TI8dx4h3DS*g zI-S~$S*D6gaci{sdBFtIYPjVD23?;R+^p=p%*!k5#aZP~b3J;7uS@}YW?X8by%PTM zqxQ=2^X)OuTFLc2VBZM+=r%1mx$SL;$Vol1%tg;iBD5WL79Sr!jfoTmPou6phTp<* z&%uBD`s2~2r?j)DE>SuRGZK4C%c#QbfVC($0w=VnJX)=XM3QT+c?Z7X^rZYc z*M&*O(0hGuWPS~K?dILpF_qe|(?lL1_-sTxZ}WToG6Y7+`-aKf9AQyP8AmOm`ba0^ z?!SXR>=E?u2>_bkICM=0Z$i%})KHCH4ii$T-JgkmcR(>!VCSEM`eLccY4_W(-ybbD zzVbbIGr>|~TA7{Qq|DEFh4Oe;U0r?Qb$|X__u@7%vpIHaB;$ABaVr8xNq;DTkWk{^ zbb-dVox9_9)7!VgdivLEFo8WGyv6OksnY!`8Vofy8+&{9&F$^qmF@pZ;NK9XcpmT; zmdo3(R0fJm3o4pA-WTq-*QuT4g{>vw*JGm>YEBoEKyQCHnk=1>{CR@Bo%>Jzdy+YP zD!%*5m%> zSa@|4i0^EcJ#i@?0S_^Edv7bk3Itjn6OVswXqF>>zPB{d*oaBt)xdy5d?5FDuS7y} zBqHY4{!qt%xnJ3CRsZEl$;|(HfjdUB_a{oe`%c3@C2LOZMrs0FNe@@N5=m2!5xZn26H&{CPFH>FYfH{3H%iSv zBzp?=IXUjZo(a@(wBpl@yng+vnlfqIS%?pZubd{84;rx*d%N$h*Aw=qz-h_sWKtdd z(joW$kgFxXN7{$X&W{AuD17DJxYY;$XCq<8XZ@@RJCtED;|kr81iKGcD+nqp|J+Y1 z5hQf zKLrKPBdARnl1$1s$l|P>pRiW?gxy@F&yyqKE4=1x9%)7PE(>+q2U&k6H3gDye z7Ry$p^ubkV#%+u{Z6i0KgcYxtnokzJ#-dXsf6_2{Cm(m?U!SR)=B;z`G=wrx1%_R| zv(Bkq^vM|A>#RVno1O0yWhf5;i$mc+yDY~61*`UeA&ChCR;KY_AI4!@Gm1qAc(7{d z!$qoNW8W~2FSf|Qa0eCPN=r@7dU$&*$s~2!#@DZ3^EPQ5knaLElR;y^h6KAmo2l=n zE2(>BeDXNLS|IaL50Pfksf@uJvI|T2%o}F z^AI+iQOFQ;?a96h3q2gnG!a79yUej%j=J|!m_`AQNvNpQG*kJLn_iSGdVjl{%P8jZ z-%58_Y?3MjbOMdur2s0U=&ij?*@XMdi5kF48tr4TEX`S$uF`Dgo_nH3$KLX_)-(FH zX+idFlzGijF__nO!bbOXPg;IG;;4&$wm_XetD7aIqM@OYr(%TAp|^}mCct`b35~~# zFkHrv4Kh28pA9|%^HZej=c_)om@=zYb8#MY1B=;VJ(6aMGrBASmPNni0FEV(U-Y*; zlZqu=><)~iTdgihz6?_nl4j^v&!AP!M@^cHo4!YjT>pBd006)%n=Y&ex7<&2bFG5i z$&dKpZJ0nCG2fMhy>MO#22{?anD_ok{=L$Rm|&6>W3!VO?((vkl+^dGqrQj!U^#Y@ z8Tp3?YNzR<)+Y0QjL!5=pRk^QSXRbMBW&9r+BG;ZFmcvoU!1mGlI;78&NAqPJh1x?qE;*C_ei=Cht!;N|T5q{Kv)_y%kRsq5v!PHB)ponh|MBCjZDMrW;q@C^1UalDYZ z*2Pq}W_VY8gJmPm;| z0E*g%V>(`o2%k#8D`RG}9^ol`Z)1Qnt8|eBv_iEQF_Ujz zZV^~B~CN-Dc*JU#nGw^iSEe9_A-yIiezbPI;;wm zr0pPdQx7^UkZvoo|J5+)@98=lEYtRpNUC#lC>53xD9AlXIUE)cAM=V@6*fd)3==e` zE{+$$oJ!bn6k6A>3*ffgexCV+&Fn;k$R-ujl$ zDvusXEof-0r$PJh)RIBR_*G~u6-%7HL6K#`#G3luhhL!aI=-V-Bumg33dfpPU+Vpm z(*?t&q7N79d0eZca2J0~hLc)UMgc{}zDs7NXCrP7r^DaB@m}i{_>iZ&MVO0wc2tzG zjbDU&cAQHTN~7F*iW$uaJ)Lx# zPUvub%HY7D+}jw~Dr~MhBPB&up!Ga)LEw2&>u{=A;7`ca5#OZ+rig*4aYVePSQov7 zyYG=)$(C(?%^8tmzsagXk)lt!)08>H==w`Kr)K+BD>LWb6 zGXvL$+pgZ$sSxy74zs`ACfdZ)24PMC4h;Tjo>70lqkF8Pw_nbKmp<$e4~OY)^S4eR zbQzJ`G%`6=7HycxxGa4Qn3Mihqv#5+Sk-;fp?0NT@{Dr9GZm8^6l)aR#Yw+u9CCly zlFI;k_JSD8*MP|F;_|gMw2#Z@r=`k6ezry1lWUBcltIN`zJ~T0r;9kmdqblM>7~ZY z%&N7-&9W&YXwx1K@#6=C(MAD$_Nx{n@;$RJh`+TmnnZZm_F^%c`Tm&|y1>-}240c} zRw!_kB+B7%U*HQC()YLdptV^VA`7hGi!-P$!)<#*wlX|6Gk&B!y_J`m z^01&gnNmAVi6c+nc~rx8`z&G*QMDmk9v0Qivobq{|H{G0v`GOP`7>76EE*lKDFY6XsH7N#Ftu}jtHRUWt%mE(9B5hqc5S!hzEFTAzNkzI zDN5sv+J^9}zRZ`W16QQ~v2fic%RZ%cy)|L5f-FzjjVoi8dfh(}9UOyHLw%22E6ihXMcb`2 z(vNb^5ld#Xn#FO8Zs%L{(p;>`kK^T*fa+NhHMX20$RYRHmj28KWlB6~^V$apA1@th zD1UDfzX79o`wGj7LfUzwK0C88?%6cefzna%{h8(tLL>Ut@mQlukb~eOJowTq7%1gJEWrEnnWYIMbZoZuZEF__zfwAL7x0-&QnMW4 zi#?<{a_vG8*X9~|^!BZ2~Ky>)l!9D{JUP57*r7#X3lV?oHZK=<2f z33?qSwDhq7%4-~%>}rgeEu4y0-52}K*H#V$9TTO*|8s9?#-Y0Uo)!~g-(Nw01DUdh z^N#Pmd6;@8B}|cu>4o#NfTE}hq%;!oS`9FSZs;EOLC@?&!`sPp9>iUj`tOr2-B^J* z<9AKnMX9Wi8|T(#+$73^`IIr!v-McIu|;_fFW>#&+;+WG#s9jxp%Wd0MW8ksMp7)4 zEo-TBI`5a8GQoj3#iYVkVimEJ0haNXJYo8xf1p|i67L+KO_;Ec-~YTmSp7&OOB|RD zFofd}&}<0hVm^&YayVgPY@rU4Zyc~f?xXY5&)acBe~&YK+bs+X$-B1zM+jciuEVXg z%n;?;DCC@{qr<#nOhTomTiZ?1ZgIRt@!+DZskJ^Hb)V0nZ3w%n$y5oC@*g|&O5@Ve zX@!paB)-U9myi-Hl+pey$#r5}->7UIbyYkeHHIlH&>D!QWpnY8a}f%#9o`Lm8r#rk z_AhB`Q2+gG79pd(5oeCdBZkRsw}96@<})4nrc7+d5XNd8&h#enZA~R+FR9nMKp(3D z29EU7t(-IY*lFji`HFA%`+55(qug=ntdmlv>ZNB2N^J>^7~N4bL-&?iMf&KWYGT?m zmTIv9e_7SyWjNT(XsktTm`OJ7fSU-~)AU(UuJKV6ASp3FMM;#kP2Z=<@0?=3+bO%- z+kXCzr#D-w*^ttpg3lNp5P2~)B7gE680@6L@yGdG5JcWw#!j!oRAOJo8y6MSh%_QE zo$B}OAHBHd*3|!TJ6jb-(}rh;-=lDMd3bR=gD--I>w(W(1ud)?#K35O!>w6cGsi7U zen%|^Pt)L6R;HR$)a%HSSvwPgHk`QxcZrTgEDr<+4_MAC#vi{Gc7og2oK+pIu`J2uqCnkK)662C9y3Mf!`E%( zFA8K!SaZZ7tN2pB>e^A4AlgISyR6Hi_jM-7r=(sAiM%CI*UxhQL#XCWUun;D@(G7p zws|hAOd*Gp%!Gu9 z_ht13nl-%{E**w9N)wF6AW1hWBusiZOs#rP6!xbbAg*XgZo1}_GF z@2n)LtVLy7)z{`jw1*AFM_(Rl=h~g2wmcVLf1Q>lGUK@M>;k;0}awtP#T~cgr zWXyDlOSX#<1QozuaoS@2sAFWWNG{s>LMr16!7NvYBuw_Aj3a+ICza097i=9OlGSAM z3eJsftKrRE1bIi8k-mAW#9%~ofH7(Lzaw5P5uZflDC|(@B465RL?qw8KBU~KCygN`+;cUe*{uL3bdNxA9Rc4HB|9ITIY z03TBqu^4prgrr2RekW&~%ckk6L*U8*OVUsG+VLWrlGsG*$2X8eB=9?;q=W3iIh9{k z;^4~W0TY+<#CRKS5ekz7)h~VW+EO8JXEubF*uo{ci&5PW^Fbi)=x`U`1}=ULkSmO&~_`B!` getPopular(int page) async { - final res = - (await client.get( - Uri.parse("${source.baseUrl}/filter?sort=all&page=$page"), - )).body; - return parseAnimeList(res); - } - - @override - Future getLatestUpdates(int page) async { - final res = - (await client.get( - Uri.parse( - "${source.baseUrl}/filter?sort=recently_updated&page=$page", - ), - )).body; - return parseAnimeList(res); - } - - @override - Future search(String query, int page, FilterList filterList) async { - final filters = filterList.filters; - String url = "${source.baseUrl}/filter?keyword=$query"; - - for (var filter in filters) { - if (filter.type == "GenreFilter") { - final genre = (filter.state as List).where((e) => e.state).toList(); - url += "${ll(url)}genre="; - if (genre.isNotEmpty) { - for (var st in genre) { - url += "${st.value}"; - if (genre.length > 1) { - url += "%2C"; - } - } - if (genre.length > 1) { - url = substringBeforeLast(url, '%2C'); - } - } - } else if (filter.type == "SeasonFilter") { - final season = (filter.state as List).where((e) => e.state).toList(); - url += "${ll(url)}season="; - if (season.isNotEmpty) { - for (var st in season) { - url += "${st.value}"; - if (season.length > 1) { - url += "%2C"; - } - } - if (season.length > 1) { - url = substringBeforeLast(url, '%2C'); - } - } - } else if (filter.type == "YearFilter") { - final year = (filter.state as List).where((e) => e.state).toList(); - url += "${ll(url)}year="; - if (year.isNotEmpty) { - for (var st in year) { - url += "${st.value}"; - if (year.length > 1) { - url += "%2C"; - } - } - if (year.length > 1) { - url = substringBeforeLast(url, '%2C'); - } - } - } else if (filter.type == "TypeFilter") { - final type = (filter.state as List).where((e) => e.state).toList(); - url += "${ll(url)}type="; - if (type.isNotEmpty) { - for (var st in type) { - url += "${st.value}"; - if (type.length > 1) { - url += "%2C"; - } - } - if (type.length > 1) { - url = substringBeforeLast(url, '%2C'); - } - } - } else if (filter.type == "StatusFilter") { - final status = filter.values[filter.state].value; - url += "${ll(url)}status=$status"; - } else if (filter.type == "LanguageFilter") { - final language = (filter.state as List).where((e) => e.state).toList(); - url += "${ll(url)}language="; - if (language.isNotEmpty) { - for (var st in language) { - url += "${st.value}"; - if (language.length > 1) { - url += "%2C"; - } - } - if (language.length > 1) { - url = substringBeforeLast(url, '%2C'); - } - } - } else if (filter.type == "SortFilter") { - final sort = filter.values[filter.state].value; - url += "${ll(url)}sort=$sort"; - } - } - - final res = (await client.get(Uri.parse("$url&page=$page"))).body; - return parseAnimeList(res); - } - - @override - Future getDetail(String url) async { - final statusList = [ - {"Currently Airing": 0, "Finished Airing": 1}, - ]; - - final res = (await client.get(Uri.parse("${source.baseUrl}$url"))).body; - MManga anime = MManga(); - final document = parseHtml(res); - final infoElement = document.selectFirst("div.film-infor"); - final status = - infoElement.xpathFirst( - '//div[contains(text(),"Status:")]/following-sibling::div/span/text()', - ) ?? - ""; - anime.status = parseStatus(status, statusList); - anime.description = - infoElement.selectFirst("div.film-description > p")?.text ?? ""; - anime.author = - infoElement.xpathFirst( - '//div[contains(text(),"Studios:")]/following-sibling::div/a/text()', - ) ?? - ""; - - anime.genre = infoElement.xpath( - '//div[contains(text(),"Genre:")]/following-sibling::div/a/text()', - ); - final id = parseHtml(res).selectFirst("div[data-id]").attr("data-id"); - - final resEp = - (await client.get( - Uri.parse("${source.baseUrl}/ajax/episode/list/$id"), - )).body; - final html = json.decode(resEp)["html"]; - - List? episodesList = []; - - final epsElements = parseHtml(html).select("a"); - for (var epElement in epsElements) { - final id = epElement.attr('data-id'); - - final title = epElement.attr('title') ?? ""; - - final epNum = epElement.attr('data-number'); - - MChapter episode = MChapter(); - episode.name = "Episode $epNum $title"; - episode.url = id; - episodesList.add(episode); - } - anime.chapters = episodesList.reversed.toList(); - return anime; - } - - @override - Future> getVideoList(String url) async { - final res = - (await client.get( - Uri.parse("${source.baseUrl}/ajax/episode/servers?episodeId=$url"), - )).body; - - final html = json.decode(res)["html"]; - - final serverElements = parseHtml(html).select("div.server-item"); - - List videos = []; - final hosterSelection = preferenceHosterSelection(source.id); - final typeSelection = preferenceTypeSelection(source.id); - for (var serverElement in serverElements) { - final name = serverElement.text; - final id = serverElement.attr("data-id"); - final subDub = serverElement.attr("data-type"); - final res = - (await client.get( - Uri.parse("${source.baseUrl}/ajax/episode/sources?id=$id"), - )).body; - final epUrl = json.decode(res)["link"]; - List a = []; - - if (hosterSelection.contains(name) && typeSelection.contains(subDub)) { - if (name.contains("Vidstreaming")) { - a = await rapidCloudExtractor(epUrl, "Vidstreaming - $subDub"); - } else if (name.contains("Vidcloud")) { - a = await rapidCloudExtractor(epUrl, "Vidcloud - $subDub"); - } - videos.addAll(a); - } - } - - return sortVideos(videos, source.id); - } - - MPages parseAnimeList(String res) { - final elements = parseHtml(res).select("div.film_list-wrap > div"); - List animeList = []; - for (var element in elements) { - MManga anime = MManga(); - anime.name = element.selectFirst("div.film-detail > h3 > a").text; - anime.imageUrl = element.selectFirst(" div.film-poster > img").getSrc; - anime.link = element.selectFirst("div.film-detail > h3 > a").getHref; - animeList.add(anime); - } - - return MPages(animeList, true); - } - - Future> rapidCloudExtractor(String url, String name) async { - final serverUrl = ['https://megacloud.tv', 'https://rapid-cloud.co']; - - final serverType = - url.startsWith('https://megacloud.tv') || - url.startsWith('https://megacloud.club') - ? 0 - : 1; - final sourceUrl = [ - '/embed-2/ajax/e-1/getSources?id=', - '/ajax/embed-6-v2/getSources?id=', - ]; - final sourceSpliter = ['/e-1/', '/embed-6-v2/']; - final id = url.split(sourceSpliter[serverType]).last.split('?').first; - final resServer = - (await client.get( - Uri.parse('${serverUrl[serverType]}${sourceUrl[serverType]}$id'), - headers: {"X-Requested-With": "XMLHttpRequest"}, - )).body; - final encrypted = getMapValue(resServer, "encrypted"); - String videoResJson = ""; - List videos = []; - if (encrypted == "true") { - final ciphered = getMapValue(resServer, "sources"); - List> indexPairs = await generateIndexPairs(serverType); - var password = ''; - String ciphertext = ciphered; - int index = 0; - for (List item in json.decode(json.encode(indexPairs))) { - int start = item.first + index; - int end = start + item.last; - String passSubstr = ciphered.substring(start, end); - password += passSubstr; - ciphertext = ciphertext.replaceFirst(passSubstr, ""); - index += item.last; - } - videoResJson = decryptAESCryptoJS(ciphertext, password); - } else { - videoResJson = json.encode( - (json.decode(resServer)["sources"] as List>), - ); - } - - String masterUrl = - ((json.decode(videoResJson) as List>) - .first)['file']; - String type = - ((json.decode(videoResJson) as List>) - .first)['type']; - - final tracks = - (json.decode(resServer)['tracks'] as List) - .where((e) => e['kind'] == 'captions' ? true : false) - .toList(); - List subtitles = []; - - for (var sub in tracks) { - try { - MTrack subtitle = MTrack(); - subtitle - ..label = sub["label"] - ..file = sub["file"]; - subtitles.add(subtitle); - } catch (_) {} - } - - if (type == "hls") { - final masterPlaylistRes = (await client.get(Uri.parse(masterUrl))).body; - - for (var it in substringAfter( - masterPlaylistRes, - "#EXT-X-STREAM-INF:", - ).split("#EXT-X-STREAM-INF:")) { - final quality = - "${substringBefore(substringBefore(substringAfter(substringAfter(it, "RESOLUTION="), "x"), ","), "\n")}p"; - - String videoUrl = substringBefore(substringAfter(it, "\n"), "\n"); - - if (!videoUrl.startsWith("http")) { - videoUrl = - "${masterUrl.split("/").sublist(0, masterUrl.split("/").length - 1).join("/")}/$videoUrl"; - } - - MVideo video = MVideo(); - video - ..url = videoUrl - ..originalUrl = videoUrl - ..quality = "$name - $quality" - ..subtitles = subtitles; - videos.add(video); - } - } else { - MVideo video = MVideo(); - video - ..url = masterUrl - ..originalUrl = masterUrl - ..quality = "$name - Default" - ..subtitles = subtitles; - videos.add(video); - } - return videos; - } - - Future>> generateIndexPairs(int serverType) async { - final jsPlayerUrl = [ - "https://megacloud.tv/js/player/a/prod/e1-player.min.js", - "https://rapid-cloud.co/js/player/prod/e6-player-v2.min.js", - ]; - final scriptText = - (await client.get(Uri.parse(jsPlayerUrl[serverType]))).body; - - final switchCode = scriptText.substring( - scriptText.lastIndexOf('switch'), - scriptText.indexOf('=partKey'), - ); - - List indexes = []; - for (var variableMatch - in RegExp(r'=(\w+)').allMatches(switchCode).toList()) { - final regex = RegExp( - ',${(variableMatch as RegExpMatch).group(1)}=((?:0x)?([0-9a-fA-F]+))', - ); - Match? match = regex.firstMatch(scriptText); - - if (match != null) { - String value = match.group(1); - if (value.contains("0x")) { - indexes.add(int.parse(substringAfter(value, "0x"), radix: 16)); - } else { - indexes.add(int.parse(value)); - } - } - } - - return chunked(indexes, 2); - } - - List> chunked(List list, int size) { - List> chunks = []; - for (int i = 0; i < list.length; i += size) { - int end = list.length; - if (i + size < list.length) { - end = i + size; - } - chunks.add(list.sublist(i, end)); - } - return chunks; - } - - @override - List getFilterList() { - return [ - GroupFilter("GenreFilter", "Genre", [ - CheckBoxFilter("Action", "1"), - CheckBoxFilter("Adventure", "2"), - CheckBoxFilter("Cars", "3"), - CheckBoxFilter("Comedy", "4"), - CheckBoxFilter("Dementia", "5"), - CheckBoxFilter("Demons", "6"), - CheckBoxFilter("Drama", "8"), - CheckBoxFilter("Ecchi", "9"), - CheckBoxFilter("Fantasy", "10"), - CheckBoxFilter("Game", "11"), - CheckBoxFilter("Harem", "35"), - CheckBoxFilter("Historical", "13"), - CheckBoxFilter("Horror", "14"), - CheckBoxFilter("Isekai", "44"), - CheckBoxFilter("Josei", "43"), - CheckBoxFilter("Kids", "15"), - CheckBoxFilter("Magic", "16"), - CheckBoxFilter("Martial Arts", "17"), - CheckBoxFilter("Mecha", "18"), - CheckBoxFilter("Military", "38"), - CheckBoxFilter("Music", "19"), - CheckBoxFilter("Mystery", "7"), - CheckBoxFilter("Parody", "20"), - CheckBoxFilter("Police", "39"), - CheckBoxFilter("Psychological", "40"), - CheckBoxFilter("Romance", "22"), - CheckBoxFilter("Samurai", "21"), - CheckBoxFilter("School", "23"), - CheckBoxFilter("Sci-Fi", "24"), - CheckBoxFilter("Seinen", "42"), - CheckBoxFilter("Shoujo", "25"), - CheckBoxFilter("Shoujo Ai", "26"), - CheckBoxFilter("Shounen", "27"), - CheckBoxFilter("Shounen Ai", "28"), - CheckBoxFilter("Slice of Life", "36"), - CheckBoxFilter("Space", "29"), - CheckBoxFilter("Sports", "30"), - CheckBoxFilter("Super Power", "31"), - CheckBoxFilter("Supernatural", "37"), - CheckBoxFilter("Thriller", "41"), - CheckBoxFilter("Vampire", "32"), - ]), - GroupFilter("SeasonFilter", "Season", [ - CheckBoxFilter("Fall", "3"), - CheckBoxFilter("Summer", "2"), - CheckBoxFilter("Spring", "1"), - CheckBoxFilter("Winter", "4"), - ]), - GroupFilter("YearFilter", "Year", [ - CheckBoxFilter("2024", "2024"), - CheckBoxFilter("2023", "2023"), - CheckBoxFilter("2022", "2022"), - CheckBoxFilter("2021", "2021"), - CheckBoxFilter("2020", "2020"), - CheckBoxFilter("2019", "2019"), - CheckBoxFilter("2018", "2018"), - CheckBoxFilter("2017", "2017"), - CheckBoxFilter("2016", "2016"), - CheckBoxFilter("2015", "2015"), - CheckBoxFilter("2014", "2014"), - CheckBoxFilter("2013", "2013"), - CheckBoxFilter("2012", "2012"), - CheckBoxFilter("2011", "2011"), - CheckBoxFilter("2010", "2010"), - CheckBoxFilter("2009", "2009"), - CheckBoxFilter("2008", "2008"), - CheckBoxFilter("2007", "2007"), - CheckBoxFilter("2006", "2006"), - CheckBoxFilter("2005", "2005"), - CheckBoxFilter("2004", "2004"), - CheckBoxFilter("2003", "2003"), - CheckBoxFilter("2002", "2002"), - CheckBoxFilter("2001", "2001"), - ]), - SelectFilter("SortFilter", "Sort by", 0, [ - SelectFilterOption("All", "all"), - SelectFilterOption("Default", "default"), - SelectFilterOption("Recently Added", "recently_added"), - SelectFilterOption("Recently Updated", "recently_updated"), - SelectFilterOption("Score", "score"), - SelectFilterOption("Name A-Z", "name_az"), - SelectFilterOption("Released Date", "released_date"), - SelectFilterOption("Most Watched", "most_watched"), - ]), - GroupFilter("TypeFilter", "Type", [ - CheckBoxFilter("Movie", "1"), - CheckBoxFilter("TV Series", "2"), - CheckBoxFilter("OVA", "3"), - CheckBoxFilter("ONA", "4"), - CheckBoxFilter("Special", "5"), - CheckBoxFilter("Music", "6"), - ]), - SelectFilter("StatusFilter", "Status", 0, [ - SelectFilterOption("All", "all"), - SelectFilterOption("Finished Airing", "1"), - SelectFilterOption("Currently Airing", "2"), - SelectFilterOption("Not yet aired", "3"), - ]), - GroupFilter("LanguageFilter", "Language", [ - CheckBoxFilter("Sub", "sub"), - CheckBoxFilter("Dub", "dub"), - ]), - ]; - } - - @override - List getSourcePreferences() { - return [ - ListPreference( - key: "preferred_quality", - title: "Preferred Quality", - summary: "", - valueIndex: 1, - entries: ["1080p", "720p", "480p", "360p"], - entryValues: ["1080", "720", "480", "360"], - ), - ListPreference( - key: "preferred_server", - title: "Preferred server", - summary: "", - valueIndex: 0, - entries: ["Vidstreaming", "VidCloud"], - entryValues: ["Vidstreaming", "VidCloud"], - ), - ListPreference( - key: "preferred_type", - title: "Preferred Type", - summary: "", - valueIndex: 0, - entries: ["Sub", "Dub"], - entryValues: ["sub", "dub"], - ), - MultiSelectListPreference( - key: "hoster_selection", - title: "Enable/Disable Hosts", - summary: "", - entries: ["Vidstreaming", "VidCloud"], - entryValues: ["Vidstreaming", "Vidcloud"], - values: ["Vidstreaming", "Vidcloud"], - ), - MultiSelectListPreference( - key: "type_selection", - title: "Enable/Disable Types", - summary: "", - entries: ["Sub", "Dub"], - entryValues: ["sub", "dub"], - values: ["sub", "dub"], - ), - ]; - } - - List sortVideos(List videos, int sourceId) { - String quality = getPreferenceValue(sourceId, "preferred_quality"); - String server = getPreferenceValue(sourceId, "preferred_server"); - String type = getPreferenceValue(sourceId, "preferred_type"); - videos.sort((MVideo a, MVideo b) { - int qualityMatchA = 0; - - if (a.quality.contains(quality) && - a.quality.toLowerCase().contains(type.toLowerCase()) && - a.quality.toLowerCase().contains(server.toLowerCase())) { - qualityMatchA = 1; - } - int qualityMatchB = 0; - if (b.quality.contains(quality) && - b.quality.toLowerCase().contains(type.toLowerCase()) && - b.quality.toLowerCase().contains(server.toLowerCase())) { - qualityMatchB = 1; - } - if (qualityMatchA != qualityMatchB) { - return qualityMatchB - qualityMatchA; - } - - final regex = RegExp(r'(\d+)p'); - final matchA = regex.firstMatch(a.quality); - final matchB = regex.firstMatch(b.quality); - final int qualityNumA = int.tryParse(matchA?.group(1) ?? '0') ?? 0; - final int qualityNumB = int.tryParse(matchB?.group(1) ?? '0') ?? 0; - return qualityNumB - qualityNumA; - }); - return videos; - } - - List preferenceHosterSelection(int sourceId) { - return getPreferenceValue(sourceId, "hoster_selection"); - } - - List preferenceTypeSelection(int sourceId) { - return getPreferenceValue(sourceId, "type_selection"); - } - - String ll(String url) { - if (url.contains("?")) { - return "&"; - } - return "?"; - } -} - -NineAnimeTv main(MSource source) { - return NineAnimeTv(source: source); -} diff --git a/dart/anime/src/en/nineanimetv/source.dart b/dart/anime/src/en/nineanimetv/source.dart deleted file mode 100644 index 216597cc..00000000 --- a/dart/anime/src/en/nineanimetv/source.dart +++ /dev/null @@ -1,17 +0,0 @@ -import '../../../../../model/source.dart'; - -Source get nineanimetv => _nineanimetv; -const _nineanimetvVersion = "0.0.55"; -const _nineanimetvCodeUrl = - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/src/en/nineanimetv/nineanimetv.dart"; -Source _nineanimetv = Source( - name: "9AnimeTv", - baseUrl: "https://9animetv.to", - lang: "en", - typeSource: "single", - iconUrl: - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/src/en/nineanimetv/icon.png", - sourceCodeUrl: _nineanimetvCodeUrl, - version: _nineanimetvVersion, - itemType: ItemType.anime, -); diff --git a/dart/anime/src/en/uhdmovies/icon.png b/dart/anime/src/en/uhdmovies/icon.png deleted file mode 100644 index 073e44f12dec67ba315fb678518fbc08d8a66f32..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3627 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 _uhdmoviesSource; -const _uhdmoviesVersion = "0.0.5"; -const _uhdmoviesSourceCodeUrl = - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/src/en/uhdmovies/uhdmovies.dart"; -Source _uhdmoviesSource = Source( - name: "UHD Movies", - baseUrl: "https://uhdmovies.fans", - lang: "en", - typeSource: "single", - iconUrl: - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/src/en/uhdmovies/icon.png", - sourceCodeUrl: _uhdmoviesSourceCodeUrl, - version: _uhdmoviesVersion, - itemType: ItemType.anime, -); diff --git a/dart/anime/src/en/uhdmovies/uhdmovies.dart b/dart/anime/src/en/uhdmovies/uhdmovies.dart deleted file mode 100644 index 1f6f598f..00000000 --- a/dart/anime/src/en/uhdmovies/uhdmovies.dart +++ /dev/null @@ -1,255 +0,0 @@ -import 'package:mangayomi/bridge_lib.dart'; -import 'dart:convert'; - -class UHDMovies extends MProvider { - UHDMovies({required this.source}); - - MSource source; - - final Client client = Client(); - - @override - bool get supportsLatest => false; - - @override - String get baseUrl => getPreferenceValue(source.id, "pref_domain_new"); - - @override - Future getPopular(int page) async { - final res = (await client.get(Uri.parse("$baseUrl/page/$page"))).body; - return animeFromElement(res); - } - - @override - Future getLatestUpdates(int page) async { - return MPages([], false); - } - - @override - Future search(String query, int page, FilterList filterList) async { - final res = - (await client.get( - Uri.parse("$baseUrl/page/$page/?s=${query.replaceAll(" ", "+")}"), - )).body; - return animeFromElement(res); - } - - @override - Future getDetail(String url) async { - url = getUrlWithoutDomain(url); - final res = (await client.get(Uri.parse("$baseUrl${url}"))).body; - MManga anime = MManga(); - final description = xpath(res, '//pre/span/text()'); - if (description.isNotEmpty) { - anime.description = description.first; - } - anime.status = MStatus.ongoing; - final episodesTitles = xpath( - res, - '//*[contains(@style, "center") or contains(@class, "maxbutton")]/a[contains(@class, "maxbutton") or contains(@href, "?sid=")]/text()', - ); - final episodesUrls = xpath( - res, - '//*[contains(@style, "center") or contains(@class, "maxbutton")]/a[contains(@class, "maxbutton") or contains(@href, "?sid=")]/@href', - ); - bool isSeries = false; - if (episodesTitles.first.contains("Episode") || - episodesTitles.first.contains("Zip") || - episodesTitles.first.contains("Pack")) { - isSeries = true; - } - List? episodesList = []; - if (!isSeries) { - List moviesTitles = []; - moviesTitles = xpath( - res, - '//*[contains(@style, "center") or contains(@class, "maxbutton")]/parent::p//preceding-sibling::p[contains(@style, "center")]/text()', - ); - List titles = []; - if (moviesTitles.isEmpty) { - moviesTitles = xpath(res, '//p[contains(@style, "center")]/text()'); - } - for (var title in moviesTitles) { - if (title.isNotEmpty && - !title.contains('Download') && - !title.contains('Note:') && - !title.contains('Copyright')) { - titles.add(title.split('[').first.trim()); - } - } - for (var i = 0; i < titles.length; i++) { - final title = titles[i]; - final quality = RegExp(r'\d{3,4}p').firstMatch(title)?.group(0) ?? ""; - final url = episodesUrls[i]; - MChapter ep = MChapter(); - ep.name = title; - ep.url = url; - ep.scanlator = quality; - episodesList.add(ep); - } - } else { - List seasonTitles = []; - final episodeTitles = xpath( - res, - '//*[contains(@style, "center") or contains(@class, "maxbutton")]/parent::p//preceding-sibling::p[contains(@style, "center") and not(text()^="Episode")]/text()', - ); - List titles = []; - for (var title in episodeTitles) { - if (title.isNotEmpty) { - titles.add(title.split('[').first.trim()); - } - } - int number = 0; - for (var i = 0; i < episodesTitles.length; i++) { - final episode = episodesTitles[i]; - final episodeUrl = episodesUrls[i]; - if (!episode.contains("Zip") || !episode.contains("Pack")) { - if (episode == "Episode 1" && seasonTitles.contains("Episode 1")) { - number++; - } else if (episode == "Episode 1") { - seasonTitles.add(episode); - } - final season = - RegExp(r'S(\d{2})').firstMatch(titles[number])?.group(1) ?? ""; - final quality = - RegExp(r'\d{3,4}p').firstMatch(titles[number])?.group(0) ?? ""; - MChapter ep = MChapter(); - ep.name = "Season $season $episode $quality"; - ep.url = episodeUrl; - ep.scanlator = quality; - episodesList.add(ep); - } - } - } - anime.chapters = episodesList.reversed.toList(); - return anime; - } - - @override - Future> getVideoList(String url) async { - final res = await getMediaUrl(url); - return await extractVideos(res); - } - - @override - List getSourcePreferences() { - return [ - EditTextPreference( - key: "pref_domain_new", - title: "Currently used domain", - summary: "", - value: "https://uhdmovies.fans", - dialogTitle: "Currently used domain", - dialogMessage: "", - text: "https://uhdmovies.fans", - ), - ]; - } - - Future> extractVideos(String url) async { - List videos = []; - for (int type = 1; type < 3; type++) { - url = url.replaceAll("/file/", "/wfile/") + "?type=$type"; - final res = (await client.get(Uri.parse(url))).body; - final links = xpath(res, '//div[@class="mb-4"]/a/@href'); - for (int i = 0; i < links.length; i++) { - final link = links[i]; - String decodedLink = link; - if (!link.contains("workers.dev")) { - decodedLink = utf8.decode( - base64Url.decode(substringAfter(link, "download?url=")), - ); - } - MVideo video = MVideo(); - video - ..url = decodedLink - ..originalUrl = decodedLink - ..quality = "CF $type Worker ${i + 1}"; - videos.add(video); - } - } - return videos; - } - - Future getMediaUrl(String url) async { - String res = ""; - String host = ""; - if (url.contains("?sid=")) { - final finalUrl = await redirectorBypasser(url); - host = Uri.parse(finalUrl).host; - res = (await client.get(Uri.parse(finalUrl))).body; - } else if (url.contains("r?key=")) { - res = (await client.get(Uri.parse(url))).body; - host = Uri.parse(url).host; - } else { - return ""; - } - final path = substringBefore(substringAfter(res, "replace(\""), "\""); - if (path == "/404") return ""; - return "https://$host$path"; - } - - Future redirectorBypasser(String url) async { - final res = (await client.get(Uri.parse(url))).body; - String lastDoc = await recursiveDoc(url, res); - final js = xpath(lastDoc, '//script[contains(text(), "/?go=")]/text()'); - if (js.isEmpty) return ""; - String script = js.first; - String nextUrl = substringBefore( - substringAfter(script, "\"href\",\""), - '"', - ); - if (!nextUrl.contains("http")) return ""; - String cookieName = substringAfter(nextUrl, "go="); - String cookieValue = substringBefore( - substringAfter(script, "'$cookieName', '"), - "'", - ); - final response = - (await client.get( - Uri.parse(nextUrl), - headers: {"referer": url, "Cookie": "$cookieName=$cookieValue"}, - )).body; - - final lastRes = parseHtml( - response, - ).selectFirst("meta[http-equiv]").attr("content"); - return substringAfter(lastRes, "url="); - } - - MPages animeFromElement(String res) { - List animeList = []; - final urls = xpath(res, '//*[@class="entry-image"]/a/@href'); - final names = xpath(res, '//*[@class="entry-image"]/a/@title'); - final images = xpath(res, '//*[@class="entry-image"]/a/img/@src'); - - for (var i = 0; i < names.length; i++) { - MManga anime = MManga(); - anime.name = names[i].replaceAll("Download", ""); - anime.imageUrl = images[i]; - anime.link = urls[i]; - animeList.add(anime); - } - final nextPage = xpath(res, '//a[@class="next page-numbers"]/@href'); - return MPages(animeList, nextPage.isNotEmpty); - } - - Future recursiveDoc(String url, String html) async { - final urlR = xpath(html, '//form[@id="landing"]/@action'); - if (urlR.isEmpty) return html; - final name = xpath(html, '//input/@name').first; - final value = xpath(html, '//input/@value').first; - final body = {"$name": value}; - final response = - (await client.post( - Uri.parse(urlR.first), - headers: {"referer": url}, - body: body, - )).body; - return recursiveDoc(url, response); - } -} - -UHDMovies main(MSource source) { - return UHDMovies(source: source); -} diff --git a/dart/anime/src/en/vumeto/icon.png b/dart/anime/src/en/vumeto/icon.png deleted file mode 100644 index 56be717a4016c671e355a71cb104057a986e82b7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7549 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 SZ!3y^aOAMXq1*#bq5lKY-6}-@ diff --git a/dart/anime/src/en/vumeto/source.dart b/dart/anime/src/en/vumeto/source.dart deleted file mode 100644 index bb7fb1d9..00000000 --- a/dart/anime/src/en/vumeto/source.dart +++ /dev/null @@ -1,19 +0,0 @@ -// from https://github.com/MiraiEnoki/anymex-extensions/blob/main/dart/anime/src/en/vumeto - -import '../../../../../model/source.dart'; - -Source get vumetoSource => _vumetoSource; -const _vumetoVersion = "0.0.55"; -const _vumetoSourceCodeUrl = - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/src/en/vumeto/vumeto.dart"; -Source _vumetoSource = Source( - name: "Vumeto", - baseUrl: "https://vumeto.com", - lang: "en", - typeSource: "single", - iconUrl: - "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/src/en/vumeto/icon.png", - sourceCodeUrl: _vumetoSourceCodeUrl, - version: _vumetoVersion, - itemType: ItemType.anime, -); diff --git a/dart/anime/src/en/vumeto/vumeto.dart b/dart/anime/src/en/vumeto/vumeto.dart deleted file mode 100644 index 03ef6bff..00000000 --- a/dart/anime/src/en/vumeto/vumeto.dart +++ /dev/null @@ -1,336 +0,0 @@ -import 'package:mangayomi/bridge_lib.dart'; -import 'dart:convert'; - -class Vumeto extends MProvider { - Vumeto({required this.source}); - - MSource source; - - final Client client = Client(); - - @override - bool get supportsLatest => true; - - @override - Map get headers => { - "Cookie": - "_ga=GA1.1.2064759276.1741681027; _ga_5HMNDC3ZE4=GS1.1.1741824276.8.1.1741824749.0.0.0", - "User-Agent": - "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36", - "Referer": "https://vumeto.com/", - }; - - @override - Future getPopular(int page) async { - final url = 'https://vumeto.com/most-popular'; - final resp = await client.get(Uri.parse(url)); - - final document = parseHtml(resp.body); - - return MPages(scrapeAnimeList(document), false); - } - - @override - Future getLatestUpdates(int page) async { - final url = 'https://vumeto.com/recently-updated'; - final resp = await client.get(Uri.parse(url)); - - final document = parseHtml(resp.body); - - return MPages(scrapeAnimeList(document), false); - } - - @override - Future search(String query, int page, FilterList filterList) async { - final url = 'https://vumeto.com/search?q=$query'; - final resp = await client.get(Uri.parse(url)); - - final document = parseHtml(resp.body); - - return MPages(scrapeAnimeList(document), false); - } - - String fixUrl(String encodedUrl) { - return encodedUrl - .split('url=') - .last - .split('&w') - .first - .replaceAll('%3A', ':') - .replaceAll('%2F', '/') - .replaceAll('%3F', '?') - .replaceAll('%3D', '=') - .replaceAll('%26', '&'); - } - - List scrapeAnimeList(MDocument document) { - List? animeElements = document.getElementsByClassName( - 'relative group border-0', - ); - List results = []; - - if (animeElements != null) { - for (var anime in animeElements) { - String? title = anime.selectFirst('h3')?.text ?? ''; - String? animeUrl = anime.selectFirst('a')?.attr('href') ?? ''; - String? imageUrl = anime.selectFirst('img')?.attr('src') ?? ''; - - MManga manga = MManga(); - manga.name = title; - manga.link = - "https://vumeto.com/watch/" + - animeUrl.replaceAll('/info/', '').split('/').first + - '?ep=1'; - manga.imageUrl = fixUrl(imageUrl.split('url=').last); - - results.add(manga); - } - } - return results; - } - - @override - Future getDetail(String url) async { - final statusList = [ - {"Releasing": 0, "Finished": 1}, - ]; - - final uri = Uri.parse(url); - final resp = await client.get(uri, headers); - final document = parseHtml(resp.body); - - final description = - document.selectFirst("meta[name='description']").attr("content") ?? ''; - - MStatus status = MStatus.unknown; - final statusStart = resp.body.indexOf( - ":", - resp.body.indexOf("\\\"status\\\""), - ); - final statusEnd = resp.body.indexOf("\\\",", statusStart); - if (statusStart != -1 && statusEnd != -1) { - final rawStatus = resp.body.substring(statusStart + 1, statusEnd); - status = parseStatus(rawStatus.replaceAll("\\\"", ""), statusList); - } - - final genresStart = resp.body.indexOf( - "[", - resp.body.indexOf("\\\"genres\\\":"), - ); - final genresEnd = resp.body.indexOf("]", genresStart); - var genres = []; - if (genresStart != -1 && genresEnd != -1) { - final genreLinks = resp.body - .substring(genresStart + 1, genresEnd) - .split(","); - genres = genreLinks.map((String e) => e.replaceAll("\\\"", "")).toList(); - } - - List chapters = []; - final scripts = document.getElementsByTagName("script"); - - String jsonData = ""; - for (var script in scripts!) { - if (script.text!.contains("episodesData")) { - final regex = RegExp( - r'self\.__next_f\.push\(\[1,".*?",null,(.*?)\]\)', - dotAll: true, - ); - final match = regex.firstMatch(script.text!); - - if (match != null && match.groupCount >= 1) { - String cleaned = match.group(1)!.replaceAll(r'\', ''); - - jsonData = cleaned.substring(0, cleaned.length - 3); - break; - } else { - print("Regex did not match."); - } - } - } - Map parsedData = json.decode(jsonData); - List episodesData = parsedData['episodesData']; - for (var ep in episodesData) { - MChapter ch = MChapter(); - final number = - (ep?['episodeNo'] ?? episodesData.indexOf(ep) + 1).toString(); - - ch.name = "Episode $number"; - - ch.url = url.split('?').first + '?ep=$number'; - - if (!chapters.any((c) => c.name == ch.name)) { - chapters.add(ch); - } - } - - MManga result = MManga(); - result.description = description; - result.status = status; - result.genre = genres; - result.chapters = chapters.reversed.toList(); - - return result; - } - - String stripTags(String htmlString) { - final RegExp exp = RegExp( - r'<[^>]*>', - multiLine: true, - caseSensitive: false, - ); - return htmlString.replaceAll(exp, '').trim(); - } - - @override - Future> getVideoList(String url) async { - try { - final resp = await client.get(Uri.parse(url), headers); - - final document = parseHtml(resp.body); - - final scripts = document.getElementsByTagName("script"); - if (scripts.isEmpty) { - print("No