mirror of
https://github.com/kodjodevf/mangayomi-extensions.git
synced 2026-02-14 19:01:15 +00:00
WIP
This commit is contained in:
@@ -1,169 +0,0 @@
|
||||
import 'dart:convert';
|
||||
import 'package:bridge_lib/bridge_lib.dart';
|
||||
|
||||
getPopularAnime(MManga anime) async {
|
||||
final data = {"url": "https://www.okanime.xyz"};
|
||||
final response = await MBridge.http('GET', json.encode(data));
|
||||
if (response.hasError) {
|
||||
return response;
|
||||
}
|
||||
String res = response.body;
|
||||
anime.urls = MBridge.xpath(res,
|
||||
'//div[@class="section" and contains(text(),"افضل انميات")]/div[@class="section-content"]/div/div/div[contains(@class,"anime-card")]/div[@class="anime-title")]/h4/a/@href');
|
||||
|
||||
anime.names = MBridge.xpath(res,
|
||||
'//div[@class="section" and contains(text(),"افضل انميات")]/div[@class="section-content"]/div/div/div[contains(@class,"anime-card")]/div[@class="anime-title")]/h4/a/text()');
|
||||
|
||||
anime.images = MBridge.xpath(res,
|
||||
'//div[@class="section" and contains(text(),"افضل انميات")]/div[@class="section-content"]/div/div/div[contains(@class,"anime-card")]/div[@class="anime-image")]/img/@src');
|
||||
anime.hasNextPage = false;
|
||||
return anime;
|
||||
}
|
||||
|
||||
getAnimeDetail(MManga anime) async {
|
||||
final statusList = [
|
||||
{"يعرض الان": 0, "مكتمل": 1}
|
||||
];
|
||||
final data = {"url": anime.link};
|
||||
final response = await MBridge.http('GET', json.encode(data));
|
||||
if (response.hasError) {
|
||||
return response;
|
||||
}
|
||||
String res = response.body;
|
||||
|
||||
final status = MBridge.xpath(res,
|
||||
'//*[@class="full-list-info" and contains(text(),"حالة الأنمي")]/small/a/text()');
|
||||
if (status.isNotEmpty) {
|
||||
anime.status = MBridge.parseStatus(status.first, statusList);
|
||||
}
|
||||
anime.description =
|
||||
MBridge.xpath(res, '//*[@class="review-content"]/text()').first;
|
||||
final genre = MBridge.xpath(res, '//*[@class="review-author-info"]/a/text()');
|
||||
anime.genre = genre;
|
||||
|
||||
anime.urls = MBridge.xpath(res,
|
||||
'//*[contains(@class,"anime-card")]/div[@class="anime-title")]/h5/a/@href')
|
||||
.reversed
|
||||
.toList();
|
||||
|
||||
anime.names = MBridge.xpath(res,
|
||||
'//*[contains(@class,"anime-card")]/div[@class="anime-title")]/h5/a/text()')
|
||||
.reversed
|
||||
.toList();
|
||||
anime.chaptersDateUploads = [];
|
||||
return anime;
|
||||
}
|
||||
|
||||
getLatestUpdatesAnime(MManga anime) async {
|
||||
final data = {
|
||||
"url": "https://www.okanime.xyz/espisode-list?page=${anime.page}"
|
||||
};
|
||||
final response = await MBridge.http('GET', json.encode(data));
|
||||
if (response.hasError) {
|
||||
return response;
|
||||
}
|
||||
String res = response.body;
|
||||
anime.urls = MBridge.xpath(res,
|
||||
'//*[contains(@class,"anime-card")]/div[@class="anime-title")]/h4/a/@href');
|
||||
|
||||
anime.names = MBridge.xpath(res,
|
||||
'//*[contains(@class,"anime-card")]/div[@class="anime-title")]/h4/a/text()');
|
||||
|
||||
anime.images = MBridge.xpath(res,
|
||||
'//*[contains(@class,"anime-card")]/div[@class="episode-image")]/img/@src');
|
||||
final nextPage =
|
||||
MBridge.xpath(res, '//li[@class="page-item"]/a[@rel="next"]/@href');
|
||||
if (nextPage.isEmpty) {
|
||||
anime.hasNextPage = false;
|
||||
} else {
|
||||
anime.hasNextPage = true;
|
||||
}
|
||||
return anime;
|
||||
}
|
||||
|
||||
searchAnime(MManga anime) async {
|
||||
String url = "https://www.okanime.xyz/search/?s=${anime.query}";
|
||||
if (anime.page > 1) {
|
||||
url += "&page=${anime.page}";
|
||||
}
|
||||
final data = {"url": url};
|
||||
final response = await MBridge.http('GET', json.encode(data));
|
||||
if (response.hasError) {
|
||||
return response;
|
||||
}
|
||||
String res = response.body;
|
||||
anime.urls = MBridge.xpath(res,
|
||||
'//*[contains(@class,"anime-card")]/div[@class="anime-title")]/h4/a/@href');
|
||||
|
||||
anime.names = MBridge.xpath(res,
|
||||
'//*[contains(@class,"anime-card")]/div[@class="anime-title")]/h4/a/text()');
|
||||
|
||||
anime.images = MBridge.xpath(res,
|
||||
'//*[contains(@class,"anime-card")]/div[@class="anime-image")]/img/@src');
|
||||
final nextPage =
|
||||
MBridge.xpath(res, '//li[@class="page-item"]/a[@rel="next"]/@href');
|
||||
if (nextPage.isEmpty) {
|
||||
anime.hasNextPage = false;
|
||||
} else {
|
||||
anime.hasNextPage = true;
|
||||
}
|
||||
return anime;
|
||||
}
|
||||
|
||||
getVideoList(MManga anime) async {
|
||||
final datas = {"url": anime.link};
|
||||
final response = await MBridge.http('GET', json.encode(datas));
|
||||
|
||||
if (response.hasError) {
|
||||
return response;
|
||||
}
|
||||
String res = response.body;
|
||||
final urls = MBridge.xpath(res, '//*[@id="streamlinks"]/a/@data-src');
|
||||
final qualities = MBridge.xpath(res, '//*[@id="streamlinks"]/a/span/text()');
|
||||
|
||||
List<MVideo> videos = [];
|
||||
for (var i = 0; i < urls.length; i++) {
|
||||
final url = urls[i];
|
||||
final quality = getQuality(qualities[i]);
|
||||
List<MVideo> a = [];
|
||||
|
||||
if (url.contains("https://doo")) {
|
||||
a = await MBridge.doodExtractor(url, "DoodStream - $quality");
|
||||
} else if (url.contains("mp4upload")) {
|
||||
a = await MBridge.mp4UploadExtractor(url, null, "", "");
|
||||
} else if (url.contains("ok.ru")) {
|
||||
a = await MBridge.okruExtractor(url);
|
||||
} else if (url.contains("voe.sx")) {
|
||||
a = await MBridge.voeExtractor(url, "VoeSX $quality");
|
||||
} else if (containsVidBom(url)) {
|
||||
a = await MBridge.vidBomExtractor(url);
|
||||
}
|
||||
if (a.isNotEmpty) {
|
||||
videos.addAll(a);
|
||||
}
|
||||
}
|
||||
return videos;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
184
anime/src/ar/okanime/okanime-v0.0.25.dart
Normal file
184
anime/src/ar/okanime/okanime-v0.0.25.dart
Normal file
@@ -0,0 +1,184 @@
|
||||
import 'package:mangayomi/bridge_lib.dart';
|
||||
import 'dart:convert';
|
||||
|
||||
class OkAnime extends MSourceProvider {
|
||||
OkAnime();
|
||||
|
||||
@override
|
||||
Future<MPages> getPopular(MSource sourceInfo, int page) async {
|
||||
final data = {"url": sourceInfo.baseUrl};
|
||||
final res = await MBridge.http('GET', json.encode(data));
|
||||
|
||||
List<MManga> animeList = [];
|
||||
final urls = MBridge.xpath(res,
|
||||
'//div[@class="section" and contains(text(),"افضل انميات")]/div[@class="section-content"]/div/div/div[contains(@class,"anime-card")]/div[@class="anime-title")]/h4/a/@href');
|
||||
final names = MBridge.xpath(res,
|
||||
'//div[@class="section" and contains(text(),"افضل انميات")]/div[@class="section-content"]/div/div/div[contains(@class,"anime-card")]/div[@class="anime-title")]/h4/a/text()');
|
||||
final images = MBridge.xpath(res,
|
||||
'//div[@class="section" and contains(text(),"افضل انميات")]/div[@class="section-content"]/div/div/div[contains(@class,"anime-card")]/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<MPages> getLatestUpdates(MSource sourceInfo, int page) async {
|
||||
final data = {"url": "${sourceInfo.baseUrl}/espisode-list?page=$page"};
|
||||
final res = await MBridge.http('GET', json.encode(data));
|
||||
|
||||
List<MManga> animeList = [];
|
||||
final urls = MBridge.xpath(res,
|
||||
'//*[contains(@class,"anime-card")]/div[@class="anime-title")]/h4/a/@href');
|
||||
final names = MBridge.xpath(res,
|
||||
'//*[contains(@class,"anime-card")]/div[@class="anime-title")]/h4/a/text()');
|
||||
final images = MBridge.xpath(res,
|
||||
'//*[contains(@class,"anime-card")]/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 =
|
||||
MBridge.xpath(res, '//li[@class="page-item"]/a[@rel="next"]/@href');
|
||||
return MPages(animeList, nextPage.isNotEmpty);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MPages> search(MSource sourceInfo, String query, int page) async {
|
||||
String url = "${sourceInfo.baseUrl}/search/?s=$query";
|
||||
if (page > 1) {
|
||||
url += "&page=$page";
|
||||
}
|
||||
final data = {"url": url};
|
||||
final res = await MBridge.http('GET', json.encode(data));
|
||||
|
||||
List<MManga> animeList = [];
|
||||
final urls = MBridge.xpath(res,
|
||||
'//*[contains(@class,"anime-card")]/div[@class="anime-title")]/h4/a/@href');
|
||||
final names = MBridge.xpath(res,
|
||||
'//*[contains(@class,"anime-card")]/div[@class="anime-title")]/h4/a/text()');
|
||||
final images = MBridge.xpath(res,
|
||||
'//*[contains(@class,"anime-card")]/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 =
|
||||
MBridge.xpath(res, '//li[@class="page-item"]/a[@rel="next"]/@href');
|
||||
return MPages(animeList, nextPage.isNotEmpty);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MManga> getDetail(MSource sourceInfo, String url) async {
|
||||
final statusList = [
|
||||
{"يعرض الان": 0, "مكتمل": 1}
|
||||
];
|
||||
final data = {"url": url};
|
||||
final res = await MBridge.http('GET', json.encode(data));
|
||||
MManga anime = MManga();
|
||||
final status = MBridge.xpath(res,
|
||||
'//*[@class="full-list-info" and contains(text(),"حالة الأنمي")]/small/a/text()');
|
||||
if (status.isNotEmpty) {
|
||||
anime.status = MBridge.parseStatus(status.first, statusList);
|
||||
}
|
||||
anime.description =
|
||||
MBridge.xpath(res, '//*[@class="review-content"]/text()').first;
|
||||
|
||||
anime.genre =
|
||||
MBridge.xpath(res, '//*[@class="review-author-info"]/a/text()');
|
||||
final epUrls = MBridge.xpath(res,
|
||||
'//*[contains(@class,"anime-card")]/div[@class="anime-title")]/h5/a/@href')
|
||||
.reversed
|
||||
.toList();
|
||||
final names = MBridge.xpath(res,
|
||||
'//*[contains(@class,"anime-card")]/div[@class="anime-title")]/h5/a/text()')
|
||||
.reversed
|
||||
.toList();
|
||||
|
||||
List<MChapter>? 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<List<MVideo>> getVideoList(MSource sourceInfo, String url) async {
|
||||
final res = await MBridge.http('GET', json.encode({"url": url}));
|
||||
|
||||
final urls = MBridge.xpath(res, '//*[@id="streamlinks"]/a/@data-src');
|
||||
final qualities =
|
||||
MBridge.xpath(res, '//*[@id="streamlinks"]/a/span/text()');
|
||||
|
||||
List<MVideo> videos = [];
|
||||
for (var i = 0; i < urls.length; i++) {
|
||||
final url = urls[i];
|
||||
final quality = getQuality(qualities[i]);
|
||||
List<MVideo> a = [];
|
||||
|
||||
if (url.contains("https://doo")) {
|
||||
a = await MBridge.doodExtractor(url, "DoodStream - $quality");
|
||||
} else if (url.contains("mp4upload")) {
|
||||
a = await MBridge.mp4UploadExtractor(url, null, "", "");
|
||||
} else if (url.contains("ok.ru")) {
|
||||
a = await MBridge.okruExtractor(url);
|
||||
} else if (url.contains("voe.sx")) {
|
||||
a = await MBridge.voeExtractor(url, "VoeSX $quality");
|
||||
} else if (containsVidBom(url)) {
|
||||
a = await MBridge.vidBomExtractor(url);
|
||||
}
|
||||
videos.addAll(a);
|
||||
}
|
||||
return videos;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<String>> getPageList(MSource sourceInfo, String url) async {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
OkAnime main() {
|
||||
return OkAnime();
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import '../../../../model/source.dart';
|
||||
import '../../../../utils/utils.dart';
|
||||
|
||||
Source get okanimeSource => _okanimeSource;
|
||||
const okanimeVersion = "0.0.2";
|
||||
const okanimeVersion = "0.0.25";
|
||||
const okanimeSourceCodeUrl =
|
||||
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/src/ar/okanime/okanime-v$okanimeVersion.dart";
|
||||
Source _okanimeSource = Source(
|
||||
|
||||
@@ -1,213 +0,0 @@
|
||||
import 'dart:convert';
|
||||
import 'package:bridge_lib/bridge_lib.dart';
|
||||
|
||||
getPopularAnime(MManga anime) async {
|
||||
final data = {"url": "${anime.baseUrl}/most-popular?page=${anime.page}"};
|
||||
final res = await MBridge.http('GET', json.encode(data));
|
||||
if (res.hasError) {
|
||||
return res;
|
||||
}
|
||||
return animeElementM(res.body, anime);
|
||||
}
|
||||
|
||||
getLatestUpdatesAnime(MManga anime) async {
|
||||
final data = {"url": "${anime.baseUrl}/recently-updated?page=${anime.page}"};
|
||||
final res = await MBridge.http('GET', json.encode(data));
|
||||
if (res.hasError) {
|
||||
return res;
|
||||
}
|
||||
return animeElementM(res.body, anime);
|
||||
}
|
||||
|
||||
getAnimeDetail(MManga anime) async {
|
||||
final statusList = [
|
||||
{
|
||||
"Currently Airing": 0,
|
||||
"Finished Airing": 1,
|
||||
}
|
||||
];
|
||||
final url = "${anime.baseUrl}${anime.link}";
|
||||
final data = {"url": url, "headers": null};
|
||||
final response = await MBridge.http('GET', json.encode(data));
|
||||
if (response.hasError) {
|
||||
return response;
|
||||
}
|
||||
String res = response.body;
|
||||
final status = MBridge.xpath(res,
|
||||
'//*[@class="anisc-info"]/div[contains(text(),"Status:")]/span[2]/text()')
|
||||
.first;
|
||||
anime.status = MBridge.parseStatus(status, statusList);
|
||||
anime.author = MBridge.xpath(res,
|
||||
'//*[@class="anisc-info"]/div[contains(text(),"Studios:")]/span/text()')
|
||||
.first
|
||||
.replaceAll("Studios:", "");
|
||||
final aired = MBridge.xpath(res,
|
||||
'//*[@class="anisc-info"]/div[contains(text(),"Aired:")]/span/text()')
|
||||
.first;
|
||||
final japanese = MBridge.xpath(res,
|
||||
'//*[@class="anisc-info"]/div[contains(text(),"Japanese:")]/span/text()')
|
||||
.first;
|
||||
final synonyms = MBridge.xpath(res,
|
||||
'//*[@class="anisc-info"]/div[contains(text(),"Synonyms:")]/span/text()')
|
||||
.first;
|
||||
final premiered = MBridge.xpath(res,
|
||||
'//*[@class="anisc-info"]/div[contains(text(),"Premiered:")]/span/text()')
|
||||
.first;
|
||||
final overview = MBridge.xpath(res,
|
||||
'//*[@class="anisc-info"]/div[contains(text(),"Overview:")]/text()')
|
||||
.first
|
||||
.replaceAll("Overview:", "");
|
||||
String description = "$overview\n\n$japanese\n$synonyms\n$aired\n$premiered";
|
||||
anime.description = description;
|
||||
final genre = MBridge.xpath(
|
||||
res, '//*[@class="anisc-info"]/div[contains(text(),"Genres:")]/a/text()');
|
||||
|
||||
anime.genre = genre;
|
||||
|
||||
final id = MBridge.substringAfterLast(anime.link, '-');
|
||||
final urlEp =
|
||||
"${anime.baseUrl}/ajax${ajaxRoute('${anime.baseUrl}')}/episode/list/$id";
|
||||
|
||||
final dataEp = {
|
||||
"url": urlEp,
|
||||
"headers": {"referer": url}
|
||||
};
|
||||
final resEp = await MBridge.http('GET', json.encode(dataEp));
|
||||
|
||||
final html = json.decode(resEp.body)["html"];
|
||||
|
||||
final epUrls = MBridge.querySelectorAll(html,
|
||||
selector: "a.ep-item", typeElement: 3, attributes: "href", typeRegExp: 0);
|
||||
|
||||
anime.urls = epUrls.reversed.toList();
|
||||
|
||||
final numbers = MBridge.querySelectorAll(html,
|
||||
selector: "a.ep-item",
|
||||
typeElement: 3,
|
||||
attributes: "data-number",
|
||||
typeRegExp: 0);
|
||||
|
||||
final titles = MBridge.querySelectorAll(html,
|
||||
selector: "a.ep-item",
|
||||
typeElement: 3,
|
||||
attributes: "title",
|
||||
typeRegExp: 0);
|
||||
|
||||
List<String> episodes = [];
|
||||
|
||||
for (var i = 0; i < titles.length; i++) {
|
||||
final number = numbers[i];
|
||||
final title = titles[i];
|
||||
episodes.add("Episode $number: $title");
|
||||
}
|
||||
|
||||
anime.names = episodes.reversed.toList();
|
||||
anime.chaptersDateUploads = [];
|
||||
return anime;
|
||||
}
|
||||
|
||||
searchAnime(MManga anime) async {
|
||||
final data = {
|
||||
"url": "${anime.baseUrl}/search?keyword=${anime.query}&page=${anime.page}"
|
||||
};
|
||||
final res = await MBridge.http('GET', json.encode(data));
|
||||
if (res.hasError) {
|
||||
return res;
|
||||
}
|
||||
return animeElementM(res.body, anime);
|
||||
}
|
||||
|
||||
getVideoList(MManga anime) async {
|
||||
final id = MBridge.substringAfterLast(anime.link, '?ep=');
|
||||
final datas = {
|
||||
"url":
|
||||
"${anime.baseUrl}/ajax${ajaxRoute('${anime.baseUrl}')}/episode/servers?episodeId=$id",
|
||||
"headers": {"referer": "${anime.baseUrl}/${anime.link}"},
|
||||
"sourceId": anime.sourceId
|
||||
};
|
||||
|
||||
final res = await MBridge.http('GET', json.encode(datas));
|
||||
|
||||
if (res.hasError) {
|
||||
return res;
|
||||
}
|
||||
final html = json.decode(res.body)["html"];
|
||||
|
||||
final names = MBridge.querySelectorAll(html,
|
||||
selector: "div.server-item",
|
||||
typeElement: 0,
|
||||
attributes: "",
|
||||
typeRegExp: 0);
|
||||
|
||||
final ids = MBridge.querySelectorAll(html,
|
||||
selector: "div.server-item",
|
||||
typeElement: 3,
|
||||
attributes: "data-id",
|
||||
typeRegExp: 0);
|
||||
|
||||
final subDubs = MBridge.querySelectorAll(html,
|
||||
selector: "div.server-item",
|
||||
typeElement: 3,
|
||||
attributes: "data-type",
|
||||
typeRegExp: 0);
|
||||
|
||||
List<MVideo> videos = [];
|
||||
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
final name = names[i];
|
||||
final id = ids[i];
|
||||
final subDub = subDubs[i];
|
||||
final datasE = {
|
||||
"url":
|
||||
"${anime.baseUrl}/ajax${ajaxRoute('${anime.baseUrl}')}/episode/sources?id=$id",
|
||||
"headers": {"referer": "${anime.baseUrl}/${anime.link}"}
|
||||
};
|
||||
|
||||
final resE = await MBridge.http('GET', json.encode(datasE));
|
||||
String url = MBridge.substringBefore(
|
||||
MBridge.substringAfter(resE.body, "\"link\":\""), "\"");
|
||||
print(url);
|
||||
List<MVideo> a = [];
|
||||
if (name.contains("Vidstreaming")) {
|
||||
a = await MBridge.rapidCloudExtractor(url, "Vidstreaming - $subDub");
|
||||
videos.addAll(a);
|
||||
} else if (name.contains("Vidcloud")) {
|
||||
a = await MBridge.rapidCloudExtractor(url, "Vidcloud - $subDub");
|
||||
videos.addAll(a);
|
||||
} else if (name.contains("StreamTape")) {
|
||||
a = await MBridge.streamTapeExtractor(url, "StreamTape - $subDub");
|
||||
videos.addAll(a);
|
||||
}
|
||||
}
|
||||
|
||||
return videos;
|
||||
}
|
||||
|
||||
MManga animeElementM(String res, MManga anime) async {
|
||||
if (res.isEmpty) {
|
||||
return anime;
|
||||
}
|
||||
anime.urls = MBridge.xpath(
|
||||
res, '//*[@class^="flw-item"]/div[@class="film-detail"]/h3/a/@href');
|
||||
|
||||
anime.names = MBridge.xpath(res,
|
||||
'//*[@class^="flw-item"]/div[@class="film-detail"]/h3/a/@data-jname');
|
||||
|
||||
anime.images = MBridge.xpath(
|
||||
res, '//*[@class^="flw-item"]/div[@class="film-poster"]/img/@data-src');
|
||||
final nextPage =
|
||||
MBridge.xpath(res, '//li[@class="page-item"]/a[@title="Next"]/@href', "");
|
||||
if (nextPage.isEmpty) {
|
||||
anime.hasNextPage = false;
|
||||
} else {
|
||||
anime.hasNextPage = true;
|
||||
}
|
||||
return anime;
|
||||
}
|
||||
|
||||
String ajaxRoute(String baseUrl) {
|
||||
if (baseUrl == "https://kaido.to") {
|
||||
return "";
|
||||
}
|
||||
return "/v2";
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import '../../../../model/source.dart';
|
||||
import '../../../../utils/utils.dart';
|
||||
|
||||
const aniwatchVersion = "0.0.35";
|
||||
const aniwatchSourceCodeUrl =
|
||||
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/src/en/aniwatch/aniwatch-v$aniwatchVersion.dart";
|
||||
|
||||
List<Source> get aniwatchSourcesList => _aniwatchSourcesList;
|
||||
List<Source> _aniwatchSourcesList = [
|
||||
Source(
|
||||
name: "AniWatch.to",
|
||||
baseUrl: "https://aniwatch.to",
|
||||
lang: "en",
|
||||
typeSource: "single",
|
||||
iconUrl: getIconUrl("aniwatch", "en"),
|
||||
version: aniwatchVersion,
|
||||
isManga: false,
|
||||
sourceCodeUrl: aniwatchSourceCodeUrl),
|
||||
Source(
|
||||
name: "Kaido.to",
|
||||
baseUrl: "https://kaido.to",
|
||||
lang: "en",
|
||||
typeSource: "single",
|
||||
iconUrl: getIconUrl("kaido", "en"),
|
||||
version: aniwatchVersion,
|
||||
isManga: false,
|
||||
sourceCodeUrl: aniwatchSourceCodeUrl),
|
||||
];
|
||||
@@ -1,148 +0,0 @@
|
||||
import 'dart:convert';
|
||||
import 'package:bridge_lib/bridge_lib.dart';
|
||||
|
||||
getPopularAnime(MManga anime) async {
|
||||
final data = {"url": "${anime.baseUrl}/popular.html?page=${anime.page}"};
|
||||
final response = await MBridge.http('GET', json.encode(data));
|
||||
if (response.hasError) {
|
||||
return response;
|
||||
}
|
||||
String res = response.body;
|
||||
anime.urls = MBridge.xpath(res, '//*[@class="img"]/a/@href');
|
||||
anime.names = MBridge.xpath(res, '//*[@class="img"]/a/@title');
|
||||
anime.images = MBridge.xpath(res, '//*[@class="img"]/a/img/@src');
|
||||
return anime;
|
||||
}
|
||||
|
||||
getLatestUpdatesAnime(MManga anime) async {
|
||||
final url =
|
||||
"https://ajax.gogo-load.com/ajax/page-recent-release-ongoing.html?page=${anime.page}&type=1";
|
||||
final data = {"url": url};
|
||||
final response = await MBridge.http('GET', json.encode(data));
|
||||
if (response.hasError) {
|
||||
return response;
|
||||
}
|
||||
String res = response.body;
|
||||
anime.urls = MBridge.xpath(
|
||||
res, '//*[@class="added_series_body popular"]/ul/li/a[1]/@href');
|
||||
anime.names = MBridge.xpath(
|
||||
res, '//*[//*[@class="added_series_body popular"]/ul/li/a[1]/@title');
|
||||
List<String> images = [];
|
||||
List<String> imagess = MBridge.xpath(res,
|
||||
'//*[//*[@class="added_series_body popular"]/ul/li/a/div[@class="thumbnail-popular"]/@style');
|
||||
for (var url in imagess) {
|
||||
images.add(url.replaceAll("background: url('", "").replaceAll("');", ""));
|
||||
}
|
||||
|
||||
anime.images = images;
|
||||
|
||||
return anime;
|
||||
}
|
||||
|
||||
getAnimeDetail(MManga anime) async {
|
||||
final statusList = [
|
||||
{
|
||||
"Ongoing": 0,
|
||||
"Completed": 1,
|
||||
}
|
||||
];
|
||||
|
||||
final data = {"url": "${anime.baseUrl}${anime.link}"};
|
||||
final response = await MBridge.http('GET', json.encode(data));
|
||||
if (response.hasError) {
|
||||
return response;
|
||||
}
|
||||
String res = response.body;
|
||||
|
||||
final status = MBridge.xpath(
|
||||
res, '//*[@class="anime_info_body_bg"]/p[@class="type"][5]/text()')
|
||||
.first
|
||||
.replaceAll("Status: ", "");
|
||||
anime.description = MBridge.xpath(
|
||||
res, '//*[@class="anime_info_body_bg"]/p[@class="type"][2]/text()')
|
||||
.first
|
||||
.replaceAll("Plot Summary: ", "");
|
||||
anime.status = MBridge.parseStatus(status, statusList);
|
||||
anime.genre = MBridge.xpath(
|
||||
res, '//*[@class="anime_info_body_bg"]/p[@class="type"][3]/text()')
|
||||
.first
|
||||
.replaceAll("Genre: ", "")
|
||||
.split(",");
|
||||
|
||||
final id = MBridge.xpath(res, '//*[@id="movie_id"]/@value').first;
|
||||
final urlEp =
|
||||
"https://ajax.gogo-load.com/ajax/load-list-episode?ep_start=0&ep_end=4000&id=$id";
|
||||
final dataEp = {"url": urlEp};
|
||||
final responseresEp = await MBridge.http('GET', json.encode(dataEp));
|
||||
if (responseresEp.hasError) {
|
||||
return response;
|
||||
}
|
||||
String resEp = responseresEp.body;
|
||||
anime.urls = MBridge.xpath(resEp, '//*[@id="episode_related"]/li/a/@href');
|
||||
final names = MBridge.xpath(
|
||||
resEp, '//*[@id="episode_related"]/li/a/div[@class="name"]/text()');
|
||||
|
||||
List<String> episodes = [];
|
||||
for (var a in names) {
|
||||
episodes.add("Episode ${MBridge.substringAfterLast(a, ' ')}");
|
||||
}
|
||||
|
||||
anime.names = episodes;
|
||||
anime.chaptersDateUploads = [];
|
||||
return anime;
|
||||
}
|
||||
|
||||
getVideoList(MManga anime) async {
|
||||
final datas = {"url": "${anime.baseUrl}${anime.link}"};
|
||||
|
||||
final response = await MBridge.http('GET', json.encode(datas));
|
||||
|
||||
if (response.hasError) {
|
||||
return response;
|
||||
}
|
||||
String res = response.body;
|
||||
|
||||
final serverUrls =
|
||||
MBridge.xpath(res, '//*[@class="anime_muti_link"]/ul/li/a/@data-video');
|
||||
final classNames =
|
||||
MBridge.xpath(res, '//*[@class="anime_muti_link"]/ul/li/@class');
|
||||
List<MVideo> videos = [];
|
||||
for (var i = 0; i < classNames.length; i++) {
|
||||
final name = classNames[i];
|
||||
final url = serverUrls[i];
|
||||
print(url);
|
||||
List<MVideo> a = [];
|
||||
if (name.contains("anime")) {
|
||||
a = await MBridge.gogoCdnExtractor(url);
|
||||
} else if (name.contains("vidcdn")) {
|
||||
a = await MBridge.gogoCdnExtractor(url);
|
||||
} else if (name.contains("doodstream")) {
|
||||
a = await MBridge.doodExtractor(url);
|
||||
} else if (name.contains("mp4upload")) {
|
||||
a = await MBridge.mp4UploadExtractor(url, null, "", "");
|
||||
} else if (name.contains("streamsb")) {
|
||||
// print("streamsb");
|
||||
// print(url);
|
||||
}
|
||||
for (var vi in a) {
|
||||
videos.add(vi);
|
||||
}
|
||||
}
|
||||
|
||||
return videos;
|
||||
}
|
||||
|
||||
searchAnime(MManga anime) async {
|
||||
final url =
|
||||
"${anime.baseUrl}/search.html?keyword=${anime.query}&page=${anime.page}";
|
||||
final data = {"url": url};
|
||||
final response = await MBridge.http('GET', json.encode(data));
|
||||
if (response.hasError) {
|
||||
return response;
|
||||
}
|
||||
String res = response.body;
|
||||
anime.urls = MBridge.xpath(res, '//*[@class="img"]/a/@href');
|
||||
anime.names = MBridge.xpath(res, '//*[@class="img"]/a/@title');
|
||||
anime.images = MBridge.xpath(res, '//*[@class="img"]/a/img/@src');
|
||||
return anime;
|
||||
}
|
||||
172
anime/src/en/gogoanime/gogoanime-v0.0.35.dart
Normal file
172
anime/src/en/gogoanime/gogoanime-v0.0.35.dart
Normal file
@@ -0,0 +1,172 @@
|
||||
import 'package:mangayomi/bridge_lib.dart';
|
||||
import 'dart:convert';
|
||||
|
||||
class GogoAnime extends MSourceProvider {
|
||||
GogoAnime();
|
||||
|
||||
@override
|
||||
Future<MPages> getPopular(MSource sourceInfo, int page) async {
|
||||
final data = {"url": "${sourceInfo.baseUrl}/popular.html?page=$page"};
|
||||
final res = await MBridge.http('GET', json.encode(data));
|
||||
|
||||
List<MManga> animeList = [];
|
||||
final urls = MBridge.xpath(res, '//*[@class="img"]/a/@href');
|
||||
final names = MBridge.xpath(res, '//*[@class="img"]/a/@title');
|
||||
final images = MBridge.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<MPages> getLatestUpdates(MSource sourceInfo, int page) async {
|
||||
final data = {
|
||||
"url":
|
||||
"https://ajax.gogo-load.com/ajax/page-recent-release-ongoing.html?page=$page&type=1"
|
||||
};
|
||||
final res = await MBridge.http('GET', json.encode(data));
|
||||
|
||||
List<MManga> animeList = [];
|
||||
final urls = MBridge.xpath(
|
||||
res, '//*[@class="added_series_body popular"]/ul/li/a[1]/@href');
|
||||
final names = MBridge.xpath(
|
||||
res, '//*[//*[@class="added_series_body popular"]/ul/li/a[1]/@title');
|
||||
List<String> images = [];
|
||||
List<String> imagess = MBridge.xpath(res,
|
||||
'//*[//*[@class="added_series_body popular"]/ul/li/a/div[@class="thumbnail-popular"]/@style');
|
||||
for (var url in imagess) {
|
||||
images.add(url.replaceAll("background: url('", "").replaceAll("');", ""));
|
||||
}
|
||||
|
||||
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<MPages> search(MSource sourceInfo, String query, int page) async {
|
||||
final data = {
|
||||
"url": "${sourceInfo.baseUrl}/search.html?keyword=$query&page=$page"
|
||||
};
|
||||
final res = await MBridge.http('GET', json.encode(data));
|
||||
|
||||
List<MManga> animeList = [];
|
||||
final urls = MBridge.xpath(res, '//*[@class="img"]/a/@href');
|
||||
final names = MBridge.xpath(res, '//*[@class="img"]/a/@title');
|
||||
final images = MBridge.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<MManga> getDetail(MSource sourceInfo, String url) async {
|
||||
final statusList = [
|
||||
{
|
||||
"Ongoing": 0,
|
||||
"Completed": 1,
|
||||
}
|
||||
];
|
||||
final data = {"url": "${sourceInfo.baseUrl}$url"};
|
||||
final res = await MBridge.http('GET', json.encode(data));
|
||||
MManga anime = MManga();
|
||||
final status = MBridge.xpath(
|
||||
res, '//*[@class="anime_info_body_bg"]/p[@class="type"][5]/text()')
|
||||
.first
|
||||
.replaceAll("Status: ", "");
|
||||
anime.description = MBridge.xpath(
|
||||
res, '//*[@class="anime_info_body_bg"]/p[@class="type"][2]/text()')
|
||||
.first
|
||||
.replaceAll("Plot Summary: ", "");
|
||||
anime.status = MBridge.parseStatus(status, statusList);
|
||||
anime.genre = MBridge.xpath(
|
||||
res, '//*[@class="anime_info_body_bg"]/p[@class="type"][3]/text()')
|
||||
.first
|
||||
.replaceAll("Genre: ", "")
|
||||
.split(",");
|
||||
|
||||
final id = MBridge.xpath(res, '//*[@id="movie_id"]/@value').first;
|
||||
final urlEp =
|
||||
"https://ajax.gogo-load.com/ajax/load-list-episode?ep_start=0&ep_end=4000&id=$id";
|
||||
final dataEp = {"url": urlEp};
|
||||
final resEp = await MBridge.http('GET', json.encode(dataEp));
|
||||
|
||||
final epUrls =
|
||||
MBridge.xpath(resEp, '//*[@id="episode_related"]/li/a/@href');
|
||||
final names = MBridge.xpath(
|
||||
resEp, '//*[@id="episode_related"]/li/a/div[@class="name"]/text()');
|
||||
List<String> episodes = [];
|
||||
|
||||
for (var a in names) {
|
||||
episodes.add("Episode ${MBridge.substringAfterLast(a, ' ')}");
|
||||
}
|
||||
List<MChapter>? 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<List<MVideo>> getVideoList(MSource sourceInfo, String url) async {
|
||||
final datas = {"url": "${sourceInfo.baseUrl}$url"};
|
||||
|
||||
final res = await MBridge.http('GET', json.encode(datas));
|
||||
final serverUrls =
|
||||
MBridge.xpath(res, '//*[@class="anime_muti_link"]/ul/li/a/@data-video');
|
||||
final classNames =
|
||||
MBridge.xpath(res, '//*[@class="anime_muti_link"]/ul/li/@class');
|
||||
List<MVideo> videos = [];
|
||||
for (var i = 0; i < classNames.length; i++) {
|
||||
final name = classNames[i];
|
||||
final url = serverUrls[i];
|
||||
List<MVideo> a = [];
|
||||
if (name.contains("anime")) {
|
||||
a = await MBridge.gogoCdnExtractor(url);
|
||||
} else if (name.contains("vidcdn")) {
|
||||
a = await MBridge.gogoCdnExtractor(url);
|
||||
} else if (name.contains("doodstream")) {
|
||||
a = await MBridge.doodExtractor(url);
|
||||
} else if (name.contains("mp4upload")) {
|
||||
a = await MBridge.mp4UploadExtractor(url, null, "", "");
|
||||
} else if (name.contains("streamsb")) {}
|
||||
videos.addAll(a);
|
||||
}
|
||||
|
||||
return videos;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<String>> getPageList(MSource sourceInfo, String url) async {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
GogoAnime main() {
|
||||
return GogoAnime();
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import '../../../../model/source.dart';
|
||||
import '../../../../utils/utils.dart';
|
||||
|
||||
Source get gogoanimeSource => _gogoanimeSource;
|
||||
const gogoanimeVersion = "0.0.3";
|
||||
const gogoanimeVersion = "0.0.35";
|
||||
const gogoanimeSourceCodeUrl =
|
||||
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/src/en/gogoanime/gogoanime-v$gogoanimeVersion.dart";
|
||||
Source _gogoanimeSource = Source(
|
||||
|
||||
@@ -1,163 +0,0 @@
|
||||
import 'dart:convert';
|
||||
import 'package:bridge_lib/bridge_lib.dart';
|
||||
|
||||
getPopularAnime(MManga anime) async {
|
||||
final data = {
|
||||
"url":
|
||||
"${anime.baseUrl}/api/DramaList/List?page=${anime.page}&type=0&sub=0&country=0&status=0&order=1&pageSize=40"
|
||||
};
|
||||
final response = await MBridge.http('GET', json.encode(data));
|
||||
if (response.hasError) {
|
||||
return response;
|
||||
}
|
||||
String res = response.body;
|
||||
final jsonRes = json.decode(res);
|
||||
final datas = jsonRes["data"] as List;
|
||||
anime.names = datas.map((e) => e["title"]).toList();
|
||||
anime.images = datas.map((e) => e["thumbnail"] ?? "").toList();
|
||||
anime.urls = datas
|
||||
.map((e) => "${anime.baseUrl}/api/DramaList/Drama/${e["id"]}?isq=false")
|
||||
.toList();
|
||||
final lastPage = jsonRes["totalCount"] as int;
|
||||
final page = jsonRes["page"] as int;
|
||||
|
||||
anime.hasNextPage = page < lastPage;
|
||||
return anime;
|
||||
}
|
||||
|
||||
getLatestUpdatesAnime(MManga anime) async {
|
||||
final data = {
|
||||
"url":
|
||||
"${anime.baseUrl}/api/DramaList/List?page=${anime.page}&type=0&sub=0&country=0&status=0&order=12&pageSize=40"
|
||||
};
|
||||
final response = await MBridge.http('GET', json.encode(data));
|
||||
if (response.hasError) {
|
||||
return response;
|
||||
}
|
||||
String res = response.body;
|
||||
final jsonRes = json.decode(res);
|
||||
final datas = jsonRes["data"] as List;
|
||||
anime.names = datas.map((e) => e["title"]).toList();
|
||||
anime.images = datas.map((e) => e["thumbnail"] ?? "").toList();
|
||||
anime.urls = datas
|
||||
.map((e) => "${anime.baseUrl}/api/DramaList/Drama/${e["id"]}?isq=false")
|
||||
.toList();
|
||||
final lastPage = jsonRes["totalCount"] as int;
|
||||
final page = jsonRes["page"] as int;
|
||||
|
||||
anime.hasNextPage = page < lastPage;
|
||||
|
||||
return anime;
|
||||
}
|
||||
|
||||
getAnimeDetail(MManga anime) async {
|
||||
final statusList = [
|
||||
{
|
||||
"Ongoing": 0,
|
||||
"Completed": 1,
|
||||
}
|
||||
];
|
||||
|
||||
final data = {"url": anime.link};
|
||||
final response = await MBridge.http('GET', json.encode(data));
|
||||
if (response.hasError) {
|
||||
return response;
|
||||
}
|
||||
String res = response.body;
|
||||
final jsonRes = json.decode(res);
|
||||
final status = jsonRes["status"] ?? "";
|
||||
print(status);
|
||||
anime.description = jsonRes["description"];
|
||||
anime.status = MBridge.parseStatus(status, statusList);
|
||||
anime.imageUrl = jsonRes["thumbnail"];
|
||||
var episodes = jsonRes["episodes"];
|
||||
String type = jsonRes["type"];
|
||||
final episodesCount = jsonRes["episodesCount"] as int;
|
||||
List<String> episodesNames = [];
|
||||
List<String> episodesUrls = [];
|
||||
final containsAnime = type.contains("Anime") as bool;
|
||||
final containsTVSeries = type.contains("TVSeries") as bool;
|
||||
final containsHollywood = type.contains("Hollywood") as bool;
|
||||
final containsMovie = type.contains("Movie") as bool;
|
||||
for (var a in episodes) {
|
||||
String number = (a["number"] as double).toString().replaceAll(".0", "");
|
||||
final id = a["id"];
|
||||
if (containsAnime || containsTVSeries) {
|
||||
episodesNames.add("Episode $number");
|
||||
} else if (containsHollywood && episodesCount == 1 || containsMovie) {
|
||||
episodesNames.add("Movie");
|
||||
} else if (containsHollywood && episodesCount > 1) {
|
||||
episodesNames.add("Episode $number");
|
||||
}
|
||||
|
||||
episodesUrls.add(
|
||||
"${anime.baseUrl}/api/DramaList/Episode/$id.png?err=false&ts=&time=");
|
||||
}
|
||||
anime.urls = episodesUrls;
|
||||
anime.names = episodesNames;
|
||||
anime.chaptersDateUploads = [];
|
||||
return anime;
|
||||
}
|
||||
|
||||
getVideoList(MManga anime) async {
|
||||
final datas = {"url": anime.link};
|
||||
|
||||
final response = await MBridge.http('GET', json.encode(datas));
|
||||
|
||||
if (response.hasError) {
|
||||
return response;
|
||||
}
|
||||
String res = response.body;
|
||||
final id = MBridge.substringAfter(
|
||||
MBridge.substringBefore(anime.link, ".png"), "Episode/");
|
||||
final jsonRes = json.decode(res);
|
||||
final subRes = await MBridge.http(
|
||||
'GET', json.encode({"url": "${anime.baseUrl}/api/Sub/$id"}));
|
||||
var jsonSubRes = json.decode(subRes.body);
|
||||
|
||||
List<MTrack> subtitles = [];
|
||||
|
||||
for (var sub in jsonSubRes) {
|
||||
try {
|
||||
final subUrl = sub["src"];
|
||||
final label = sub["label"];
|
||||
MTrack subtitle = MTrack();
|
||||
subtitle
|
||||
..label = label
|
||||
..file = subUrl;
|
||||
subtitles.add(subtitle);
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
final videoUrl = jsonRes["Video"];
|
||||
MVideo video = MVideo();
|
||||
video
|
||||
..url = videoUrl
|
||||
..originalUrl = videoUrl
|
||||
..quality = "kisskh"
|
||||
..subtitles = subtitles
|
||||
..headers = {
|
||||
"referer": "https://kisskh.me/",
|
||||
"origin": "https://kisskh.me"
|
||||
};
|
||||
return [video];
|
||||
}
|
||||
|
||||
searchAnime(MManga anime) async {
|
||||
final data = {
|
||||
"url": "${anime.baseUrl}/api/DramaList/Search?q=${anime.query}&type=0"
|
||||
};
|
||||
final response = await MBridge.http('GET', json.encode(data));
|
||||
if (response.hasError) {
|
||||
return response;
|
||||
}
|
||||
String res = response.body;
|
||||
var jsonRes = json.decode(res) as List;
|
||||
anime.names = jsonRes.map((e) => e["title"]).toList();
|
||||
anime.images = jsonRes.map((e) => e["thumbnail"] ?? "").toList();
|
||||
anime.urls = jsonRes
|
||||
.map((e) => "${anime.baseUrl}/api/DramaList/Drama/${e["id"]}?isq=false")
|
||||
.toList();
|
||||
|
||||
return anime;
|
||||
}
|
||||
172
anime/src/en/kisskh/kisskh-v0.0.25.dart
Normal file
172
anime/src/en/kisskh/kisskh-v0.0.25.dart
Normal file
@@ -0,0 +1,172 @@
|
||||
import 'package:mangayomi/bridge_lib.dart';
|
||||
import 'dart:convert';
|
||||
|
||||
class KissKh extends MSourceProvider {
|
||||
KissKh();
|
||||
|
||||
@override
|
||||
Future<MPages> getPopular(MSource sourceInfo, int page) async {
|
||||
final data = {
|
||||
"url":
|
||||
"${sourceInfo.baseUrl}/api/DramaList/List?page=$page&type=0&sub=0&country=0&status=0&order=1&pageSize=40"
|
||||
};
|
||||
final res = await MBridge.http('GET', json.encode(data));
|
||||
final jsonRes = json.decode(res);
|
||||
final datas = jsonRes["data"] as List;
|
||||
List<MManga> animeList = [];
|
||||
|
||||
for (var data in datas) {
|
||||
MManga anime = MManga();
|
||||
anime.name = data["title"];
|
||||
anime.imageUrl = data["thumbnail"] ?? "";
|
||||
anime.link =
|
||||
"${sourceInfo.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<MPages> getLatestUpdates(MSource sourceInfo, int page) async {
|
||||
final data = {
|
||||
"url":
|
||||
"${sourceInfo.baseUrl}/api/DramaList/List?page=$page&type=0&sub=0&country=0&status=0&order=12&pageSize=40",
|
||||
"header": {"ee": "eee"}
|
||||
};
|
||||
final res = await MBridge.http('GET', json.encode(data));
|
||||
final jsonRes = json.decode(res);
|
||||
final datas = jsonRes["data"] as List;
|
||||
|
||||
List<MManga> animeList = [];
|
||||
|
||||
for (var data in datas) {
|
||||
MManga anime = MManga();
|
||||
anime.name = data["title"];
|
||||
anime.imageUrl = data["thumbnail"] ?? "";
|
||||
anime.link =
|
||||
"${sourceInfo.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<MPages> search(MSource sourceInfo, String query, int page) async {
|
||||
final data = {
|
||||
"url": "${sourceInfo.baseUrl}/api/DramaList/Search?q=$query&type=0"
|
||||
};
|
||||
final res = await MBridge.http('GET', json.encode(data));
|
||||
final jsonRes = json.decode(res);
|
||||
List<MManga> animeList = [];
|
||||
for (var data in jsonRes) {
|
||||
MManga anime = MManga();
|
||||
anime.name = data["title"];
|
||||
anime.imageUrl = data["thumbnail"] ?? "";
|
||||
anime.link =
|
||||
"${sourceInfo.baseUrl}/api/DramaList/Drama/${data["id"]}?isq=false";
|
||||
animeList.add(anime);
|
||||
}
|
||||
return MPages(animeList, false);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MManga> getDetail(MSource sourceInfo, String url) async {
|
||||
final statusList = [
|
||||
{
|
||||
"Ongoing": 0,
|
||||
"Completed": 1,
|
||||
}
|
||||
];
|
||||
final data = {"url": url};
|
||||
final res = await MBridge.http('GET', json.encode(data));
|
||||
MManga anime = MManga();
|
||||
final jsonRes = json.decode(res);
|
||||
final status = jsonRes["status"] ?? "";
|
||||
print(status);
|
||||
anime.description = jsonRes["description"];
|
||||
anime.status = MBridge.parseStatus(status, statusList);
|
||||
anime.imageUrl = jsonRes["thumbnail"];
|
||||
var episodes = jsonRes["episodes"];
|
||||
String type = jsonRes["type"];
|
||||
final episodesCount = jsonRes["episodesCount"];
|
||||
final containsAnime = type.contains("Anime");
|
||||
final containsTVSeries = type.contains("TVSeries");
|
||||
final containsHollywood = type.contains("Hollywood");
|
||||
final containsMovie = type.contains("Movie");
|
||||
List<MChapter>? 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 =
|
||||
"${sourceInfo.baseUrl}/api/DramaList/Episode/$id.png?err=false&ts=&time=";
|
||||
episodesList.add(episode);
|
||||
}
|
||||
|
||||
anime.chapters = episodesList;
|
||||
return anime;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<MVideo>> getVideoList(MSource sourceInfo, String url) async {
|
||||
final datas = {"url": url};
|
||||
|
||||
final res = await MBridge.http('GET', json.encode(datas));
|
||||
final id = MBridge.substringAfter(
|
||||
MBridge.substringBefore(url, ".png"), "Episode/");
|
||||
final jsonRes = json.decode(res);
|
||||
|
||||
final subRes = await MBridge.http(
|
||||
'GET', json.encode({"url": "${sourceInfo.baseUrl}/api/Sub/$id"}));
|
||||
var jsonSubRes = json.decode(subRes);
|
||||
|
||||
List<MTrack> subtitles = [];
|
||||
|
||||
for (var sub in jsonSubRes) {
|
||||
try {
|
||||
final subUrl = sub["src"];
|
||||
final label = sub["label"];
|
||||
MTrack subtitle = MTrack();
|
||||
subtitle
|
||||
..label = label
|
||||
..file = subUrl;
|
||||
subtitles.add(subtitle);
|
||||
} catch (_) {}
|
||||
}
|
||||
final videoUrl = jsonRes["Video"];
|
||||
MVideo video = MVideo();
|
||||
video
|
||||
..url = videoUrl
|
||||
..originalUrl = videoUrl
|
||||
..quality = "kisskh"
|
||||
..subtitles = subtitles
|
||||
..headers = {
|
||||
"referer": "https://kisskh.me/",
|
||||
"origin": "https://kisskh.me"
|
||||
};
|
||||
return [video];
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<String>> getPageList(MSource sourceInfo, String url) async {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
KissKh main() {
|
||||
return KissKh();
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import '../../../../model/source.dart';
|
||||
import '../../../../utils/utils.dart';
|
||||
|
||||
Source get kisskhSource => _kisskhSource;
|
||||
const kisskhVersion = "0.0.2";
|
||||
const kisskhVersion = "0.0.25";
|
||||
const kisskhSourceCodeUrl =
|
||||
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/src/en/kisskh/kisskh-v$kisskhVersion.dart";
|
||||
Source _kisskhSource = Source(
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
import 'dart:convert';
|
||||
import 'package:bridge_lib/bridge_lib.dart';
|
||||
|
||||
getPopularAnime(MManga anime) async {
|
||||
final data = {"url": "${anime.baseUrl}/"};
|
||||
final response = await MBridge.http('GET', json.encode(data));
|
||||
if (response.hasError) {
|
||||
return response;
|
||||
}
|
||||
String res = response.body;
|
||||
anime.urls = MBridge.xpath(res,
|
||||
'//*[contains(@class,"swiper-slide item-qtip")]/div[@class="item"]/a/@href');
|
||||
anime.names = MBridge.xpath(res,
|
||||
'//*[contains(@class,"swiper-slide item-qtip")]/div[@class="item"]/a/img/@title');
|
||||
anime.images = MBridge.xpath(res,
|
||||
'//*[contains(@class,"swiper-slide item-qtip")]/div[@class="item"]/a/img/@data-src');
|
||||
anime.hasNextPage = false;
|
||||
return anime;
|
||||
}
|
||||
|
||||
getLatestUpdatesAnime(MManga anime) async {
|
||||
final data = {"url": "${anime.baseUrl}/"};
|
||||
final response = await MBridge.http('GET', json.encode(data));
|
||||
if (response.hasError) {
|
||||
return response;
|
||||
}
|
||||
String res = response.body;
|
||||
|
||||
anime.urls = MBridge.xpath(res,
|
||||
'//*[@class="block_area block_area_home"]/div[@class="tab-content"]/div[contains(@class,"block_area-content block_area-list")]/div[@class="film_list-wrap"]/div[@class="flw-item"]/div[@class="film-poster"]/a/@href');
|
||||
anime.names = MBridge.xpath(res,
|
||||
'//*[@class="block_area block_area_home"]/div[@class="tab-content"]/div[contains(@class,"block_area-content block_area-list")]/div[@class="film_list-wrap"]/div[@class="flw-item"]/div[@class="film-poster"]/a/@title');
|
||||
anime.images = MBridge.xpath(res,
|
||||
'//*[@class="block_area block_area_home"]/div[@class="tab-content"]/div[contains(@class,"block_area-content block_area-list")]/div[@class="film_list-wrap"]/div[@class="flw-item"]/div[@class="film-poster"]/img/@data-src');
|
||||
anime.hasNextPage = false;
|
||||
return anime;
|
||||
}
|
||||
|
||||
searchAnime(MManga anime) async {
|
||||
final url =
|
||||
"${anime.baseUrl}/?story=${anime.query}&do=search&subaction=search";
|
||||
final data = {"url": url};
|
||||
final response = await MBridge.http('GET', json.encode(data));
|
||||
if (response.hasError) {
|
||||
return response;
|
||||
}
|
||||
String res = response.body;
|
||||
anime.urls = MBridge.xpath(res, '//*[@class="film-poster"]/a/@href');
|
||||
anime.names = MBridge.xpath(res, '//*[@class="film-poster"]/a/@title');
|
||||
anime.images = MBridge.xpath(res, '//*[@class="film-poster"]/img/@data-src');
|
||||
anime.hasNextPage = false;
|
||||
return anime;
|
||||
}
|
||||
|
||||
getAnimeDetail(MManga anime) async {
|
||||
final statusList = [
|
||||
{
|
||||
"En cours": 0,
|
||||
"Terminé": 1,
|
||||
}
|
||||
];
|
||||
final url = anime.link;
|
||||
final data = {"url": url};
|
||||
final response = await MBridge.http('GET', json.encode(data));
|
||||
if (response.hasError) {
|
||||
return response;
|
||||
}
|
||||
String res = response.body;
|
||||
anime.description =
|
||||
MBridge.xpath(res, '//*[@class="film-description m-hide"]/text()').first;
|
||||
|
||||
final status = MBridge.xpath(res,
|
||||
'//*[@class="item item-title" and contains(text(),"Status:")]/span[2]/text()')
|
||||
.first;
|
||||
anime.status = MBridge.parseStatus(status, statusList);
|
||||
anime.genre = MBridge.xpath(res,
|
||||
'//*[@class="item item-list" and contains(text(),"Genres:")]/a/text()');
|
||||
anime.author = MBridge.xpath(res,
|
||||
'//*[@class="item item-title" and contains(text(),"Studio:")]/span[2]/text()')
|
||||
.first;
|
||||
final urlEp = anime.link.replaceAll('.html', '/episode-1.html');
|
||||
final resEpWebview =
|
||||
await MBridge.getHtmlViaWebview(urlEp, '//*[@class="ss-list"]/a/@href');
|
||||
anime.urls = MBridge.xpath(resEpWebview, '//*[@class="ss-list"]/a/@href')
|
||||
.reversed
|
||||
.toList();
|
||||
anime.names = MBridge.xpath(resEpWebview,
|
||||
'//*[@class="ss-list"]/a/div[@class="ssli-detail"]/div/text()')
|
||||
.reversed
|
||||
.toList();
|
||||
anime.chaptersDateUploads = [];
|
||||
return anime;
|
||||
}
|
||||
|
||||
getVideoList(MManga anime) async {
|
||||
final resWebview = await MBridge.getHtmlViaWebview(
|
||||
anime.link, '//*[@class="ps__-list"]/div/@data-server-id');
|
||||
|
||||
final serverIds =
|
||||
MBridge.xpath(resWebview, '//*[@class="ps__-list"]/div/@data-server-id');
|
||||
final serverNames =
|
||||
MBridge.xpath(resWebview, '//*[@class="ps__-list"]/div/a/text()');
|
||||
List<String> serverUrls = [];
|
||||
for (var id in serverIds) {
|
||||
final serversUrls =
|
||||
MBridge.xpath(resWebview, '//*[@id="content_player_${id}"]/text()')
|
||||
.first;
|
||||
serverUrls.add(serversUrls);
|
||||
}
|
||||
List<MVideo> videos = [];
|
||||
for (var i = 0; i < serverNames.length; i++) {
|
||||
final name = serverNames[i];
|
||||
final url = serverUrls[i];
|
||||
|
||||
List<MVideo> a = [];
|
||||
if (name.contains("Sendvid")) {
|
||||
a = await MBridge.sendVidExtractor(
|
||||
url.replaceAll("https:////", "https://"),
|
||||
json.encode({"Referer": "${anime.baseUrl}/"}),
|
||||
"");
|
||||
} else if (name.contains("Sibnet")) {
|
||||
a = await MBridge.sibnetExtractor(
|
||||
"https://video.sibnet.ru/shell.php?videoid=$url");
|
||||
} else if (name.contains("Mytv")) {
|
||||
a = await MBridge.myTvExtractor("https://www.myvi.tv/embed/$url");
|
||||
}
|
||||
for (var vi in a) {
|
||||
videos.add(vi);
|
||||
}
|
||||
}
|
||||
|
||||
return videos;
|
||||
}
|
||||
171
anime/src/fr/animesultra/animesultra-v0.0.35.dart
Normal file
171
anime/src/fr/animesultra/animesultra-v0.0.35.dart
Normal file
@@ -0,0 +1,171 @@
|
||||
import 'package:mangayomi/bridge_lib.dart';
|
||||
import 'dart:convert';
|
||||
|
||||
class AnimesUltra extends MSourceProvider {
|
||||
AnimesUltra();
|
||||
|
||||
@override
|
||||
Future<MPages> getPopular(MSource sourceInfo, int page) async {
|
||||
final data = {"url": "${sourceInfo.baseUrl}/"};
|
||||
final res = await MBridge.http('GET', json.encode(data));
|
||||
|
||||
List<MManga> animeList = [];
|
||||
final urls = MBridge.xpath(res,
|
||||
'//*[contains(@class,"swiper-slide item-qtip")]/div[@class="item"]/a/@href');
|
||||
final names = MBridge.xpath(res,
|
||||
'//*[contains(@class,"swiper-slide item-qtip")]/div[@class="item"]/a/img/@title');
|
||||
final images = MBridge.xpath(res,
|
||||
'//*[contains(@class,"swiper-slide item-qtip")]/div[@class="item"]/a/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<MPages> getLatestUpdates(MSource sourceInfo, int page) async {
|
||||
final data = {"url": "${sourceInfo.baseUrl}/"};
|
||||
final res = await MBridge.http('GET', json.encode(data));
|
||||
|
||||
List<MManga> animeList = [];
|
||||
final urls = MBridge.xpath(res,
|
||||
'//*[@class="block_area block_area_home"]/div[@class="tab-content"]/div[contains(@class,"block_area-content block_area-list")]/div[@class="film_list-wrap"]/div[@class="flw-item"]/div[@class="film-poster"]/a/@href');
|
||||
final names = MBridge.xpath(res,
|
||||
'//*[@class="block_area block_area_home"]/div[@class="tab-content"]/div[contains(@class,"block_area-content block_area-list")]/div[@class="film_list-wrap"]/div[@class="flw-item"]/div[@class="film-poster"]/a/@title');
|
||||
final images = MBridge.xpath(res,
|
||||
'//*[@class="block_area block_area_home"]/div[@class="tab-content"]/div[contains(@class,"block_area-content block_area-list")]/div[@class="film_list-wrap"]/div[@class="flw-item"]/div[@class="film-poster"]/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<MPages> search(MSource sourceInfo, String query, int page) async {
|
||||
final data = {"url": "${sourceInfo.baseUrl}/"};
|
||||
final res = await MBridge.http('GET', json.encode(data));
|
||||
|
||||
List<MManga> animeList = [];
|
||||
final urls = MBridge.xpath(res, '//*[@class="film-poster"]/a/@href');
|
||||
final names = MBridge.xpath(res, '//*[@class="film-poster"]/a/@title');
|
||||
final images =
|
||||
MBridge.xpath(res, '//*[@class="film-poster"]/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<MManga> getDetail(MSource sourceInfo, String url) async {
|
||||
final statusList = [
|
||||
{
|
||||
"En cours": 0,
|
||||
"Terminé": 1,
|
||||
}
|
||||
];
|
||||
final data = {"url": url};
|
||||
final res = await MBridge.http('GET', json.encode(data));
|
||||
MManga anime = MManga();
|
||||
anime.description =
|
||||
MBridge.xpath(res, '//*[@class="film-description m-hide"]/text()')
|
||||
.first;
|
||||
|
||||
final status = MBridge.xpath(res,
|
||||
'//*[@class="item item-title" and contains(text(),"Status:")]/span[2]/text()')
|
||||
.first;
|
||||
anime.status = MBridge.parseStatus(status, statusList);
|
||||
anime.genre = MBridge.xpath(res,
|
||||
'//*[@class="item item-list" and contains(text(),"Genres:")]/a/text()');
|
||||
anime.author = MBridge.xpath(res,
|
||||
'//*[@class="item item-title" and contains(text(),"Studio:")]/span[2]/text()')
|
||||
.first;
|
||||
final urlEp = url.replaceAll('.html', '/episode-1.html');
|
||||
final resEpWebview =
|
||||
await MBridge.getHtmlViaWebview(urlEp, '//*[@class="ss-list"]/a/@href');
|
||||
final epUrls = MBridge.xpath(resEpWebview, '//*[@class="ss-list"]/a/@href')
|
||||
.reversed
|
||||
.toList();
|
||||
final names = MBridge.xpath(resEpWebview,
|
||||
'//*[@class="ss-list"]/a/div[@class="ssli-detail"]/div/text()')
|
||||
.reversed
|
||||
.toList();
|
||||
|
||||
List<MChapter>? episodesList = [];
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
MChapter episode = MChapter();
|
||||
episode.name = names[i];
|
||||
episode.url = epUrls[i];
|
||||
episodesList.add(episode);
|
||||
}
|
||||
|
||||
anime.chapters = episodesList;
|
||||
return anime;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<MVideo>> getVideoList(MSource sourceInfo, String url) async {
|
||||
final resWebview = await MBridge.getHtmlViaWebview(
|
||||
url, '//*[@class="ps__-list"]/div/@data-server-id');
|
||||
|
||||
final serverIds = MBridge.xpath(
|
||||
resWebview, '//*[@class="ps__-list"]/div/@data-server-id');
|
||||
final serverNames =
|
||||
MBridge.xpath(resWebview, '//*[@class="ps__-list"]/div/a/text()');
|
||||
List<String> serverUrls = [];
|
||||
for (var id in serverIds) {
|
||||
final serversUrls =
|
||||
MBridge.xpath(resWebview, '//*[@id="content_player_${id}"]/text()')
|
||||
.first;
|
||||
serverUrls.add(serversUrls);
|
||||
}
|
||||
List<MVideo> videos = [];
|
||||
for (var i = 0; i < serverNames.length; i++) {
|
||||
final name = serverNames[i];
|
||||
final url = serverUrls[i];
|
||||
|
||||
List<MVideo> a = [];
|
||||
if (name.contains("Sendvid")) {
|
||||
a = await MBridge.sendVidExtractor(
|
||||
url.replaceAll("https:////", "https://"),
|
||||
json.encode({"Referer": "${sourceInfo.baseUrl}/"}),
|
||||
"");
|
||||
} else if (name.contains("Sibnet")) {
|
||||
a = await MBridge.sibnetExtractor(
|
||||
"https://video.sibnet.ru/shell.php?videoid=$url");
|
||||
} else if (name.contains("Mytv")) {
|
||||
a = await MBridge.myTvExtractor("https://www.myvi.tv/embed/$url");
|
||||
}
|
||||
videos.addAll(a);
|
||||
}
|
||||
|
||||
return videos;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<String>> getPageList(MSource sourceInfo, String url) async {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
AnimesUltra main() {
|
||||
return AnimesUltra();
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import '../../../../model/source.dart';
|
||||
import '../../../../utils/utils.dart';
|
||||
|
||||
Source get animesultraSource => _animesultraSource;
|
||||
const animesultraVersion = "0.0.3";
|
||||
const animesultraVersion = "0.0.35";
|
||||
const animesultraSourceCodeUrl =
|
||||
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/src/fr/animesultra/animesultra-v$animesultraVersion.dart";
|
||||
Source _animesultraSource = Source(
|
||||
|
||||
@@ -1,386 +0,0 @@
|
||||
import 'dart:convert';
|
||||
import 'package:bridge_lib/bridge_lib.dart';
|
||||
|
||||
Future<MHttpResponse> dataBase(int sourceId) async {
|
||||
final data = {
|
||||
"url": "https://api.franime.fr/api/animes/",
|
||||
"headers": {"Referer": "https://franime.fr/"}
|
||||
};
|
||||
|
||||
return await MBridge.http('GET', json.encode(data));
|
||||
}
|
||||
|
||||
getPopularAnime(MManga anime) async {
|
||||
final data = {
|
||||
"url": "https://api.franime.fr/api/animes/",
|
||||
"headers": {"Referer": "https://franime.fr/"}
|
||||
};
|
||||
final res = await MBridge.http('GET', json.encode(data));
|
||||
if (res.hasError) {
|
||||
return res;
|
||||
}
|
||||
List<MManga> animeList = animeResList(res.body);
|
||||
|
||||
return animeList;
|
||||
}
|
||||
|
||||
List<MManga> animeResList(String res) {
|
||||
final statusList = [
|
||||
{"EN COURS": 0, "TERMINÉ": 1}
|
||||
];
|
||||
List<MManga> animeList = [];
|
||||
|
||||
var jsonResList = json.decode(res);
|
||||
|
||||
for (var animeJson in jsonResList) {
|
||||
final seasons = animeJson["saisons"];
|
||||
List<bool> vostfrListName = [];
|
||||
List<bool> vfListName = [];
|
||||
for (var season in seasons) {
|
||||
for (var episode in season["episodes"]) {
|
||||
final lang = episode["lang"];
|
||||
final vo = lang["vo"];
|
||||
final vf = lang["vf"];
|
||||
vostfrListName.add(vo["lecteurs"].isNotEmpty);
|
||||
vfListName.add(vf["lecteurs"].isNotEmpty);
|
||||
}
|
||||
}
|
||||
|
||||
final titleO = animeJson["titleO"];
|
||||
final title = animeJson["title"];
|
||||
final genre = animeJson["themes"];
|
||||
final description = animeJson["description"];
|
||||
final status = MBridge.parseStatus(animeJson["status"], statusList);
|
||||
final imageUrl = animeJson["affiche"];
|
||||
bool hasVostfr = vostfrListName.contains(true);
|
||||
bool hasVf = vfListName.contains(true);
|
||||
if (hasVostfr || hasVf) {
|
||||
for (int i = 0; i < seasons.length; i++) {
|
||||
MManga anime = MManga();
|
||||
int ind = i + 1;
|
||||
anime.genre = genre;
|
||||
anime.description = description;
|
||||
String seasonTitle = "".toString();
|
||||
String lang = "";
|
||||
if (title.isEmpty) {
|
||||
seasonTitle = titleO;
|
||||
} else {
|
||||
seasonTitle = title;
|
||||
}
|
||||
if (seasons.length > 1) {
|
||||
seasonTitle += " S$ind";
|
||||
}
|
||||
if (hasVf) {
|
||||
seasonTitle += " VF";
|
||||
lang = "vf".toString();
|
||||
}
|
||||
if (hasVostfr) {
|
||||
seasonTitle += " VOSTFR";
|
||||
lang = "vo".toString();
|
||||
}
|
||||
|
||||
anime.status = status;
|
||||
anime.name = seasonTitle;
|
||||
anime.imageUrl = imageUrl;
|
||||
anime.link =
|
||||
"/anime/${MBridge.regExp(titleO, "[^A-Za-z0-9 ]", "", 0, 0).replaceAll(" ", "-").toLowerCase()}?lang=$lang&s=$ind";
|
||||
|
||||
animeList.add(anime);
|
||||
}
|
||||
}
|
||||
}
|
||||
return animeList;
|
||||
}
|
||||
|
||||
String databaseAnimeByTitleO(String res, String titleO) {
|
||||
final datas = MBridge.jsonDecodeToList(res, 1);
|
||||
for (var data in datas) {
|
||||
if (MBridge.regExp(
|
||||
MBridge.getMapValue(data, "titleO"), "[^A-Za-z0-9 ]", "", 0, 0)
|
||||
.replaceAll(" ", "-")
|
||||
.toLowerCase() ==
|
||||
"${titleO}") {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
getAnimeDetail(MManga anime) async {
|
||||
String language = "vo".toString();
|
||||
if (anime.link.contains("lang=")) {
|
||||
language = MBridge.substringBefore(
|
||||
MBridge.substringAfter(anime.link, "lang="), "&");
|
||||
}
|
||||
String stem =
|
||||
MBridge.substringBefore(MBridge.substringAfterLast(anime.link, "/"), "?");
|
||||
final res = await dataBase(anime.sourceId);
|
||||
if (res.hasError) {
|
||||
return res;
|
||||
}
|
||||
final animeByTitleOJson = databaseAnimeByTitleO(res.body, stem);
|
||||
if (animeByTitleOJson.isEmpty) {
|
||||
return anime;
|
||||
}
|
||||
final seasons = json.decode(animeByTitleOJson)["saisons"];
|
||||
|
||||
var seasonsJson = seasons.first;
|
||||
|
||||
if (anime.link.contains("s=")) {
|
||||
int seasonNumber = MBridge.intParse(
|
||||
MBridge.substringBefore(MBridge.substringAfter(anime.link, "s="), "&"));
|
||||
seasonsJson = seasons[seasonNumber - 1];
|
||||
}
|
||||
|
||||
final episodes = seasonsJson["episodes"];
|
||||
|
||||
List<String> episodesNames = [];
|
||||
List<String> episodesUrls = [];
|
||||
for (int i = 0; i < episodes.length; i++) {
|
||||
final episode = episodes[i];
|
||||
|
||||
final lang = episode["lang"];
|
||||
|
||||
final vo = lang["vo"];
|
||||
final vf = lang["vf"];
|
||||
bool hasVostfr = vo["lecteurs"].isNotEmpty;
|
||||
bool hasVf = vf["lecteurs"].isNotEmpty;
|
||||
bool playerIsNotEmpty = false;
|
||||
|
||||
if (language == "vo" && hasVostfr) {
|
||||
playerIsNotEmpty = true;
|
||||
} else if (language == "vf" && hasVf) {
|
||||
playerIsNotEmpty = true;
|
||||
}
|
||||
if (playerIsNotEmpty) {
|
||||
episodesUrls.add("${anime.link}&ep=${i + 1}");
|
||||
String title = episode["title"];
|
||||
episodesNames.add(title.replaceAll('"', ""));
|
||||
}
|
||||
}
|
||||
|
||||
anime.urls = episodesUrls.reversed.toList();
|
||||
anime.names = episodesNames.reversed.toList();
|
||||
anime.chaptersDateUploads = [];
|
||||
return anime;
|
||||
}
|
||||
|
||||
getLatestUpdatesAnime(MManga anime) async {
|
||||
final res = await dataBase(anime.sourceId);
|
||||
|
||||
if (res.hasError) {
|
||||
return res;
|
||||
}
|
||||
List list = json.decode(res.body);
|
||||
List reversedList = list.reversed.toList();
|
||||
List<MManga> animeList = animeResList(json.encode(reversedList));
|
||||
|
||||
return animeList;
|
||||
}
|
||||
|
||||
searchAnime(MManga anime) async {
|
||||
final res = await dataBase(anime.sourceId);
|
||||
|
||||
if (res.hasError) {
|
||||
return res;
|
||||
}
|
||||
List<MManga> animeList = animeSeachFetch(res.body, anime.query);
|
||||
return animeList;
|
||||
}
|
||||
|
||||
List<MManga> animeSeachFetch(String res, query) {
|
||||
final statusList = [
|
||||
{"EN COURS": 0, "TERMINÉ": 1}
|
||||
];
|
||||
List<MManga> animeList = [];
|
||||
final jsonResList = json.decode(res);
|
||||
for (var animeJson in jsonResList) {
|
||||
MManga anime = MManga();
|
||||
|
||||
final titleO = MBridge.getMapValue(json.encode(animeJson), "titleO");
|
||||
final titleAlt =
|
||||
MBridge.getMapValue(json.encode(animeJson), "titles", encode: true);
|
||||
final enContains = MBridge.getMapValue(titleAlt, "en")
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.contains(query);
|
||||
final enJpContains = MBridge.getMapValue(titleAlt, "en_jp")
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.contains(query);
|
||||
final jaJpContains = MBridge.getMapValue(titleAlt, "ja_jp")
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.contains(query);
|
||||
final titleOContains = titleO.toLowerCase().contains(query);
|
||||
bool contains = false;
|
||||
if (enContains) {
|
||||
contains = true;
|
||||
}
|
||||
if (enJpContains) {
|
||||
contains = true;
|
||||
}
|
||||
if (jaJpContains) {
|
||||
contains = true;
|
||||
}
|
||||
if (titleOContains) {
|
||||
contains = true;
|
||||
}
|
||||
if (contains) {
|
||||
final seasons = animeJson["saisons"];
|
||||
List<bool> vostfrListName = [];
|
||||
List<bool> vfListName = [];
|
||||
for (var season in seasons) {
|
||||
for (var episode in season["episodes"]) {
|
||||
final lang = episode["lang"];
|
||||
final vo = lang["vo"];
|
||||
final vf = lang["vf"];
|
||||
vostfrListName.add(vo["lecteurs"].isNotEmpty);
|
||||
vfListName.add(vf["lecteurs"].isNotEmpty);
|
||||
}
|
||||
}
|
||||
final titleO = animeJson["titleO"];
|
||||
final title = animeJson["title"];
|
||||
final genre = animeJson["themes"];
|
||||
final description = animeJson["description"];
|
||||
final status = MBridge.parseStatus(animeJson["status"], statusList);
|
||||
final imageUrl = animeJson["affiche"];
|
||||
|
||||
bool hasVostfr = vostfrListName.contains(true);
|
||||
bool hasVf = vfListName.contains(true);
|
||||
if (hasVostfr || hasVf) {
|
||||
for (int i = 0; i < seasons.length; i++) {
|
||||
MManga anime = MManga();
|
||||
int ind = i + 1;
|
||||
anime.genre = genre;
|
||||
anime.description = description;
|
||||
String seasonTitle = "".toString();
|
||||
String lang = "";
|
||||
if (title.isEmpty) {
|
||||
seasonTitle = titleO;
|
||||
} else {
|
||||
seasonTitle = title;
|
||||
}
|
||||
if (seasons.length > 1) {
|
||||
seasonTitle += " S$ind";
|
||||
}
|
||||
if (hasVf) {
|
||||
seasonTitle += " VF";
|
||||
lang = "vf".toString();
|
||||
}
|
||||
if (hasVostfr) {
|
||||
seasonTitle += " VOSTFR";
|
||||
lang = "vo".toString();
|
||||
}
|
||||
|
||||
anime.status = status;
|
||||
anime.name = seasonTitle;
|
||||
anime.imageUrl = imageUrl;
|
||||
anime.link =
|
||||
"/anime/${MBridge.regExp(titleO, "[^A-Za-z0-9 ]", "", 0, 0).replaceAll(" ", "-").toLowerCase()}?lang=$lang&s=$ind";
|
||||
|
||||
animeList.add(anime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return animeList;
|
||||
}
|
||||
|
||||
getVideoList(MManga anime) async {
|
||||
String language = "vo".toString();
|
||||
String videoBaseUrl = "https://api.franime.fr/api/anime".toString();
|
||||
if (anime.link.contains("lang=")) {
|
||||
language = MBridge.substringBefore(
|
||||
MBridge.substringAfter(anime.link, "lang="), "&");
|
||||
print(language);
|
||||
}
|
||||
String stem =
|
||||
MBridge.substringBefore(MBridge.substringAfterLast(anime.link, "/"), "?");
|
||||
final res = await dataBase(anime.sourceId);
|
||||
if (res.hasError) {
|
||||
return res;
|
||||
}
|
||||
final animeByTitleOJson = databaseAnimeByTitleO(res.body, stem);
|
||||
if (animeByTitleOJson.isEmpty) {
|
||||
return anime;
|
||||
}
|
||||
final animeId = json.decode(animeByTitleOJson)["id"];
|
||||
final seasons = json.decode(animeByTitleOJson)["saisons"];
|
||||
|
||||
var seasonsJson = seasons.first;
|
||||
|
||||
videoBaseUrl += "/$animeId/";
|
||||
|
||||
if (anime.link.contains("s=")) {
|
||||
int seasonNumber = MBridge.intParse(
|
||||
MBridge.substringBefore(MBridge.substringAfter(anime.link, "s="), "&"));
|
||||
print(seasonNumber);
|
||||
videoBaseUrl += "${seasonNumber - 1}/";
|
||||
seasonsJson = seasons[seasonNumber - 1];
|
||||
} else {
|
||||
videoBaseUrl += "0/";
|
||||
}
|
||||
final episodesJson = seasonsJson["episodes"];
|
||||
var episode = episodesJson.first;
|
||||
if (anime.link.contains("ep=")) {
|
||||
int episodeNumber =
|
||||
MBridge.intParse(MBridge.substringAfter(anime.link, "ep="));
|
||||
print(episodeNumber);
|
||||
episode = episodesJson[episodeNumber - 1];
|
||||
videoBaseUrl += "${episodeNumber - 1}";
|
||||
} else {
|
||||
videoBaseUrl += "0";
|
||||
}
|
||||
final lang = episode["lang"];
|
||||
|
||||
final vo = lang["vo"];
|
||||
final vf = lang["vf"];
|
||||
bool hasVostfr = vo["lecteurs"].isNotEmpty;
|
||||
bool hasVf = vf["lecteurs"].isNotEmpty;
|
||||
List<String> vostfrPlayers = vo["lecteurs"];
|
||||
List<String> vfPlayers = vf["lecteurs"];
|
||||
List<String> players = [];
|
||||
if (language == "vo" && hasVostfr) {
|
||||
players = vostfrPlayers;
|
||||
} else if (language == "vf" && hasVf) {
|
||||
players = vfPlayers;
|
||||
}
|
||||
List<MVideo> videos = [];
|
||||
for (var i = 0; i < players.length; i++) {
|
||||
String apiUrl = "$videoBaseUrl/$language/$i";
|
||||
String playerName = players[i];
|
||||
|
||||
MVideo video = MVideo();
|
||||
|
||||
final data = {
|
||||
"url": apiUrl,
|
||||
"headers": {"Referer": "https://franime.fr/"},
|
||||
"sourceId": anime.sourceId
|
||||
};
|
||||
final requestPlayerUrl = await MBridge.http('GET', json.encode(data));
|
||||
if (requestPlayerUrl.hasError) {
|
||||
return requestPlayerUrl;
|
||||
}
|
||||
String playerUrl = requestPlayerUrl.body;
|
||||
List<MVideo> a = [];
|
||||
if (playerName.contains("franime_myvi")) {
|
||||
videos.add(video
|
||||
..url = playerUrl
|
||||
..originalUrl = playerUrl
|
||||
..quality = "FRAnime");
|
||||
} else if (playerName.contains("myvi")) {
|
||||
a = await MBridge.myTvExtractor(playerUrl);
|
||||
} else if (playerName.contains("sendvid")) {
|
||||
a = await MBridge.sendVidExtractor(
|
||||
playerUrl, json.encode({"Referer": "https://franime.fr/"}), "");
|
||||
} else if (playerName.contains("sibnet")) {
|
||||
a = await MBridge.sibnetExtractor(playerUrl);
|
||||
} else if (playerName.contains("sbfull")) {}
|
||||
for (var vi in a) {
|
||||
videos.add(vi);
|
||||
}
|
||||
}
|
||||
|
||||
return videos;
|
||||
}
|
||||
364
anime/src/fr/franime/franime-v0.0.35.dart
Normal file
364
anime/src/fr/franime/franime-v0.0.35.dart
Normal file
@@ -0,0 +1,364 @@
|
||||
import 'package:mangayomi/bridge_lib.dart';
|
||||
import 'package:mangayomi/utils.dart';
|
||||
import 'dart:convert';
|
||||
|
||||
class FrAnime extends MSourceProvider {
|
||||
FrAnime();
|
||||
|
||||
@override
|
||||
Future<MPages> getPopular(MSource sourceInfo, int page) async {
|
||||
final data = {
|
||||
"url": "https://api.franime.fr/api/animes/",
|
||||
"headers": {"Referer": "https://franime.fr/"}
|
||||
};
|
||||
final res = await MBridge.http('GET', json.encode(data));
|
||||
|
||||
return animeResList(res);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MPages> getLatestUpdates(MSource sourceInfo, int page) async {
|
||||
final res = await dataBase();
|
||||
|
||||
List list = json.decode(res);
|
||||
return animeResList(json.encode(list.reversed.toList()));
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MPages> search(MSource sourceInfo, String query, int page) async {
|
||||
final res = await dataBase();
|
||||
|
||||
return animeSeachFetch(res, query);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MManga> getDetail(MSource sourceInfo, String url) async {
|
||||
MManga anime = MManga();
|
||||
String language = "vo".toString();
|
||||
if (url.contains("lang=")) {
|
||||
language =
|
||||
Substring(url).substringAfter("lang=").substringBefore("&").text;
|
||||
print(language);
|
||||
}
|
||||
String stem =
|
||||
Substring(url).substringAfterLast("/").substringBefore("?").text;
|
||||
final res = await dataBase();
|
||||
|
||||
final animeByTitleOJson = databaseAnimeByTitleO(res, stem);
|
||||
final seasons = json.decode(animeByTitleOJson)["saisons"];
|
||||
|
||||
var seasonsJson = seasons.first;
|
||||
|
||||
if (url.contains("s=")) {
|
||||
int seasonNumber = int.parse(
|
||||
Substring(url).substringAfter("s=").substringBefore("&").text);
|
||||
seasonsJson = seasons[seasonNumber - 1];
|
||||
}
|
||||
|
||||
List<MChapter>? episodesList = [];
|
||||
|
||||
final episodes = seasonsJson["episodes"];
|
||||
|
||||
for (int i = 0; i < episodes.length; i++) {
|
||||
final ep = episodes[i];
|
||||
|
||||
final lang = ep["lang"];
|
||||
|
||||
final vo = lang["vo"];
|
||||
final vf = lang["vf"];
|
||||
bool hasVostfr = vo["lecteurs"].isNotEmpty;
|
||||
bool hasVf = vf["lecteurs"].isNotEmpty;
|
||||
bool playerIsNotEmpty = false;
|
||||
|
||||
if (language == "vo" && hasVostfr) {
|
||||
playerIsNotEmpty = true;
|
||||
} else if (language == "vf" && hasVf) {
|
||||
playerIsNotEmpty = true;
|
||||
}
|
||||
if (playerIsNotEmpty) {
|
||||
MChapter episode = MChapter();
|
||||
episode.url = "$url&ep=${i + 1}";
|
||||
String title = ep["title"];
|
||||
episode.name = title.replaceAll('"', "");
|
||||
episodesList.add(episode);
|
||||
}
|
||||
}
|
||||
|
||||
anime.chapters = episodesList;
|
||||
return anime;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<MVideo>> getVideoList(MSource sourceInfo, String url) async {
|
||||
String language = "vo".toString();
|
||||
String videoBaseUrl = "https://api.franime.fr/api/anime".toString();
|
||||
if (url.contains("lang=")) {
|
||||
language =
|
||||
Substring(url).substringAfter("lang=").substringBefore("&").text;
|
||||
print(language);
|
||||
}
|
||||
String stem =
|
||||
Substring(url).substringAfterLast("/").substringBefore("?").text;
|
||||
final res = await dataBase();
|
||||
|
||||
final animeByTitleOJson = databaseAnimeByTitleO(res, stem);
|
||||
final animeId = json.decode(animeByTitleOJson)["id"];
|
||||
final seasons = json.decode(animeByTitleOJson)["saisons"];
|
||||
|
||||
var seasonsJson = seasons.first;
|
||||
|
||||
videoBaseUrl += "/$animeId/";
|
||||
|
||||
if (url.contains("s=")) {
|
||||
int seasonNumber = int.parse(
|
||||
Substring(url).substringAfter("s=").substringBefore("&").text);
|
||||
print(seasonNumber);
|
||||
videoBaseUrl += "${seasonNumber - 1}/";
|
||||
seasonsJson = seasons[seasonNumber - 1];
|
||||
} else {
|
||||
videoBaseUrl += "0/";
|
||||
}
|
||||
final episodesJson = seasonsJson["episodes"];
|
||||
var episode = episodesJson.first;
|
||||
if (url.contains("ep=")) {
|
||||
int episodeNumber = int.parse(Substring(url).substringAfter("ep=").text);
|
||||
print(episodeNumber);
|
||||
episode = episodesJson[episodeNumber - 1];
|
||||
videoBaseUrl += "${episodeNumber - 1}";
|
||||
} else {
|
||||
videoBaseUrl += "0";
|
||||
}
|
||||
final lang = episode["lang"];
|
||||
|
||||
final vo = lang["vo"];
|
||||
final vf = lang["vf"];
|
||||
bool hasVostfr = vo["lecteurs"].isNotEmpty;
|
||||
bool hasVf = vf["lecteurs"].isNotEmpty;
|
||||
List<String> vostfrPlayers = vo["lecteurs"];
|
||||
List<String> vfPlayers = vf["lecteurs"];
|
||||
List<String> players = [];
|
||||
if (language == "vo" && hasVostfr) {
|
||||
players = vostfrPlayers;
|
||||
} else if (language == "vf" && hasVf) {
|
||||
players = vfPlayers;
|
||||
}
|
||||
List<MVideo> videos = [];
|
||||
for (var i = 0; i < players.length; i++) {
|
||||
String apiUrl = "$videoBaseUrl/$language/$i";
|
||||
String playerName = players[i];
|
||||
|
||||
MVideo video = MVideo();
|
||||
|
||||
final data = {
|
||||
"url": apiUrl,
|
||||
"headers": {"Referer": "https://franime.fr/"}
|
||||
};
|
||||
final playerUrl = await MBridge.http('GET', json.encode(data));
|
||||
|
||||
List<MVideo> a = [];
|
||||
if (playerName.contains("vido")) {
|
||||
videos.add(video
|
||||
..url = playerUrl
|
||||
..originalUrl = playerUrl
|
||||
..quality = "FRAnime (Vido)");
|
||||
} else if (playerName.contains("myvi")) {
|
||||
a = await MBridge.myTvExtractor(playerUrl);
|
||||
} else if (playerName.contains("sendvid")) {
|
||||
a = await MBridge.sendVidExtractor(
|
||||
playerUrl, json.encode({"Referer": "https://franime.fr/"}), "");
|
||||
} else if (playerName.contains("sibnet")) {
|
||||
a = await MBridge.sibnetExtractor(playerUrl);
|
||||
}
|
||||
videos.addAll(a);
|
||||
}
|
||||
|
||||
return videos;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<String>> getPageList(MSource sourceInfo, String url) async {
|
||||
return [];
|
||||
}
|
||||
|
||||
MPages animeResList(String res) {
|
||||
final statusList = [
|
||||
{"EN COURS": 0, "TERMINÉ": 1}
|
||||
];
|
||||
List<MManga> animeList = [];
|
||||
|
||||
var jsonResList = json.decode(res);
|
||||
|
||||
for (var animeJson in jsonResList) {
|
||||
final seasons = animeJson["saisons"];
|
||||
List<bool> vostfrListName = [];
|
||||
List<bool> vfListName = [];
|
||||
for (var season in seasons) {
|
||||
for (var episode in season["episodes"]) {
|
||||
final lang = episode["lang"];
|
||||
final vo = lang["vo"];
|
||||
final vf = lang["vf"];
|
||||
vostfrListName.add(vo["lecteurs"].isNotEmpty);
|
||||
vfListName.add(vf["lecteurs"].isNotEmpty);
|
||||
}
|
||||
}
|
||||
|
||||
final titleO = animeJson["titleO"];
|
||||
final title = animeJson["title"];
|
||||
final genre = animeJson["themes"];
|
||||
final description = animeJson["description"];
|
||||
final status = MBridge.parseStatus(animeJson["status"], statusList);
|
||||
final imageUrl = animeJson["affiche"];
|
||||
bool hasVostfr = vostfrListName.contains(true);
|
||||
bool hasVf = vfListName.contains(true);
|
||||
if (hasVostfr || hasVf) {
|
||||
for (int i = 0; i < seasons.length; i++) {
|
||||
MManga anime = MManga();
|
||||
int ind = i + 1;
|
||||
anime.genre = genre;
|
||||
anime.description = description;
|
||||
String seasonTitle = "".toString();
|
||||
String lang = "";
|
||||
if (title.isEmpty) {
|
||||
seasonTitle = titleO;
|
||||
} else {
|
||||
seasonTitle = title;
|
||||
}
|
||||
if (seasons.length > 1) {
|
||||
seasonTitle += " S$ind";
|
||||
}
|
||||
if (hasVf) {
|
||||
seasonTitle += " VF";
|
||||
lang = "vf".toString();
|
||||
}
|
||||
if (hasVostfr) {
|
||||
seasonTitle += " VOSTFR";
|
||||
lang = "vo".toString();
|
||||
}
|
||||
|
||||
anime.status = status;
|
||||
anime.name = seasonTitle;
|
||||
anime.imageUrl = imageUrl;
|
||||
anime.link =
|
||||
"/anime/${MBridge.regExp(titleO, "[^A-Za-z0-9 ]", "", 0, 0).replaceAll(" ", "-").toLowerCase()}?lang=$lang&s=$ind";
|
||||
|
||||
animeList.add(anime);
|
||||
}
|
||||
}
|
||||
}
|
||||
return MPages(animeList, true);
|
||||
}
|
||||
|
||||
MPages animeSeachFetch(String res, String query) {
|
||||
final statusList = [
|
||||
{"EN COURS": 0, "TERMINÉ": 1}
|
||||
];
|
||||
List<MManga> animeList = [];
|
||||
final jsonResList = json.decode(res);
|
||||
for (var animeJson in jsonResList) {
|
||||
MManga anime = MManga();
|
||||
|
||||
final titleO = MBridge.getMapValue(json.encode(animeJson), "titleO");
|
||||
final titleAlt =
|
||||
MBridge.getMapValue(json.encode(animeJson), "titles", encode: true);
|
||||
final containsEn = MBridge.getMapValue(titleAlt, "en")
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.contains(query.toLowerCase());
|
||||
final containsEnJp = MBridge.getMapValue(titleAlt, "en_jp")
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.contains(query.toLowerCase());
|
||||
final containsJaJp = MBridge.getMapValue(titleAlt, "ja_jp")
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.contains(query.toLowerCase());
|
||||
final containsTitleO = titleO.toLowerCase().contains(query.toLowerCase());
|
||||
|
||||
if (containsEn || containsEnJp || containsJaJp || containsTitleO) {
|
||||
final seasons = animeJson["saisons"];
|
||||
List<bool> vostfrListName = [];
|
||||
List<bool> vfListName = [];
|
||||
for (var season in seasons) {
|
||||
for (var episode in season["episodes"]) {
|
||||
final lang = episode["lang"];
|
||||
final vo = lang["vo"];
|
||||
final vf = lang["vf"];
|
||||
vostfrListName.add(vo["lecteurs"].isNotEmpty);
|
||||
vfListName.add(vf["lecteurs"].isNotEmpty);
|
||||
}
|
||||
}
|
||||
final titleO = animeJson["titleO"];
|
||||
final title = animeJson["title"];
|
||||
final genre = animeJson["themes"];
|
||||
final description = animeJson["description"];
|
||||
final status = MBridge.parseStatus(animeJson["status"], statusList);
|
||||
final imageUrl = animeJson["affiche"];
|
||||
|
||||
bool hasVostfr = vostfrListName.contains(true);
|
||||
bool hasVf = vfListName.contains(true);
|
||||
if (hasVostfr || hasVf) {
|
||||
for (int i = 0; i < seasons.length; i++) {
|
||||
MManga anime = MManga();
|
||||
int ind = i + 1;
|
||||
anime.genre = genre;
|
||||
anime.description = description;
|
||||
String seasonTitle = "".toString();
|
||||
String lang = "";
|
||||
if (title.isEmpty) {
|
||||
seasonTitle = titleO;
|
||||
} else {
|
||||
seasonTitle = title;
|
||||
}
|
||||
if (seasons.length > 1) {
|
||||
seasonTitle += " S$ind";
|
||||
}
|
||||
if (hasVf) {
|
||||
seasonTitle += " VF";
|
||||
lang = "vf".toString();
|
||||
}
|
||||
if (hasVostfr) {
|
||||
seasonTitle += " VOSTFR";
|
||||
lang = "vo".toString();
|
||||
}
|
||||
|
||||
anime.status = status;
|
||||
anime.name = seasonTitle;
|
||||
anime.imageUrl = imageUrl;
|
||||
anime.link =
|
||||
"/anime/${MBridge.regExp(titleO, "[^A-Za-z0-9 ]", "", 0, 0).replaceAll(" ", "-").toLowerCase()}?lang=$lang&s=$ind";
|
||||
|
||||
animeList.add(anime);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return MPages(animeList, true);
|
||||
}
|
||||
|
||||
Future<String> dataBase() async {
|
||||
final data = {
|
||||
"url": "https://api.franime.fr/api/animes/",
|
||||
"headers": {"Referer": "https://franime.fr/"}
|
||||
};
|
||||
|
||||
return await MBridge.http('GET', json.encode(data));
|
||||
}
|
||||
|
||||
String databaseAnimeByTitleO(String res, String titleO) {
|
||||
final datas = MBridge.jsonDecodeToList(res, 1);
|
||||
for (var data in datas) {
|
||||
if (MBridge.regExp(MBridge.getMapValue(data, "titleO"), "[^A-Za-z0-9 ]",
|
||||
"", 0, 0)
|
||||
.replaceAll(" ", "-")
|
||||
.toLowerCase() ==
|
||||
"${titleO}") {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
FrAnime main() {
|
||||
return FrAnime();
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import '../../../../model/source.dart';
|
||||
import '../../../../utils/utils.dart';
|
||||
|
||||
Source get franimeSource => _franimeSource;
|
||||
const franimeVersion = "0.0.3";
|
||||
const franimeVersion = "0.0.35";
|
||||
const franimeSourceCodeUrl =
|
||||
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/src/fr/franime/franime-v$franimeVersion.dart";
|
||||
Source _franimeSource = Source(
|
||||
|
||||
@@ -1,200 +0,0 @@
|
||||
import 'dart:convert';
|
||||
import 'package:bridge_lib/bridge_lib.dart';
|
||||
|
||||
getPopularAnime(MManga anime) async {
|
||||
final data = {
|
||||
"url": "${anime.baseUrl}/toute-la-liste-affiches/page/${anime.page}/?q=."
|
||||
};
|
||||
final response = await MBridge.http('GET', json.encode(data));
|
||||
if (response.hasError) {
|
||||
return response;
|
||||
}
|
||||
String res = response.body;
|
||||
anime.urls =
|
||||
MBridge.xpath(res, '//*[@class="list"]/article/div/div/figure/a/@href');
|
||||
anime.names = MBridge.xpath(
|
||||
res, '//*[@class="list"]/article/div/div/figure/a/img/@title');
|
||||
anime.images = MBridge.xpath(
|
||||
res, '//*[@class="list"]/article/div/div/figure/a/img/@src');
|
||||
final nextPage = MBridge.xpath(res, '//a[@class="next page-link"]/@href');
|
||||
if (nextPage.isEmpty) {
|
||||
anime.hasNextPage = false;
|
||||
} else {
|
||||
anime.hasNextPage = true;
|
||||
}
|
||||
return anime;
|
||||
}
|
||||
|
||||
getLatestUpdatesAnime(MManga anime) async {
|
||||
final data = {"url": "${anime.baseUrl}/page/${anime.page}/"};
|
||||
final response = await MBridge.http('GET', json.encode(data));
|
||||
if (response.hasError) {
|
||||
return response;
|
||||
}
|
||||
String res = response.body;
|
||||
anime.urls = MBridge.xpath(res, '//*[@class="episode"]/div/a/@href');
|
||||
final namess = MBridge.xpath(res, '//*[@class="episode"]/div/a/text()');
|
||||
List<String> names = [];
|
||||
for (var name in namess) {
|
||||
names.add(MBridge.regExp(
|
||||
name,
|
||||
r'(?<=\bS\d\s*|)\d{2}\s*(?=\b(Vostfr|vostfr|VF|Vf|vf|\(VF\)|\(vf\)|\(Vf\)|\(Vostfr\)\b))?',
|
||||
'',
|
||||
0,
|
||||
0)
|
||||
.replaceAll(' vostfr', '')
|
||||
.replaceAll(' Vostfr', '')
|
||||
.replaceAll(' VF', '')
|
||||
.replaceAll(' Vf', '')
|
||||
.replaceAll(' vf', '')
|
||||
.replaceAll(' (VF)', '')
|
||||
.replaceAll(' (vf)', '')
|
||||
.replaceAll(' (vf)', '')
|
||||
.replaceAll(' (Vf)', '')
|
||||
.replaceAll(' (Vostfr)', ''));
|
||||
}
|
||||
anime.names = names;
|
||||
anime.images =
|
||||
MBridge.xpath(res, '//*[@class="episode"]/div/figure/a/img/@src');
|
||||
final nextPage = MBridge.xpath(res, '//a[@class="next page-link"]/@href');
|
||||
if (nextPage.isEmpty) {
|
||||
anime.hasNextPage = false;
|
||||
} else {
|
||||
anime.hasNextPage = true;
|
||||
}
|
||||
return anime;
|
||||
}
|
||||
|
||||
getAnimeDetail(MManga anime) async {
|
||||
final statusList = [
|
||||
{
|
||||
"En cours": 0,
|
||||
"Terminé": 1,
|
||||
}
|
||||
];
|
||||
final url = anime.link;
|
||||
final data = {"url": url};
|
||||
final response = await MBridge.http('GET', json.encode(data));
|
||||
if (response.hasError) {
|
||||
return response;
|
||||
}
|
||||
String res = response.body;
|
||||
|
||||
final originalUrl = MBridge.xpath(res,
|
||||
'//*[@class="breadcrumb"]/li[@class="breadcrumb-item"][2]/a/@href')
|
||||
.first;
|
||||
if (originalUrl.isNotEmpty) {
|
||||
final newData = {"url": originalUrl};
|
||||
final newResponse = await MBridge.http('GET', json.encode(newData));
|
||||
if (newResponse.hasError) {
|
||||
return newResponse;
|
||||
}
|
||||
res = newResponse.body;
|
||||
if (res.isEmpty) {
|
||||
return anime;
|
||||
}
|
||||
}
|
||||
anime.description =
|
||||
MBridge.xpath(res, '//*[@class="episode fz-sm synop"]/p/text()')
|
||||
.first
|
||||
.replaceAll("Synopsis:", "");
|
||||
final status = MBridge.xpath(res,
|
||||
'//*[@class="list-unstyled"]/li[contains(text(),"Statut")]/text()')
|
||||
.first
|
||||
.replaceAll("Statut: ", "");
|
||||
anime.status = MBridge.parseStatus(status, statusList);
|
||||
anime.genre = MBridge.xpath(res,
|
||||
'//*[@class="list-unstyled"]/li[contains(text(),"Genre")]/ul/li/a/text()');
|
||||
|
||||
anime.urls =
|
||||
MBridge.xpath(res, '//*[@class="list-episodes list-group"]/a/@href');
|
||||
final dates = MBridge.xpath(
|
||||
res, '//*[@class="list-episodes list-group"]/a/span/text()');
|
||||
final names =
|
||||
MBridge.xpath(res, '//*[@class="list-episodes list-group"]/a/text()');
|
||||
|
||||
List<String> episodes = [];
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
final date = dates[i];
|
||||
final name = names[i];
|
||||
episodes.add(
|
||||
"Episode ${MBridge.regExp(name.replaceAll(date, ""), r".* (\d*) [VvfF]{1,1}", '', 1, 1)}");
|
||||
}
|
||||
anime.names = episodes;
|
||||
anime.chaptersDateUploads =
|
||||
MBridge.listParseDateTime(dates, "dd MMMM yyyy", "fr");
|
||||
return anime;
|
||||
}
|
||||
|
||||
searchAnime(MManga anime) async {
|
||||
final data = {
|
||||
"url":
|
||||
"${anime.baseUrl}/toute-la-liste-affiches/page/${anime.page}/?q=${anime.query}"
|
||||
};
|
||||
final response = await MBridge.http('GET', json.encode(data));
|
||||
if (response.hasError) {
|
||||
return response;
|
||||
}
|
||||
String res = response.body;
|
||||
|
||||
anime.urls =
|
||||
MBridge.xpath(res, '//*[@class="list"]/article/div/div/figure/a/@href');
|
||||
|
||||
anime.names = MBridge.xpath(
|
||||
res, '//*[@class="list"]/article/div/div/figure/a/img/@title');
|
||||
anime.images = MBridge.xpath(
|
||||
res, '//*[@class="list"]/article/div/div/figure/a/img/@src');
|
||||
final nextPage = MBridge.xpath(res, '//a[@class="next page-link"]/@href');
|
||||
if (nextPage.isEmpty) {
|
||||
anime.hasNextPage = false;
|
||||
} else {
|
||||
anime.hasNextPage = true;
|
||||
}
|
||||
return anime;
|
||||
}
|
||||
|
||||
getVideoList(MManga anime) async {
|
||||
final datas = {"url": anime.link};
|
||||
|
||||
final res = await MBridge.http('GET', json.encode(datas));
|
||||
|
||||
if (res.hasError) {
|
||||
return res;
|
||||
}
|
||||
final servers =
|
||||
MBridge.xpath(res.body, '//*[@id="nav-tabContent"]/div/iframe/@src');
|
||||
List<MVideo> videos = [];
|
||||
for (var url in servers) {
|
||||
final datasServer = {
|
||||
"url": fixUrl(url),
|
||||
"headers": {"X-Requested-With": "XMLHttpRequest"}
|
||||
};
|
||||
|
||||
final responseResServer =
|
||||
await MBridge.http('GET', json.encode(datasServer));
|
||||
String resServer = responseResServer.body;
|
||||
final serverUrl =
|
||||
fixUrl(MBridge.regExp(resServer, r"data-url='([^']+)'", '', 1, 1));
|
||||
List<MVideo> a = [];
|
||||
if (serverUrl.contains("https://streamwish")) {
|
||||
a = await MBridge.streamWishExtractor(serverUrl, "StreamWish");
|
||||
} else if (serverUrl.contains("sibnet")) {
|
||||
a = await MBridge.sibnetExtractor(serverUrl);
|
||||
} else if (serverUrl.contains("https://doo")) {
|
||||
a = await MBridge.doodExtractor(serverUrl);
|
||||
} else if (serverUrl.contains("https://voe.sx")) {
|
||||
a = await MBridge.voeExtractor(serverUrl, null);
|
||||
} else if (serverUrl.contains("https://ok.ru")) {
|
||||
a = await MBridge.okruExtractor(serverUrl);
|
||||
}
|
||||
for (var vi in a) {
|
||||
videos.add(vi);
|
||||
}
|
||||
}
|
||||
|
||||
return videos;
|
||||
}
|
||||
|
||||
String fixUrl(String url) {
|
||||
return MBridge.regExp(url, r"^(?:(?:https?:)?//|www\.)", 'https://', 0, 0);
|
||||
}
|
||||
207
anime/src/fr/otakufr/otakufr-v0.0.35.dart
Normal file
207
anime/src/fr/otakufr/otakufr-v0.0.35.dart
Normal file
@@ -0,0 +1,207 @@
|
||||
import 'package:mangayomi/bridge_lib.dart';
|
||||
import 'dart:convert';
|
||||
|
||||
class OtakuFr extends MSourceProvider {
|
||||
OtakuFr();
|
||||
|
||||
@override
|
||||
Future<MPages> getPopular(MSource sourceInfo, int page) async {
|
||||
final data = {
|
||||
"url": "${sourceInfo.baseUrl}/toute-la-liste-affiches/page/$page/?q=."
|
||||
};
|
||||
final res = await MBridge.http('GET', json.encode(data));
|
||||
|
||||
List<MManga> animeList = [];
|
||||
final urls =
|
||||
MBridge.xpath(res, '//*[@class="list"]/article/div/div/figure/a/@href');
|
||||
final names = MBridge.xpath(
|
||||
res, '//*[@class="list"]/article/div/div/figure/a/img/@title');
|
||||
final images = MBridge.xpath(
|
||||
res, '//*[@class="list"]/article/div/div/figure/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);
|
||||
}
|
||||
final nextPage = MBridge.xpath(res, '//a[@class="next page-link"]/@href');
|
||||
return MPages(animeList, nextPage.isNotEmpty);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MPages> getLatestUpdates(MSource sourceInfo, int page) async {
|
||||
final data = {"url": "${sourceInfo.baseUrl}/page/$page/"};
|
||||
final res = await MBridge.http('GET', json.encode(data));
|
||||
|
||||
List<MManga> animeList = [];
|
||||
final urls = MBridge.xpath(res, '//*[@class="episode"]/div/a/@href');
|
||||
final namess = MBridge.xpath(res, '//*[@class="episode"]/div/a/text()');
|
||||
List<String> names = [];
|
||||
for (var name in namess) {
|
||||
names.add(MBridge.regExp(
|
||||
name,
|
||||
r'(?<=\bS\d\s*|)\d{2}\s*(?=\b(Vostfr|vostfr|VF|Vf|vf|\(VF\)|\(vf\)|\(Vf\)|\(Vostfr\)\b))?',
|
||||
'',
|
||||
0,
|
||||
0)
|
||||
.replaceAll(' vostfr', '')
|
||||
.replaceAll(' Vostfr', '')
|
||||
.replaceAll(' VF', '')
|
||||
.replaceAll(' Vf', '')
|
||||
.replaceAll(' vf', '')
|
||||
.replaceAll(' (VF)', '')
|
||||
.replaceAll(' (vf)', '')
|
||||
.replaceAll(' (vf)', '')
|
||||
.replaceAll(' (Vf)', '')
|
||||
.replaceAll(' (Vostfr)', ''));
|
||||
}
|
||||
final images =
|
||||
MBridge.xpath(res, '//*[@class="episode"]/div/figure/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);
|
||||
}
|
||||
final nextPage = MBridge.xpath(res, '//a[@class="next page-link"]/@href');
|
||||
return MPages(animeList, nextPage.isNotEmpty);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MPages> search(MSource sourceInfo, String query, int page) async {
|
||||
final data = {
|
||||
"url":
|
||||
"${sourceInfo.baseUrl}/toute-la-liste-affiches/page/$page/?q=$query"
|
||||
};
|
||||
final res = await MBridge.http('GET', json.encode(data));
|
||||
|
||||
List<MManga> animeList = [];
|
||||
final urls =
|
||||
MBridge.xpath(res, '//*[@class="list"]/article/div/div/figure/a/@href');
|
||||
final names = MBridge.xpath(
|
||||
res, '//*[@class="list"]/article/div/div/figure/a/img/@title');
|
||||
final images = MBridge.xpath(
|
||||
res, '//*[@class="list"]/article/div/div/figure/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);
|
||||
}
|
||||
final nextPage = MBridge.xpath(res, '//a[@class="next page-link"]/@href');
|
||||
return MPages(animeList, nextPage.isNotEmpty);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<MManga> getDetail(MSource sourceInfo, String url) async {
|
||||
final statusList = [
|
||||
{
|
||||
"En cours": 0,
|
||||
"Terminé": 1,
|
||||
}
|
||||
];
|
||||
final data = {"url": url};
|
||||
String res = await MBridge.http('GET', json.encode(data));
|
||||
MManga anime = MManga();
|
||||
final originalUrl = MBridge.xpath(res,
|
||||
'//*[@class="breadcrumb"]/li[@class="breadcrumb-item"][2]/a/@href')
|
||||
.first;
|
||||
if (originalUrl.isNotEmpty) {
|
||||
final newData = {"url": originalUrl};
|
||||
res = await MBridge.http('GET', json.encode(newData));
|
||||
}
|
||||
|
||||
anime.description =
|
||||
MBridge.xpath(res, '//*[@class="episode fz-sm synop"]/p/text()')
|
||||
.first
|
||||
.replaceAll("Synopsis:", "");
|
||||
final status = MBridge.xpath(res,
|
||||
'//*[@class="list-unstyled"]/li[contains(text(),"Statut")]/text()')
|
||||
.first
|
||||
.replaceAll("Statut: ", "");
|
||||
anime.status = MBridge.parseStatus(status, statusList);
|
||||
anime.genre = MBridge.xpath(res,
|
||||
'//*[@class="list-unstyled"]/li[contains(text(),"Genre")]/ul/li/a/text()');
|
||||
|
||||
final epUrls =
|
||||
MBridge.xpath(res, '//*[@class="list-episodes list-group"]/a/@href');
|
||||
final dates = MBridge.xpath(
|
||||
res, '//*[@class="list-episodes list-group"]/a/span/text()');
|
||||
final names =
|
||||
MBridge.xpath(res, '//*[@class="list-episodes list-group"]/a/text()');
|
||||
List<String> episodes = [];
|
||||
|
||||
for (var i = 0; i < names.length; i++) {
|
||||
final date = dates[i];
|
||||
final name = names[i];
|
||||
episodes.add(
|
||||
"Episode ${MBridge.regExp(name.replaceAll(date, ""), r".* (\d*) [VvfF]{1,1}", '', 1, 1)}");
|
||||
}
|
||||
final dateUploads = MBridge.parseDates(dates, "dd MMMM yyyy", "fr");
|
||||
|
||||
List<MChapter>? episodesList = [];
|
||||
for (var i = 0; i < episodes.length; i++) {
|
||||
MChapter episode = MChapter();
|
||||
episode.name = episodes[i];
|
||||
episode.url = epUrls[i];
|
||||
episode.dateUpload = dateUploads[i];
|
||||
episodesList.add(episode);
|
||||
}
|
||||
|
||||
anime.chapters = episodesList;
|
||||
return anime;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<MVideo>> getVideoList(MSource sourceInfo, String url) async {
|
||||
final res = await MBridge.http('GET', json.encode({"url": url}));
|
||||
|
||||
final servers =
|
||||
MBridge.xpath(res, '//*[@id="nav-tabContent"]/div/iframe/@src');
|
||||
List<MVideo> videos = [];
|
||||
for (var url in servers) {
|
||||
final datasServer = {
|
||||
"url": fixUrl(url),
|
||||
"headers": {"X-Requested-With": "XMLHttpRequest"}
|
||||
};
|
||||
|
||||
final resServer = await MBridge.http('GET', json.encode(datasServer));
|
||||
final serverUrl =
|
||||
fixUrl(MBridge.regExp(resServer, r"data-url='([^']+)'", '', 1, 1));
|
||||
List<MVideo> a = [];
|
||||
if (serverUrl.contains("https://streamwish")) {
|
||||
a = await MBridge.streamWishExtractor(serverUrl, "StreamWish");
|
||||
} else if (serverUrl.contains("sibnet")) {
|
||||
a = await MBridge.sibnetExtractor(serverUrl);
|
||||
} else if (serverUrl.contains("https://doo")) {
|
||||
a = await MBridge.doodExtractor(serverUrl);
|
||||
} else if (serverUrl.contains("https://voe.sx")) {
|
||||
a = await MBridge.voeExtractor(serverUrl, null);
|
||||
} else if (serverUrl.contains("https://ok.ru")) {
|
||||
a = await MBridge.okruExtractor(serverUrl);
|
||||
}
|
||||
videos.addAll(a);
|
||||
}
|
||||
|
||||
return videos;
|
||||
}
|
||||
|
||||
String fixUrl(String url) {
|
||||
return MBridge.regExp(url, r"^(?:(?:https?:)?//|www\.)", 'https://', 0, 0);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<String>> getPageList(MSource sourceInfo, String url) async {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
OtakuFr main() {
|
||||
return OtakuFr();
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import '../../../../model/source.dart';
|
||||
import '../../../../utils/utils.dart';
|
||||
|
||||
Source get otakufr => _otakufr;
|
||||
const otakufrVersion = "0.0.3";
|
||||
const otakufrVersion = "0.0.35";
|
||||
const otakufrCodeUrl =
|
||||
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/src/fr/otakufr/otakufr-v$otakufrVersion.dart";
|
||||
Source _otakufr = Source(
|
||||
|
||||
Reference in New Issue
Block a user