From 8d3b79251c67c9bdb47b62403fafb38e115f2754 Mon Sep 17 00:00:00 2001 From: kodjomoustapha <107993382+kodjodevf@users.noreply.github.com> Date: Thu, 4 Jan 2024 17:24:59 +0100 Subject: [PATCH] New source: AnimeWorld India (MULTI) --- anime/source_generator.dart | 4 +- .../all/animeworldindia/animeworldindia.dart | 411 ++++++++++++++++++ anime/src/all/animeworldindia/icon.png | Bin 0 -> 7536 bytes anime/src/all/animeworldindia/sources.dart | 32 ++ 4 files changed, 446 insertions(+), 1 deletion(-) create mode 100644 anime/src/all/animeworldindia/animeworldindia.dart create mode 100644 anime/src/all/animeworldindia/icon.png create mode 100644 anime/src/all/animeworldindia/sources.dart diff --git a/anime/source_generator.dart b/anime/source_generator.dart index 7ba2e412..7caa06d6 100644 --- a/anime/source_generator.dart +++ b/anime/source_generator.dart @@ -5,6 +5,7 @@ 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/ar/okanime/source.dart'; import 'src/de/aniflix/source.dart'; import 'src/en/aniwave/source.dart'; @@ -46,7 +47,8 @@ void main() { yomoviesSource, animesamaSource, nineanimetv, - aniflix + aniflix, + ...animeworldindiaSourcesList ]; final List> jsonList = _sourcesList.map((source) => source.toJson()).toList(); diff --git a/anime/src/all/animeworldindia/animeworldindia.dart b/anime/src/all/animeworldindia/animeworldindia.dart new file mode 100644 index 00000000..fd532d31 --- /dev/null +++ b/anime/src/all/animeworldindia/animeworldindia.dart @@ -0,0 +1,411 @@ +import 'package:mangayomi/bridge_lib.dart'; +import 'dart:convert'; + +class AnimeWorldIndia extends MProvider { + AnimeWorldIndia(); + + @override + Future getPopular(MSource source, int page) async { + final data = { + "url": + "${source.baseUrl}/advanced-search/page/$page/?s_lang=${source.lang}&s_orderby=viewed" + }; + + final res = await http('GET', json.encode(data)); + return parseAnimeList(res, source.baseUrl); + } + + @override + Future getLatestUpdates(MSource source, int page) async { + final data = { + "url": + "${source.baseUrl}/advanced-search/page/$page/?s_lang=${source.lang}&s_orderby=update" + }; + final res = await http('GET', json.encode(data)); + return parseAnimeList(res, source.baseUrl); + } + + @override + Future search( + MSource source, 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) { + url += "${st.value}".toLowerCase().replaceAll(" ", "-"); + if (genre.length > 1) { + url += "%2C"; + } + } + if (genre.length > 1) { + url = substringBeforeLast(url, '%2C'); + } + } + } + } + final data = {"url": url}; + final res = await http('GET', json.encode(data)); + return parseAnimeList(res, source.baseUrl); + } + + @override + Future getDetail(MSource source, String url) async { + final data = {"url": url}; + final res = await http('GET', json.encode(data)); + 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(MSource source, String url) async { + final res = + await http('GET', json.encode({"url": "${source.baseUrl}$url"})); + + 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); + } + + String getUrlWithoutDomain(String orig) { + final uri = Uri.parse(orig.replaceAll(' ', '%20')); + String out = uri.path; + if (uri.query.isNotEmpty) { + out += '?${uri.query}'; + } + if (uri.fragment.isNotEmpty) { + out += '#${uri.fragment}'; + } + return out; + } + + MPages parseAnimeList(String res, String baseUrl) { + 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 = + "$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 http('GET', json.encode({"url": url})); + final streamCode = substringBefore( + substringAfter(substringAfter(res, "sniff("), ", \""), '"'); + + final streamUrl = + "${substringBefore(url, "/watch")}/m3u8/$streamCode/master.txt?s=1&cache=1"; + final masterPlaylistRes = + await http('GET', json.encode({"url": streamUrl})); + 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(MSource source) { + 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(MSource source) { + 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() { + return AnimeWorldIndia(); +} diff --git a/anime/src/all/animeworldindia/icon.png b/anime/src/all/animeworldindia/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..0426e29dfb699517e03b740f2d6fce7ee3ac2d91 GIT binary patch literal 7536 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 literal 0 HcmV?d00001 diff --git a/anime/src/all/animeworldindia/sources.dart b/anime/src/all/animeworldindia/sources.dart new file mode 100644 index 00000000..6890c3d6 --- /dev/null +++ b/anime/src/all/animeworldindia/sources.dart @@ -0,0 +1,32 @@ +import '../../../../model/source.dart'; + +const _animeworldindiaVersion = "0.0.1"; +const _animeworldindiaSourceCodeUrl = + "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/anime/src/all/animeworldindia/animeworldindia.dart"; + +String _iconUrl = + "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/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, + sourceCodeUrl: _animeworldindiaSourceCodeUrl)) + .toList();