Reorganize folders

This commit is contained in:
kodjomoustapha
2024-03-28 11:13:42 +01:00
parent abdc9cab62
commit 67109cdbbc
565 changed files with 988 additions and 1863 deletions

View File

@@ -0,0 +1,395 @@
import 'package:mangayomi/bridge_lib.dart';
import 'dart:convert';
class AnimeWorldIndia extends MProvider {
AnimeWorldIndia({required this.source});
MSource source;
final Client client = Client(source);
@override
Future<MPages> 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<MPages> 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<MPages> 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) {
url += "${st.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<MManga> 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<Map<String, dynamic>>;
bool isSingleSeason = seasonsJson.length == 1;
List<MChapter>? 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<Map<String, dynamic>>)
.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<List<MVideo>> 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<Map<String, dynamic>>)
.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<MVideo> 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<MManga> 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<List<MVideo>> mystreamExtractor(String url, String language) async {
List<MVideo> 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<MTrack> 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<dynamic> 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<dynamic> 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<MVideo> sortVideos(List<MVideo> 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);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

View File

@@ -0,0 +1,33 @@
import '../../../../../model/source.dart';
const _animeworldindiaVersion = "0.0.25";
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<String> _languages = [
"all",
"en",
"bn",
"hi",
"ja",
"ml",
"mr",
"ta",
"te",
];
List<Source> get animeworldindiaSourcesList => _animeworldindiaSourcesList;
List<Source> _animeworldindiaSourcesList = _languages
.map((e) => Source(
name: 'AnimeWorld India',
baseUrl: "https://anime-world.in",
lang: e,
typeSource: "multiple",
iconUrl: _iconUrl,
version: _animeworldindiaVersion,
isManga: false,
sourceCodeUrl: _animeworldindiaSourceCodeUrl))
.toList();