From 46806a76b0ba6914fe86adff2833b2e087a179e3 Mon Sep 17 00:00:00 2001 From: kodjomoustapha <107993382+kodjodevf@users.noreply.github.com> Date: Thu, 14 Dec 2023 16:00:50 +0100 Subject: [PATCH] New sources DataLifeEngine : Wiflix (FR), French Anime (FR) --- .../datalifeengine/datalifeengine.dart | 336 ++++++++++++++++++ anime/multisrc/datalifeengine/sources.dart | 19 + .../src/frenchanime/frenchanime-v0.0.1.dart | 13 + .../datalifeengine/src/frenchanime/icon.png | Bin 0 -> 5173 bytes .../datalifeengine/src/wiflix/icon.png | Bin 0 -> 4635 bytes .../datalifeengine/src/wiflix/wiflix.dart | 13 + anime/source_generator.dart | 4 +- 7 files changed, 384 insertions(+), 1 deletion(-) create mode 100644 anime/multisrc/datalifeengine/datalifeengine.dart create mode 100644 anime/multisrc/datalifeengine/sources.dart create mode 100644 anime/multisrc/datalifeengine/src/frenchanime/frenchanime-v0.0.1.dart create mode 100644 anime/multisrc/datalifeengine/src/frenchanime/icon.png create mode 100644 anime/multisrc/datalifeengine/src/wiflix/icon.png create mode 100644 anime/multisrc/datalifeengine/src/wiflix/wiflix.dart diff --git a/anime/multisrc/datalifeengine/datalifeengine.dart b/anime/multisrc/datalifeengine/datalifeengine.dart new file mode 100644 index 00000000..a10a1814 --- /dev/null +++ b/anime/multisrc/datalifeengine/datalifeengine.dart @@ -0,0 +1,336 @@ +import 'package:mangayomi/bridge_lib.dart'; +import 'dart:convert'; + +class DataLifeEngine extends MProvider { + DataLifeEngine(); + + @override + bool get supportsLatest => false; + + @override + Future getPopular(MSource source, int page) async { + final data = {"url": "${source.baseUrl}${getPath(source)}page/$page"}; + final res = await http('GET', json.encode(data)); + return animeFromElement(res, source.baseUrl); + } + + @override + Future getLatestUpdates(MSource source, int page) async { + return MPages([], false); + } + + @override + Future search( + MSource source, String query, int page, FilterList filterList) async { + final filters = filterList.filters; + final baseUrl = source.baseUrl; + String res = ""; + if (query.isNotEmpty) { + if (query.length < 4) return MPages([], false); + final headers = { + "Host": Uri.parse(baseUrl).host, + "Origin": baseUrl, + "Referer": "$baseUrl/" + }; + final cleanQuery = query.replaceAll(" ", "+"); + if (page == 1) { + res = await http( + 'POST', + json.encode({ + "url": "$baseUrl?do=search&subaction=search&story=$cleanQuery", + "headers": headers + })); + } else { + res = await http( + 'POST', + json.encode({ + "url": + "$baseUrl?do=search&subaction=search&search_start=$page&full_search=0&result_from=11&story=$cleanQuery", + "headers": headers + })); + } + } 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 http('GET', json.encode({"url": url})); + } + + return animeFromElement(res, baseUrl); + } + + @override + Future getDetail(MSource source, String url) async { + final data = {"url": url}; + String res = await http('GET', json.encode(data)); + 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 eps = xpath(res, + '//*[@class="hostsblock"]/div/a[contains(@href,"https")]/parent::div/@class'); + if (eps.isNotEmpty) { + for (var i = 0; i < eps.length; i++) { + final epUrls = xpath(res, + '//*[@class="hostsblock"]/div[@class="${eps[i]}"]/a[contains(@href,"https")]/@href'); + MChapter ep = MChapter(); + ep.name = "Episode ${i + 1}"; + ep.url = epUrls.join(",").replaceAll("/vd.php?u=", ""); + ep.scanlator = eps[i].contains('vf') ? 'VF' : 'VOSTFR'; + episodesList.add(ep); + } + } else { + anime.status = MStatus.completed; + final epUrls = xpath(res, + '//*[contains(@class,"filmlinks")]/div/a[contains(@href,"https")]/@href'); + MChapter ep = MChapter(); + ep.name = "Film"; + ep.url = epUrls.join(",").replaceAll("/vd.php?u=", ""); + episodesList.add(ep); + } + } + + anime.chapters = episodesList.reversed.toList(); + return anime; + } + + @override + Future> getVideoList(MSource source, String url) async { + List videos = []; + final sUrls = url.split(','); + for (var sUrl in sUrls) { + List a = []; + if (sUrl.contains("dood")) { + a = await doodExtractor(sUrl, "DoodStream"); + } else if (sUrl.contains("voe.sx")) { + a = await voeExtractor(sUrl, "Voe"); + } else if (sUrl.contains("streamvid") || + sUrl.contains("guccihide") || + sUrl.contains("streamhide")) { + 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); + } + videos.addAll(a); + } + return videos; + } + + MPages animeFromElement(String res, String baseUrl) { + final htmls = querySelectorAll(res, + selector: "div#dle-content > div.mov", + typeElement: 1, + attributes: "", + typeRegExp: 0); + List animeList = []; + for (var html in htmls) { + 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 http('GET', json.encode({"url": url})); + final masterUrl = substringBefore( + substringAfter( + substringAfter(substringAfter(evalJs(res), "sources:"), "file:\""), + "src:\""), + '"'); + final masterPlaylistRes = + await http('GET', json.encode({"url": masterUrl})); + 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 http('GET', json.encode({"url": url})); + final js = xpath(res, '//script[contains(text(), "m3u8")]/text()'); + if (js.isEmpty) { + return []; + } + final masterUrl = + substringBefore(substringAfter(evalJs(js.first), "{file:\""), "\"}"); + final masterPlaylistRes = + await http('GET', json.encode({"url": masterUrl})); + 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 http('GET', json.encode({"url": url})); + 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]; + } + + String getPath(MSource source) { + if (source.name == "French Anime") return "/animes-vostfr/"; + return "/serie-en-streaming/"; + } + + @override + List getFilterList(MSource source) { + 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() { + return DataLifeEngine(); +} diff --git a/anime/multisrc/datalifeengine/sources.dart b/anime/multisrc/datalifeengine/sources.dart new file mode 100644 index 00000000..59f23442 --- /dev/null +++ b/anime/multisrc/datalifeengine/sources.dart @@ -0,0 +1,19 @@ +import '../../../model/source.dart'; +import '../../src/fr/franime/source.dart'; +import 'src/wiflix/wiflix.dart'; + +const _datalifeengineVersion = "0.0.1"; +const _datalifeengineSourceCodeUrl = + "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/multisrc/datalifeengine/datalifeengine-v$_datalifeengineVersion.dart"; + +List get datalifeengineSourcesList => _datalifeengineSourcesList; +List _datalifeengineSourcesList = [ +//French Anime (FR) + franimeSource, +//Wiflix (FR) + wiflixSource, +] + .map((e) => e + ..sourceCodeUrl = _datalifeengineSourceCodeUrl + ..version = _datalifeengineVersion) + .toList(); diff --git a/anime/multisrc/datalifeengine/src/frenchanime/frenchanime-v0.0.1.dart b/anime/multisrc/datalifeengine/src/frenchanime/frenchanime-v0.0.1.dart new file mode 100644 index 00000000..bf4a8613 --- /dev/null +++ b/anime/multisrc/datalifeengine/src/frenchanime/frenchanime-v0.0.1.dart @@ -0,0 +1,13 @@ +import '../../../../../model/source.dart'; + +Source get frenchanimeSource => _frenchanimeSource; + +Source _frenchanimeSource = Source( + name: "French Anime", + baseUrl: "https://french-anime.com", + lang: "fr", + typeSource: "datalifeengine", + isManga: false, + iconUrl: + "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/multisrc/datalifeengine/src/frenchanime/icon.png", +); diff --git a/anime/multisrc/datalifeengine/src/frenchanime/icon.png b/anime/multisrc/datalifeengine/src/frenchanime/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..62591a8ef47880bf6256785139b2d40fcc92fa0b GIT binary patch literal 5173 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 bPNJ5c(6DOu(zgS@11a?HKG3N~U}F9Ue#+&E literal 0 HcmV?d00001 diff --git a/anime/multisrc/datalifeengine/src/wiflix/icon.png b/anime/multisrc/datalifeengine/src/wiflix/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..3317e74495c1ae9d09c24688d963c4e4e25a8cf3 GIT binary patch literal 4635 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 R%8~#8002ovPDHLkV1n}Z&2az# literal 0 HcmV?d00001 diff --git a/anime/multisrc/datalifeengine/src/wiflix/wiflix.dart b/anime/multisrc/datalifeengine/src/wiflix/wiflix.dart new file mode 100644 index 00000000..7dac63a0 --- /dev/null +++ b/anime/multisrc/datalifeengine/src/wiflix/wiflix.dart @@ -0,0 +1,13 @@ +import '../../../../../model/source.dart'; + +Source get wiflixSource => _wiflixSource; + +Source _wiflixSource = Source( + name: "Wiflix", + baseUrl: "https://wiflix.voto", + lang: "fr", + typeSource: "datalifeengine", + isManga: false, + iconUrl: + "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/multisrc/datalifeengine/src/wiflix/icon.png", +); diff --git a/anime/source_generator.dart b/anime/source_generator.dart index 3e4a2b3a..8ef1722a 100644 --- a/anime/source_generator.dart +++ b/anime/source_generator.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'dart:developer'; import 'dart:io'; import '../model/source.dart'; +import 'multisrc/datalifeengine/sources.dart'; import 'multisrc/dopeflix/sources.dart'; import 'multisrc/zorotheme/sources.dart'; import 'src/ar/okanime/source.dart'; @@ -32,7 +33,8 @@ void main() { aniwave, ...dopeflixSourcesList, animesaturn, - uhdmoviesSource + uhdmoviesSource, + ...datalifeengineSourcesList ]; final List> jsonList = _sourcesList.map((source) => source.toJson()).toList();