This commit is contained in:
kodjomoustapha
2023-10-24 21:28:23 +01:00
parent 9739a8720e
commit 6eac32b58c
39 changed files with 457 additions and 953 deletions

View File

@@ -5,20 +5,16 @@ import '../model/source.dart';
import 'src/ar/okanime/source.dart';
import 'src/en/aniwatch/sources.dart';
import 'src/en/gogoanime/source.dart';
// import 'src/en/wcostream/source.dart';
import 'src/en/kisskh/source.dart';
import 'src/fr/animesultra/source.dart';
import 'src/fr/franime/source.dart';
import 'src/fr/otakufr/source.dart';
import 'src/fr/universanime/source.dart';
void main() {
List<Source> _sourcesList = [
gogoanimeSource,
franimeSource,
universanimeSource,
otakufr,
// wcostreamSource,
animesultraSource,
...aniwatchSourcesList,
kisskhSource,

View File

@@ -1,7 +1,7 @@
import 'dart:convert';
import 'package:bridge_lib/bridge_lib.dart';
getPopularAnime(MangaModel anime) async {
getPopularAnime(MManga anime) async {
final data = {"url": "https://www.okanime.xyz"};
final res = await MBridge.http('GET', json.encode(data));
if (res.isEmpty) {
@@ -19,7 +19,7 @@ getPopularAnime(MangaModel anime) async {
return anime;
}
getAnimeDetail(MangaModel anime) async {
getAnimeDetail(MManga anime) async {
final statusList = [
{"يعرض الان": 0, "مكتمل": 1}
];
@@ -52,7 +52,7 @@ getAnimeDetail(MangaModel anime) async {
return anime;
}
getLatestUpdatesAnime(MangaModel anime) async {
getLatestUpdatesAnime(MManga anime) async {
final data = {
"url": "https://www.okanime.xyz/espisode-list?page=${anime.page}"
};
@@ -78,7 +78,7 @@ getLatestUpdatesAnime(MangaModel anime) async {
return anime;
}
searchAnime(MangaModel anime) async {
searchAnime(MManga anime) async {
String url = "https://www.okanime.xyz/search/?s=${anime.query}";
if (anime.page > 1) {
url += "&page=${anime.page}";
@@ -106,7 +106,7 @@ searchAnime(MangaModel anime) async {
return anime;
}
getVideoList(MangaModel anime) async {
getVideoList(MManga anime) async {
final datas = {"url": anime.link};
final res = await MBridge.http('GET', json.encode(datas));
@@ -116,11 +116,11 @@ getVideoList(MangaModel anime) async {
final urls = MBridge.xpath(res, '//*[@id="streamlinks"]/a/@data-src');
final qualities = MBridge.xpath(res, '//*[@id="streamlinks"]/a/span/text()');
List<VideoModel> videos = [];
List<MVideo> videos = [];
for (var i = 0; i < urls.length; i++) {
final url = urls[i];
final quality = getQuality(qualities[i]);
List<VideoModel> a = [];
List<MVideo> a = [];
if (url.contains("https://doo")) {
a = await MBridge.doodExtractor(url, "DoodStream - $quality");

View File

@@ -2,7 +2,7 @@ import '../../../../model/source.dart';
import '../../../../utils/utils.dart';
Source get okanimeSource => _okanimeSource;
const okanimeVersion = "0.0.1";
const okanimeVersion = "0.0.2";
const okanimeSourceCodeUrl =
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/src/ar/okanime/okanime-v$okanimeVersion.dart";
Source _okanimeSource = Source(
@@ -13,5 +13,4 @@ Source _okanimeSource = Source(
iconUrl: getIconUrl("okanime", "ar"),
sourceCodeUrl: okanimeSourceCodeUrl,
version: okanimeVersion,
appMinVerReq: "0.0.48",
isManga: false);

View File

@@ -1,26 +1,21 @@
import 'dart:convert';
import 'package:bridge_lib/bridge_lib.dart';
getPopularAnime(MangaModel anime) async {
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.isEmpty) {
return anime;
}
return animeElementM(res, anime);
}
getLatestUpdatesAnime(MangaModel anime) async {
getLatestUpdatesAnime(MManga anime) async {
final data = {"url": "${anime.baseUrl}/top-airing?page=${anime.page}"};
final res = await MBridge.http('GET', json.encode(data));
if (res.isEmpty) {
return anime;
}
return animeElementM(res, anime);
}
getAnimeDetail(MangaModel anime) async {
getAnimeDetail(MManga anime) async {
final statusList = [
{
"Currently Airing": 0,
@@ -107,18 +102,16 @@ getAnimeDetail(MangaModel anime) async {
return anime;
}
searchAnime(MangaModel anime) async {
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.isEmpty) {
return anime;
}
return animeElementM(res, anime);
}
getVideoList(MangaModel anime) async {
getVideoList(MManga anime) async {
final id = MBridge.substringAfterLast(anime.link, '?ep=');
final datas = {
"url":
@@ -152,7 +145,7 @@ getVideoList(MangaModel anime) async {
attributes: "data-type",
typeRegExp: 0);
List<VideoModel> videos = [];
List<MVideo> videos = [];
for (var i = 0; i < names.length; i++) {
final name = names[i];
@@ -168,7 +161,7 @@ getVideoList(MangaModel anime) async {
String url = MBridge.substringBefore(
MBridge.substringAfter(resE, "\"link\":\""), "\"");
print(url);
List<VideoModel> a = [];
List<MVideo> a = [];
if (name.contains("Vidstreaming")) {
a = await MBridge.rapidCloudExtractor(url, "Vidstreaming - $subDub");
videos.addAll(a);
@@ -184,7 +177,7 @@ getVideoList(MangaModel anime) async {
return videos;
}
MangaModel animeElementM(String res, MangaModel anime) async {
MManga animeElementM(String res, MManga anime) async {
if (res.isEmpty) {
return anime;
}

View File

@@ -1,7 +1,7 @@
import '../../../../model/source.dart';
import '../../../../utils/utils.dart';
const aniwatchVersion = "0.0.21";
const aniwatchVersion = "0.0.3";
const aniwatchSourceCodeUrl =
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/src/en/aniwatch/aniwatch-v$aniwatchVersion.dart";
@@ -15,7 +15,6 @@ List<Source> _aniwatchSourcesList = [
iconUrl: getIconUrl("aniwatch", "en"),
version: aniwatchVersion,
isManga: false,
appMinVerReq: "0.0.45",
sourceCodeUrl: aniwatchSourceCodeUrl),
Source(
name: "Kaido.to",
@@ -25,6 +24,5 @@ List<Source> _aniwatchSourcesList = [
iconUrl: getIconUrl("kaido", "en"),
version: aniwatchVersion,
isManga: false,
appMinVerReq: "0.0.45",
sourceCodeUrl: aniwatchSourceCodeUrl),
];

View File

@@ -1,22 +1,19 @@
import 'dart:convert';
import 'package:bridge_lib/bridge_lib.dart';
getPopularAnime(MangaModel anime) async {
getPopularAnime(MManga anime) async {
final data = {"url": "${anime.baseUrl}/popular.html?page=${anime.page}"};
final res = await MBridge.http('GET', json.encode(data));
if (res.isEmpty) {
return anime;
}
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(MangaModel anime) async {
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};
@@ -26,7 +23,6 @@ getLatestUpdatesAnime(MangaModel anime) async {
}
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 = [];
@@ -41,7 +37,7 @@ getLatestUpdatesAnime(MangaModel anime) async {
return anime;
}
getAnimeDetail(MangaModel anime) async {
getAnimeDetail(MManga anime) async {
final statusList = [
{
"Ongoing": 0,
@@ -59,12 +55,10 @@ getAnimeDetail(MangaModel anime) async {
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()')
@@ -91,7 +85,7 @@ getAnimeDetail(MangaModel anime) async {
return anime;
}
getVideoList(MangaModel anime) async {
getVideoList(MManga anime) async {
final datas = {"url": "${anime.baseUrl}${anime.link}"};
final res = await MBridge.http('GET', json.encode(datas));
@@ -104,13 +98,12 @@ getVideoList(MangaModel anime) async {
MBridge.xpath(res, '//*[@class="anime_muti_link"]/ul/li/a/@data-video');
final classNames =
MBridge.xpath(res, '//*[@class="anime_muti_link"]/ul/li/@class');
print(serverUrls);
List<VideoModel> videos = [];
List<MVideo> videos = [];
for (var i = 0; i < classNames.length; i++) {
final name = classNames[i];
final url = serverUrls[i];
print(url);
List<VideoModel> a = [];
List<MVideo> a = [];
if (name.contains("anime")) {
a = await MBridge.gogoCdnExtractor(url);
} else if (name.contains("vidcdn")) {
@@ -131,7 +124,7 @@ getVideoList(MangaModel anime) async {
return videos;
}
searchAnime(MangaModel anime) async {
searchAnime(MManga anime) async {
final url =
"${anime.baseUrl}/search.html?keyword=${anime.query}&page=${anime.page}";
final data = {"url": url};
@@ -140,9 +133,7 @@ searchAnime(MangaModel anime) async {
return anime;
}
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;
}

View File

@@ -2,7 +2,7 @@ import '../../../../model/source.dart';
import '../../../../utils/utils.dart';
Source get gogoanimeSource => _gogoanimeSource;
const gogoanimeVersion = "0.0.2";
const gogoanimeVersion = "0.0.3";
const gogoanimeSourceCodeUrl =
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/src/en/gogoanime/gogoanime-v$gogoanimeVersion.dart";
Source _gogoanimeSource = Source(

View File

@@ -1,7 +1,7 @@
import 'dart:convert';
import 'package:bridge_lib/bridge_lib.dart';
getPopularAnime(MangaModel anime) async {
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"
@@ -24,7 +24,7 @@ getPopularAnime(MangaModel anime) async {
return anime;
}
getLatestUpdatesAnime(MangaModel anime) async {
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"
@@ -48,7 +48,7 @@ getLatestUpdatesAnime(MangaModel anime) async {
return anime;
}
getAnimeDetail(MangaModel anime) async {
getAnimeDetail(MManga anime) async {
final statusList = [
{
"Ongoing": 0,
@@ -72,10 +72,10 @@ getAnimeDetail(MangaModel anime) async {
final episodesCount = jsonRes["episodesCount"] as int;
List<String> episodesNames = [];
List<String> episodesUrls = [];
bool containsAnime = type.contains("Anime") as bool;
bool containsTVSeries = type.contains("TVSeries") as bool;
bool containsHollywood = type.contains("Hollywood") as bool;
bool containsMovie = type.contains("Movie") as bool;
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"];
@@ -96,7 +96,7 @@ getAnimeDetail(MangaModel anime) async {
return anime;
}
getVideoList(MangaModel anime) async {
getVideoList(MManga anime) async {
final datas = {"url": anime.link};
final res = await MBridge.http('GET', json.encode(datas));
@@ -111,13 +111,13 @@ getVideoList(MangaModel anime) async {
'GET', json.encode({"url": "${anime.baseUrl}/api/Sub/$id"}));
var jsonSubRes = json.decode(subRes);
List<TrackModel> subtitles = [];
List<MTrack> subtitles = [];
for (var sub in jsonSubRes) {
try {
final subUrl = sub["src"];
final label = sub["label"];
TrackModel subtitle = TrackModel();
MTrack subtitle = MTrack();
subtitle
..label = label
..file = subUrl;
@@ -126,7 +126,7 @@ getVideoList(MangaModel anime) async {
}
final videoUrl = jsonRes["Video"];
VideoModel video = VideoModel();
MVideo video = MVideo();
video
..url = videoUrl
..originalUrl = videoUrl
@@ -139,7 +139,7 @@ getVideoList(MangaModel anime) async {
return [video];
}
searchAnime(MangaModel anime) async {
searchAnime(MManga anime) async {
final data = {
"url": "${anime.baseUrl}/api/DramaList/Search?q=${anime.query}&type=0"
};
@@ -148,11 +148,8 @@ searchAnime(MangaModel anime) async {
return anime;
}
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();

View File

@@ -2,7 +2,7 @@ import '../../../../model/source.dart';
import '../../../../utils/utils.dart';
Source get kisskhSource => _kisskhSource;
const kisskhVersion = "0.0.1";
const kisskhVersion = "0.0.2";
const kisskhSourceCodeUrl =
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/src/en/kisskh/kisskh-v$kisskhVersion.dart";
Source _kisskhSource = Source(
@@ -13,5 +13,4 @@ Source _kisskhSource = Source(
iconUrl: getIconUrl("kisskh", "en"),
sourceCodeUrl: kisskhSourceCodeUrl,
version: kisskhVersion,
appMinVerReq: "0.0.48",
isManga: false);

View File

@@ -1,17 +0,0 @@
import '../../../../model/source.dart';
import '../../../../utils/utils.dart';
Source get wcostreamSource => _wcostreamSource;
const wcostreamVersion = "0.0.11";
const wcostreamSourceCodeUrl =
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/src/en/wcostream/wcostream-v$wcostreamVersion.dart";
Source _wcostreamSource = Source(
name: "WCOStream",
baseUrl: "https://www.wcostream.org",
lang: "en",
typeSource: "single",
iconUrl: getIconUrl("wcostream", "en"),
sourceCodeUrl: wcostreamSourceCodeUrl,
version: wcostreamVersion,
isManga: false,
isFullData: false);

View File

@@ -1,223 +0,0 @@
import 'dart:convert';
import 'package:bridge_lib/bridge_lib.dart';
getPopularAnime(MangaModel anime) async {
return await getLatestUpdatesAnime(anime);
}
Future<MangaModel> getLatestUpdatesAnime(MangaModel anime) async {
final data = {
"url": anime.baseUrl,
"headers": {"referer": "https://wcostream.org/"},
"sourceId": anime.sourceId
};
final res = await MBridge.http(json.encode(data), 0);
if (res.isEmpty) {
return anime;
}
final urlss = MBridge.xpath(
res,
'//*[@id="content"]/div/div[contains(text(),"Recent Releases")]/div/ul/li/div[@class="img"]/a/img/@alt',
'._')
.split('._');
List<String> urls = [];
for (var url in MBridge.listParse(urlss, 0)) {
urls.add(
"/anime/${MBridge.regExp(url, "[^A-Za-z0-9 ]", "", 0, 0).replaceAll(" ", "-").toLowerCase()}/");
}
anime.urls = urls;
final imagess = MBridge.xpath(
res,
'//*[@id="content"]/div/div[contains(text(),"Recent Releases")]/div/ul/li/div[@class="img"]/a/img/@src',
'._')
.split('._');
List<String> images = [];
for (var image in MBridge.listParse(imagess, 0)) {
images.add(fixUrl(image));
}
anime.images = images;
final namess = MBridge.xpath(
res,
'//*[@id="content"]/div/div[contains(text(),"Recent Releases")]/div/ul/li/div[@class="recent-release-episodes"]/a/text()',
'._')
.split('._');
List<String> names = [];
for (var name in MBridge.listParse(namess, 0)) {
names.add(MBridge.subString(name, ' Episode', 0));
}
anime.names = names;
anime.hasNextPage = false;
return anime;
}
String fixUrl(String url) {
return MBridge.regExp(url, r"^(?:(?:https?:)?//|www\.)", 'https://', 0, 0);
}
getAnimeDetail(MangaModel anime) async {
final url = '${anime.baseUrl}${anime.link}';
print(url);
final data = {
"url": url,
"headers": {"referer": "https://wcostream.org/"}
};
final res = await MBridge.http(json.encode(data), 0);
if (res.isEmpty) {
return anime;
}
anime.status = 5;
anime.description = MBridge.xpath(
res,
'//*[@class="katcont"]/div/p[contains(text(),"Plot Summary:")]/text()',
'')
.replaceAll('Plot Summary: ', '');
anime.genre = MBridge.xpath(
res, '//*[@id="cat-genre"]/div[@class="wcobtn"]/a/text()', '._')
.split('._');
anime.urls = MBridge.xpath(
res,
'//*[@id="catlist-listview" and @class^="cat-listview"]/ul/li/a/@href',
'._')
.split('._');
anime.names = MBridge.xpath(
res,
'//*[@id="catlist-listview" and @class^="cat-listview"]/ul/li/a/text()',
'._')
.split('._');
anime.chaptersDateUploads = [];
return anime;
}
searchAnime(MangaModel anime) async {
final data = {
"url": "${anime.baseUrl}/search",
"fields": {'catara': anime.query.replaceAll(" ", "+"), 'konuara': 'series'},
"headers": {"Referer": "${anime.baseUrl}/"},
"sourceId": anime.sourceId
};
final res = await MBridge.httpMultiparFormData(json.encode(data), 1);
if (res.isEmpty) {
return anime;
}
anime.urls = MBridge.xpath(
res,
'//*[@id="blog"]/div[@class="cerceve"]/div[@class="iccerceve"]/a/@href',
'._')
.split('._');
anime.names = MBridge.xpath(
res,
'//*[@id="blog"]/div[@class="cerceve"]/div[@class="iccerceve"]/a/@title',
'._')
.split('._');
anime.images = MBridge.xpath(
res,
'//*[@id="blog"]/div[@class="cerceve"]/div[@class="iccerceve"]/a/img/@src',
'._')
.split('._');
anime.hasNextPage = false;
return anime;
}
getVideoList(MangaModel anime) async {
final datas = {
"url": anime.link,
"headers": null,
"sourceId": anime.sourceId
};
final res = await MBridge.http(json.encode(datas), 0);
if (res.isEmpty) {
return [];
}
final script = MBridge.xpath(
res, '//script[contains(text(), "decodeURIComponent")]/text()', "");
final stringList = MBridge.jsonDecodeToList(
"[${MBridge.subString(MBridge.subString(script, '[', 2), ']', 0)}]", 0);
final shiftNumber = MBridge.intParse(
MBridge.subString(MBridge.subString(script, '- ', 1), ')', 0));
print(shiftNumber - 1);
List<String> iframeStuff = [];
for (var i = 0; i < stringList.length; i++) {
final decoded = MBridge.bAse64(MBridge.listParse(stringList, 0)[i], 0);
final intValue =
MBridge.intParse(MBridge.regExp(decoded, r"""\D""", '', 0, 0));
iframeStuff
.add(MBridge.stringParse("${intValue - shiftNumber}".toString(), 1));
}
final iframeUrl =
MBridge.xpath(MBridge.listParse(iframeStuff, 6)[0], '//iframe/@src', "");
final iframeHeaders = {
'Accept':
'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
'Connection': 'keep-alive',
'Host': MBridge.listParse(iframeUrl.split('/'), 0)[2],
'Referer': '${anime.baseUrl}/',
'Sec-Fetch-Dest': 'iframe',
'Sec-Fetch-Mode': 'navigate',
'Sec-Fetch-Site': 'cross-site',
'Upgrade-Insecure-Requests': '1',
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36 Edg/88.0.705.63',
};
final datasIframe = {"url": iframeUrl, "headers": iframeHeaders};
final resIframe = await MBridge.http(json.encode(datasIframe), 0);
final getVideoLinkScript = MBridge.xpath(
resIframe, '//script[contains(text(), "getJSON")]/text()', "");
final getVideoLinkUrl = MBridge.subString(
MBridge.subString(getVideoLinkScript, "getJSON(\"", 2), "\"", 0);
final getVideoHeaders = {
'Accept': 'application/json, text/javascript, */*; q=0.01',
'Host': MBridge.listParse(iframeUrl.split('/'), 0)[2],
'Referer': iframeUrl,
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36 Edg/88.0.705.63',
'X-Requested-With': 'XMLHttpRequest',
};
final datasVideoLink = {
"url":
'https://${MBridge.listParse(iframeUrl.split('/'), 0)[2]}$getVideoLinkUrl',
"headers": getVideoHeaders
};
final resVideoLink = await MBridge.http(json.encode(datasVideoLink), 0);
final server = MBridge.getMapValue(resVideoLink, "server", 0);
final enc = MBridge.getMapValue(resVideoLink, "enc", 0);
final hd = MBridge.getMapValue(resVideoLink, "hd", 0);
final fhd = MBridge.getMapValue(resVideoLink, "fhd", 0);
final videoUrl = "$server/getvid?evid=$enc";
final videoHeaders = {
'Accept':
'video/webm,video/ogg,video/*;q=0.9,application/ogg;q=0.7,audio/*;q=0.6,*/*;q=0.5',
'Host': MBridge.listParse(videoUrl.split('/'), 0)[2],
'Referer': MBridge.listParse(iframeUrl.split('/'), 0)[2],
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36 Edg/88.0.705.63',
};
List<VideoModel> videos = [];
videos.add(MBridge.toVideo(
videoUrl, "Video 480p", videoUrl, json.encode(videoHeaders)));
if (hd.isEmpty) {
} else {
final hdVideoUrl = "$server/getvid?evid=$hd";
videos.add(MBridge.toVideo(
hdVideoUrl, "Video 720p", hdVideoUrl, json.encode(videoHeaders)));
}
if (fhd.isEmpty) {
} else {
final fhdVideoUrl = "$server/getvid?evid=$fhd";
videos.add(MBridge.toVideo(
fhdVideoUrl, "Video 1080p", fhdVideoUrl, json.encode(videoHeaders)));
}
return videos;
}

View File

@@ -1,7 +1,7 @@
import 'dart:convert';
import 'package:bridge_lib/bridge_lib.dart';
getPopularAnime(MangaModel anime) async {
getPopularAnime(MManga anime) async {
final data = {"url": "${anime.baseUrl}/"};
final res = await MBridge.http('GET', json.encode(data));
if (res.isEmpty) {
@@ -9,17 +9,15 @@ getPopularAnime(MangaModel anime) async {
}
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(MangaModel anime) async {
getLatestUpdatesAnime(MManga anime) async {
final data = {"url": "${anime.baseUrl}/"};
final res = await MBridge.http('GET', json.encode(data));
if (res.isEmpty) {
@@ -28,17 +26,15 @@ getLatestUpdatesAnime(MangaModel anime) async {
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(MangaModel anime) async {
searchAnime(MManga anime) async {
final url =
"${anime.baseUrl}/?story=${anime.query}&do=search&subaction=search";
final data = {"url": url};
@@ -47,14 +43,13 @@ searchAnime(MangaModel anime) async {
return anime;
}
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(MangaModel anime) async {
getAnimeDetail(MManga anime) async {
final statusList = [
{
"En cours": 0,
@@ -67,16 +62,13 @@ getAnimeDetail(MangaModel anime) async {
if (res.isEmpty) {
return anime;
}
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,
@@ -88,7 +80,6 @@ getAnimeDetail(MangaModel anime) async {
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
@@ -97,7 +88,7 @@ getAnimeDetail(MangaModel anime) async {
return anime;
}
getVideoList(MangaModel anime) async {
getVideoList(MManga anime) async {
final resWebview = await MBridge.getHtmlViaWebview(
anime.link, '//*[@class="ps__-list"]/div/@data-server-id');
@@ -112,13 +103,12 @@ getVideoList(MangaModel anime) async {
.first;
serverUrls.add(serversUrls);
}
List<VideoModel> videos = [];
List<MVideo> videos = [];
for (var i = 0; i < serverNames.length; i++) {
final name = serverNames[i];
final url = serverUrls[i];
List<VideoModel> a = [];
List<MVideo> a = [];
if (name.contains("Sendvid")) {
a = await MBridge.sendVidExtractor(
url.replaceAll("https:////", "https://"),

View File

@@ -2,7 +2,7 @@ import '../../../../model/source.dart';
import '../../../../utils/utils.dart';
Source get animesultraSource => _animesultraSource;
const animesultraVersion = "0.0.2";
const animesultraVersion = "0.0.3";
const animesultraSourceCodeUrl =
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/src/fr/animesultra/animesultra-v$animesultraVersion.dart";
Source _animesultraSource = Source(

View File

@@ -10,7 +10,7 @@ Future<String> dataBase(int sourceId) async {
return res;
}
getPopularAnime(MangaModel anime) async {
getPopularAnime(MManga anime) async {
final data = {
"url": "https://api.franime.fr/api/animes/",
"headers": {"Referer": "https://franime.fr/"}
@@ -19,16 +19,16 @@ getPopularAnime(MangaModel anime) async {
if (res.isEmpty) {
return anime;
}
List<MangaModel> animeList = animeResList(res);
List<MManga> animeList = animeResList(res);
return animeList;
}
List<MangaModel> animeResList(String res) {
List<MManga> animeResList(String res) {
final statusList = [
{"EN COURS": 0, "TERMINÉ": 1}
];
List<MangaModel> animeList = [];
List<MManga> animeList = [];
var jsonResList = json.decode(res);
@@ -56,7 +56,7 @@ List<MangaModel> animeResList(String res) {
bool hasVf = vfListName.contains(true);
if (hasVostfr || hasVf) {
for (int i = 0; i < seasons.length; i++) {
MangaModel anime = MangaModel();
MManga anime = MManga();
int ind = i + 1;
anime.genre = genre;
anime.description = description;
@@ -106,7 +106,7 @@ String databaseAnimeByTitleO(String res, String titleO) {
return "";
}
getAnimeDetail(MangaModel anime) async {
getAnimeDetail(MManga anime) async {
String language = "vo".toString();
if (anime.link.contains("lang=")) {
language = MBridge.substringBefore(
@@ -165,7 +165,7 @@ getAnimeDetail(MangaModel anime) async {
return anime;
}
getLatestUpdatesAnime(MangaModel anime) async {
getLatestUpdatesAnime(MManga anime) async {
final res = await dataBase(anime.sourceId);
if (res.isEmpty) {
@@ -173,29 +173,29 @@ getLatestUpdatesAnime(MangaModel anime) async {
}
List list = json.decode(res);
List reversedList = list.reversed.toList();
List<MangaModel> animeList = animeResList(json.encode(reversedList));
List<MManga> animeList = animeResList(json.encode(reversedList));
return animeList;
}
searchAnime(MangaModel anime) async {
searchAnime(MManga anime) async {
final res = await dataBase(anime.sourceId);
if (res.isEmpty) {
return anime;
}
List<MangaModel> animeList = animeSeachFetch(res, anime.query);
List<MManga> animeList = animeSeachFetch(res, anime.query);
return animeList;
}
List<MangaModel> animeSeachFetch(String res, query) {
List<MManga> animeSeachFetch(String res, query) {
final statusList = [
{"EN COURS": 0, "TERMINÉ": 1}
];
List<MangaModel> animeList = [];
List<MManga> animeList = [];
final jsonResList = json.decode(res);
for (var animeJson in jsonResList) {
MangaModel anime = MangaModel();
MManga anime = MManga();
final titleO = MBridge.getMapValue(json.encode(animeJson), "titleO");
final titleAlt =
@@ -250,7 +250,7 @@ List<MangaModel> animeSeachFetch(String res, query) {
bool hasVf = vfListName.contains(true);
if (hasVostfr || hasVf) {
for (int i = 0; i < seasons.length; i++) {
MangaModel anime = MangaModel();
MManga anime = MManga();
int ind = i + 1;
anime.genre = genre;
anime.description = description;
@@ -287,7 +287,7 @@ List<MangaModel> animeSeachFetch(String res, query) {
return animeList;
}
getVideoList(MangaModel anime) async {
getVideoList(MManga anime) async {
String language = "vo".toString();
String videoBaseUrl = "https://api.franime.fr/api/anime".toString();
if (anime.link.contains("lang=")) {
@@ -346,12 +346,12 @@ getVideoList(MangaModel anime) async {
} else if (language == "vf" && hasVf) {
players = vfPlayers;
}
List<VideoModel> videos = [];
List<MVideo> videos = [];
for (var i = 0; i < players.length; i++) {
String apiUrl = "$videoBaseUrl/$language/$i";
String playerName = players[i];
VideoModel video = VideoModel();
MVideo video = MVideo();
final data = {
"url": apiUrl,
@@ -359,7 +359,7 @@ getVideoList(MangaModel anime) async {
"sourceId": anime.sourceId
};
final playerUrl = await MBridge.http('GET', json.encode(data));
List<VideoModel> a = [];
List<MVideo> a = [];
if (playerName.contains("franime_myvi")) {
videos.add(video
..url = playerUrl

View File

@@ -2,7 +2,7 @@ import '../../../../model/source.dart';
import '../../../../utils/utils.dart';
Source get franimeSource => _franimeSource;
const franimeVersion = "0.0.22";
const franimeVersion = "0.0.3";
const franimeSourceCodeUrl =
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/src/fr/franime/franime-v$franimeVersion.dart";
Source _franimeSource = Source(

View File

@@ -1,7 +1,7 @@
import 'dart:convert';
import 'package:bridge_lib/bridge_lib.dart';
getPopularAnime(MangaModel anime) async {
getPopularAnime(MManga anime) async {
final data = {
"url": "${anime.baseUrl}/toute-la-liste-affiches/page/${anime.page}/?q=."
};
@@ -9,10 +9,8 @@ getPopularAnime(MangaModel anime) async {
if (res.isEmpty) {
return anime;
}
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(
@@ -26,13 +24,12 @@ getPopularAnime(MangaModel anime) async {
return anime;
}
getLatestUpdatesAnime(MangaModel anime) async {
getLatestUpdatesAnime(MManga anime) async {
final data = {"url": "${anime.baseUrl}/page/${anime.page}/"};
final res = await MBridge.http('GET', json.encode(data));
if (res.isEmpty) {
return anime;
}
anime.urls = MBridge.xpath(res, '//*[@class="episode"]/div/a/@href');
final namess = MBridge.xpath(res, '//*[@class="episode"]/div/a/text()');
List<String> names = [];
@@ -66,7 +63,7 @@ getLatestUpdatesAnime(MangaModel anime) async {
return anime;
}
getAnimeDetail(MangaModel anime) async {
getAnimeDetail(MManga anime) async {
final statusList = [
{
"En cours": 0,
@@ -122,7 +119,7 @@ getAnimeDetail(MangaModel anime) async {
return anime;
}
searchAnime(MangaModel anime) async {
searchAnime(MManga anime) async {
final data = {
"url":
"${anime.baseUrl}/toute-la-liste-affiches/page/${anime.page}/?q=${anime.query}"
@@ -148,7 +145,7 @@ searchAnime(MangaModel anime) async {
return anime;
}
getVideoList(MangaModel anime) async {
getVideoList(MManga anime) async {
final datas = {"url": anime.link};
final res = await MBridge.http('GET', json.encode(datas));
@@ -158,7 +155,7 @@ getVideoList(MangaModel anime) async {
}
final servers =
MBridge.xpath(res, '//*[@id="nav-tabContent"]/div/iframe/@src');
List<VideoModel> videos = [];
List<MVideo> videos = [];
for (var url in servers) {
final datasServer = {
"url": fixUrl(url),
@@ -168,7 +165,7 @@ getVideoList(MangaModel anime) async {
final resServer = await MBridge.http('GET', json.encode(datasServer));
final serverUrl =
fixUrl(MBridge.regExp(resServer, r"data-url='([^']+)'", '', 1, 1));
List<VideoModel> a = [];
List<MVideo> a = [];
if (serverUrl.contains("https://streamwish")) {
a = await MBridge.streamWishExtractor(serverUrl, "StreamWish");
} else if (serverUrl.contains("sibnet")) {

View File

@@ -2,7 +2,7 @@ import '../../../../model/source.dart';
import '../../../../utils/utils.dart';
Source get otakufr => _otakufr;
const otakufrVersion = "0.0.2";
const otakufrVersion = "0.0.3";
const otakufrCodeUrl =
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/src/fr/otakufr/otakufr-v$otakufrVersion.dart";
Source _otakufr = Source(

View File

@@ -1,17 +0,0 @@
import '../../../../model/source.dart';
import '../../../../utils/utils.dart';
Source get universanimeSource => _universanimeSource;
const universanimeVersion = "0.0.2";
const universanimeSourceCodeUrl =
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/src/fr/universanime/universanime-v$universanimeVersion.dart";
Source _universanimeSource = Source(
name: "UniversAnime",
baseUrl: "https://www.universanime.club",
lang: "fr",
typeSource: "single",
iconUrl: getIconUrl("universanime", "fr"),
sourceCodeUrl: universanimeSourceCodeUrl,
version: universanimeVersion,
isManga: false,
isFullData: true);

View File

@@ -1,125 +0,0 @@
import 'dart:convert';
import 'package:bridge_lib/bridge_lib.dart';
getVideoList(MangaModel anime) async {
final datas = {"url": anime.link};
final res = await MBridge.http('GET', json.encode(datas));
if (res.isEmpty) {
return [];
}
final serverUrls =
MBridge.xpath(res, '//*[@class="entry-content"]/div/div/iframe/@src');
List<VideoModel> videos = [];
for (var i = 0; i < serverUrls.length; i++) {
final url = serverUrls[i];
print(url);
List<VideoModel> a = [];
if (url.startsWith("https://filemoon.")) {
a = await MBridge.filemoonExtractor(url, "");
} else if (url.startsWith("https://doodstream.")) {
a = await MBridge.doodExtractor(url);
} else if (url.startsWith("https://streamtape.")) {
a = await MBridge.streamTapeExtractor(url);
} else if (url.contains("streamsb")) {}
for (var vi in a) {
videos.add(vi);
}
}
return videos;
}
Future<MangaModel> getLatestUpdatesAnime(MangaModel anime) async {
final data = {"url": "${anime.baseUrl}/page/${anime.page}/"};
final res = await MBridge.http('GET', json.encode(data));
if (res.isEmpty) {
return anime;
}
anime.urls = MBridge.xpath(
res, '//*[@class="recent-posts"]/li/div[@class="post-thumb"]/a/@href');
anime.names = MBridge.xpath(
res, '//*[@class="recent-posts"]/li/div[@class="post-thumb"]/a/@title');
anime.images = [];
return anime;
}
getAnimeDetail(MangaModel anime) async {
final url = anime.link;
final data = {"url": url};
final res = await MBridge.http('GET', json.encode(data));
if (res.isEmpty) {
return anime;
}
anime.description = MBridge.xpath(res,
'//*[@class="entry-content"]/p[contains(text(),"Synopsis")]/text()')
.first;
anime.status = 5;
final urls = MBridge.xpath(res,
'//*[@class="entry-content"]/ul[@class="lcp_catlist" and contains(@id,"lcp_instance_")]/li/a/@href');
final names = MBridge.xpath(res,
'//*[@class="entry-content"]/ul[@class="lcp_catlist" and contains(@id,"lcp_instance_")]/li/a/text()');
if (urls.isEmpty && names.isEmpty) {
anime.urls = [anime.link];
anime.names = ["Film"];
} else {
anime.urls = urls;
anime.names = names;
}
anime.chaptersDateUploads = [];
return anime;
}
getPopularAnime(MangaModel anime) async {
return await getLatestUpdatesAnime(anime);
}
searchAnime(MangaModel anime) async {
final data = {"url": "${anime.baseUrl}/liste-des-animes-2/"};
final res = await MBridge.http('GET', json.encode(data));
if (res.isEmpty) {
return anime;
}
final dataMovies = {"url": "${anime.baseUrl}/films-mangas/"};
final resMovies = await MBridge.http('GET', json.encode(dataMovies));
List<String> urlsS = [];
List<String> namesS = [];
final urls = MBridge.xpath(res,
'//*[@class="lcp_catlist" and contains(@id,"lcp_instance_")]/li/a/@href');
final names = MBridge.xpath(res,
'//*[@class="lcp_catlist" and contains(@id,"lcp_instance_")]/li/a/text()');
final urlsMovies = MBridge.xpath(resMovies,
'//*[@class="recent-posts"]/li/div[@class="post-thumb"]/a/@href');
final namesMovies = MBridge.xpath(resMovies,
'//*[@class="recent-posts"]/li/div[@class="post-thumb"]/a/@title');
for (var i = 0; i < names.length; i++) {
final name = names[i];
if (name.toLowerCase().contains(anime.query)) {
final url = urls[i];
urlsS.add(url);
namesS.add(name);
}
}
for (var i = 0; i < namesMovies.length; i++) {
final name = namesMovies[i];
if (name.toLowerCase().contains(anime.query)) {
final url = urlsMovies[i];
urlsS.add(url);
namesS.add(name);
}
}
anime.urls = urlsS;
anime.names = namesS;
anime.images = [];
return anime;
}

File diff suppressed because one or more lines are too long

View File

@@ -1,7 +1,7 @@
import 'dart:convert';
import 'package:bridge_lib/bridge_lib.dart';
searchManga(MangaModel manga) async {
searchManga(MManga manga) async {
final headers = getHeader(manga.baseUrl);
String res = "".toString();
@@ -14,32 +14,20 @@ searchManga(MangaModel manga) async {
return manga;
}
} else {
final newEndpointUrl = "${manga.apiUrl}/query";
final newEndpointBody = {
"query_string": manga.query,
"series_status": "All",
"page": manga.page,
"order": "desc",
"order_by": "total_views",
"perPage": "12",
"tags_ids": "[]",
"series_type": "Comic"
};
final newEndpointData = {
"url": newEndpointUrl,
"headers": headers,
"newEndpointBody": newEndpointBody
};
final newEndpointUrl =
"${manga.apiUrl}/query/?page=${manga.page}&query_string=${manga.query}&series_status=All&order=desc&orderBy=total_views&perPage=12&tags_ids=[]&series_type=Comic";
final newEndpointData = {"url": newEndpointUrl, "headers": headers};
res = await MBridge.http('GET', json.encode(newEndpointData));
if (res.isEmpty) {
return manga;
}
}
return mangaModelRes(res, manga);
return MMangaRes(res, manga);
}
getPopularManga(MangaModel manga) async {
getPopularManga(MManga manga) async {
final headers = getHeader(manga.baseUrl);
String res = "".toString();
if (!useNewQueryEndpoint(manga.source)) {
@@ -62,33 +50,23 @@ getPopularManga(MangaModel manga) async {
res = await MBridge.http('POST', json.encode(data));
} else {
final newEndpointUrl = "${manga.apiUrl}/query";
final newEndpointBody = {
"query_string": "",
"series_status": "All",
"page": manga.page,
"order": "desc",
"order_by": "total_views",
"perPage": "12",
"tags_ids": "[]",
"series_type": "Comic"
};
final newEndpointUrl =
"${manga.apiUrl}/query/?page=${manga.page}&query_string=&series_status=All&order=desc&orderBy=total_views&perPage=12&tags_ids=[]&series_type=Comic";
final newEndpointData = {
"url": newEndpointUrl,
"headers": headers,
"sourceId": manga.sourceId,
"body": newEndpointBody
"sourceId": manga.sourceId
};
print("sssssssssssssssssssss");
res = await MBridge.http('GET', json.encode(newEndpointData));
}
if (res.isEmpty) {
return manga;
}
return mangaModelRes(res, manga);
return MMangaRes(res, manga);
}
getLatestUpdatesManga(MangaModel manga) async {
getLatestUpdatesManga(MManga manga) async {
final headers = getHeader(manga.baseUrl);
String res = "".toString();
if (!useNewQueryEndpoint(manga.source)) {
@@ -108,23 +86,10 @@ getLatestUpdatesManga(MangaModel manga) async {
};
res = await MBridge.http('POST', json.encode(data));
} else {
final newEndpointUrl = "${manga.apiUrl}/query";
final newEndpointBody = {
"query_string": "",
"series_status": "All",
"page": manga.page,
"order": "desc",
"order_by": "latest",
"perPage": "12",
"tags_ids": "[]",
"series_type": "Comic"
};
final newEndpointData = {
"url": newEndpointUrl,
"headers": headers,
"sourceId": manga.sourceId,
"body": newEndpointBody
};
final newEndpointUrl =
"${manga.apiUrl}/query/?page=${manga.page}&query_string=&series_status=All&order=desc&orderBy=latest&perPage=12&tags_ids=[]&series_type=Comic";
final newEndpointData = {"url": newEndpointUrl, "headers": headers};
res = await MBridge.http('GET', json.encode(newEndpointData));
print(res);
}
@@ -132,10 +97,10 @@ getLatestUpdatesManga(MangaModel manga) async {
if (res.isEmpty) {
return manga;
}
return mangaModelRes(res, manga);
return MMangaRes(res, manga);
}
getMangaDetail(MangaModel manga) async {
getMangaDetail(MManga manga) async {
String currentSlug = MBridge.substringAfterLast(manga.link, "/");
final headers = getHeader(manga.baseUrl);
final url = "${manga.apiUrl}/series/$currentSlug";
@@ -144,7 +109,7 @@ getMangaDetail(MangaModel manga) async {
if (res.isEmpty) {
return manga;
}
print(res);
print("${manga.apiUrl}/series/$currentSlug");
manga.author = MBridge.getMapValue(res, "author");
manga.description = MBridge.getMapValue(res, "description");
@@ -193,7 +158,7 @@ getMangaDetail(MangaModel manga) async {
return manga;
}
getChapterUrl(MangaModel manga) async {
getChapterPages(MManga manga) async {
String res = "".toString();
final headers = getHeader(manga.baseUrl);
if (!useslugStrategy(manga.source)) {
@@ -255,7 +220,7 @@ bool useslugStrategy(String sourceName) {
return sources.contains(sourceName);
}
MangaModel mangaModelRes(String res, MangaModel manga) {
MManga MMangaRes(String res, MManga manga) {
List<String> names = [];
List<String> urls = [];
List<String> images = [];
@@ -269,7 +234,7 @@ MangaModel mangaModelRes(String res, MangaModel manga) {
images.add("${manga.apiUrl}/cover/$thumbnail");
}
names.add(a["title"]);
final seriesSlug = MBridge.regExp(a["series_slug"], "-\\d+", "", 0, 0);
final seriesSlug = a["series_slug"];
urls.add("/series/$seriesSlug");
}
} else {
@@ -281,9 +246,10 @@ MangaModel mangaModelRes(String res, MangaModel manga) {
images.add("${manga.apiUrl}/cover/$thumbnail");
}
names.add(a["title"]);
final seriesSlug = MBridge.regExp(a["series_slug"], "-\\d+", "", 0, 0);
final seriesSlug = a["series_slug"];
urls.add("/series/$seriesSlug");
}
manga.hasNextPage = false;
}
manga.urls = urls;

View File

@@ -1,7 +1,7 @@
import '../../../model/source.dart';
import '../../../utils/utils.dart';
const heancmsVersion = "0.0.21";
const heancmsVersion = "0.0.3";
const heancmsSourceCodeUrl =
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/manga/multisrc/heancms/heancms-v$heancmsVersion.dart";
const defaultDateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ";

View File

@@ -1,7 +1,7 @@
import 'dart:convert';
import 'package:bridge_lib/bridge_lib.dart';
getPopularManga(MangaModel manga) async {
getPopularManga(MManga manga) async {
final url = "${manga.baseUrl}/manga/page/${manga.page}/?m_orderby=views";
final data = {"url": url, "sourceId": manga.sourceId};
final res = await MBridge.http('GET', json.encode(data));
@@ -25,7 +25,7 @@ getPopularManga(MangaModel manga) async {
return manga;
}
getMangaDetail(MangaModel manga) async {
getMangaDetail(MManga manga) async {
final statusList = [
{
"OnGoing": 0,
@@ -174,7 +174,7 @@ getMangaDetail(MangaModel manga) async {
return manga;
}
getChapterUrl(MangaModel manga) async {
getChapterPages(MManga manga) async {
final datas = {"url": manga.link, "sourceId": manga.sourceId};
final res = await MBridge.http('GET', json.encode(datas));
if (res.isEmpty) {
@@ -222,7 +222,7 @@ getChapterUrl(MangaModel manga) async {
return pageUrls;
}
getLatestUpdatesManga(MangaModel manga) async {
getLatestUpdatesManga(MManga manga) async {
final url = "${manga.baseUrl}/manga/page/${manga.page}/?m_orderby=latest";
final datas = {"url": url, "sourceId": manga.sourceId};
final res = await MBridge.http('GET', json.encode(datas));
@@ -245,7 +245,7 @@ getLatestUpdatesManga(MangaModel manga) async {
return manga;
}
searchManga(MangaModel manga) async {
searchManga(MManga manga) async {
final urll = "${manga.baseUrl}/?s=${manga.query}&post_type=wp-manga";
final datas = {"url": urll, "sourceId": manga.sourceId};
final res = await MBridge.http('GET', json.encode(datas));

View File

@@ -1,7 +1,7 @@
import '../../../model/source.dart';
import '../../../utils/utils.dart';
const madaraVersion = "0.0.2";
const madaraVersion = "0.0.3";
const madaraSourceCodeUrl =
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/manga/multisrc/madara/madara-v$madaraVersion.dart";
const defaultDateFormat = "MMMM dd, yyyy";

View File

@@ -1,7 +1,7 @@
import 'dart:convert';
import 'package:bridge_lib/bridge_lib.dart';
getPopularManga(MangaModel manga) async {
getPopularManga(MManga manga) async {
final url = "${manga.baseUrl}${getMangaUrlDirectory(manga.source)}/?page=${manga.page}&order=popular";
final data = {"url": url, "sourceId": manga.sourceId};
final res = await MBridge.http('GET', json.encode(data));
@@ -14,7 +14,7 @@ getPopularManga(MangaModel manga) async {
return manga;
}
getLatestUpdatesManga(MangaModel manga) async {
getLatestUpdatesManga(MManga manga) async {
final url = "${manga.baseUrl}${getMangaUrlDirectory(manga.source)}/?page=${manga.page}&order=update";
final data = {"url": url, "sourceId": manga.sourceId};
final res = await MBridge.http('GET', json.encode(data));
@@ -27,7 +27,7 @@ getLatestUpdatesManga(MangaModel manga) async {
return manga;
}
getMangaDetail(MangaModel manga) async {
getMangaDetail(MManga manga) async {
final statusList = [
{
"مستمرة": 0,
@@ -125,7 +125,7 @@ getMangaDetail(MangaModel manga) async {
return manga;
}
searchManga(MangaModel manga) async {
searchManga(MManga manga) async {
final url = "${manga.baseUrl}${getMangaUrlDirectory(manga.source)}/?&title=${manga.query}&page=${manga.page}";
final data = {"url": url, "sourceId": manga.sourceId};
final res = await MBridge.http('GET', json.encode(data));
@@ -138,7 +138,7 @@ searchManga(MangaModel manga) async {
return manga;
}
getChapterUrl(MangaModel manga) async {
getChapterPages(MManga manga) async {
final datas = {"url": manga.link, "sourceId": manga.sourceId};
final res = await MBridge.http('GET', json.encode(datas));

View File

@@ -1,7 +1,7 @@
import '../../../model/source.dart';
import '../../../utils/utils.dart';
const mangareaderVersion = "0.0.3";
const mangareaderVersion = "0.0.4";
const mangareaderSourceCodeUrl =
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/manga/multisrc/mangareader/mangareader-v$mangareaderVersion.dart";
const defaultDateFormat = "MMMM dd, yyyy";

View File

@@ -1,7 +1,7 @@
import 'dart:convert';
import 'package:bridge_lib/bridge_lib.dart';
searchManga(MangaModel manga) async {
searchManga(MManga manga) async {
final url = "${manga.baseUrl}/search?query=${manga.query}";
final data = {"url": url, "sourceId": manga.sourceId};
final res = await MBridge.http('GET', json.encode(data));
@@ -35,7 +35,7 @@ searchManga(MangaModel manga) async {
return manga;
}
getPopularManga(MangaModel manga) async {
getPopularManga(MManga manga) async {
final url = "${manga.baseUrl}/filterList?page=${manga.page}&sortBy=views&asc=false";
final data = {"url": url, "sourceId": manga.sourceId};
final res = await MBridge.http('GET', json.encode(data));
@@ -57,7 +57,7 @@ getPopularManga(MangaModel manga) async {
return manga;
}
getMangaDetail(MangaModel manga) async {
getMangaDetail(MManga manga) async {
final statusList = [
{
"complete": 1,
@@ -99,7 +99,7 @@ getMangaDetail(MangaModel manga) async {
return manga;
}
getLatestUpdatesManga(MangaModel manga) async {
getLatestUpdatesManga(MManga manga) async {
final url = "${manga.baseUrl}/latest-release?page=${manga.page}";
final data = {"url": url, "sourceId": manga.sourceId};
final res = await MBridge.http('GET', json.encode(data));
@@ -121,7 +121,7 @@ getLatestUpdatesManga(MangaModel manga) async {
return manga;
}
getChapterUrl(MangaModel manga) async {
getChapterPages(MManga manga) async {
final datas = {"url": manga.link, "sourceId": manga.sourceId};
final res = await MBridge.http('GET', json.encode(datas));
if (res.isEmpty) {

View File

@@ -1,7 +1,7 @@
import '../../../model/source.dart';
import '../../../utils/utils.dart';
const mmrcmsVersion = "0.0.2";
const mmrcmsVersion = "0.0.3";
const mmrcmsSourceCodeUrl =
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/manga/multisrc/mmrcms/mmrcms-v$mmrcmsVersion.dart";
const defaultDateFormat = "d MMM. yyyy";

View File

@@ -1,7 +1,7 @@
import 'dart:convert';
import 'package:bridge_lib/bridge_lib.dart';
getPopularManga(MangaModel manga) async {
getPopularManga(MManga manga) async {
final data = {"url": "${manga.baseUrl}/search/"};
final res = await MBridge.http('GET', json.encode(data));
if (res.isEmpty) {
@@ -13,7 +13,7 @@ getPopularManga(MangaModel manga) async {
return parseDirectory(resSort, manga);
}
getLatestUpdatesManga(MangaModel manga) async {
getLatestUpdatesManga(MManga manga) async {
final data = {"url": "${manga.baseUrl}/search/"};
final res = await MBridge.http('GET', json.encode(data));
if (res.isEmpty) {
@@ -25,7 +25,7 @@ getLatestUpdatesManga(MangaModel manga) async {
return parseDirectory(resSort, manga);
}
searchManga(MangaModel manga) async {
searchManga(MManga manga) async {
final data = {"url": "${manga.baseUrl}/search/"};
final res = await MBridge.http('GET', json.encode(data));
if (res.isEmpty) {
@@ -45,7 +45,7 @@ searchManga(MangaModel manga) async {
return parseDirectory(json.encode(queryRes), manga);
}
getMangaDetail(MangaModel manga) async {
getMangaDetail(MManga manga) async {
final statusList = [
{"Ongoing": 0, "Completed": 1, "Cancelled": 3, "Hiatus": 2}
];
@@ -94,7 +94,7 @@ getMangaDetail(MangaModel manga) async {
return manga;
}
getChapterUrl(MangaModel manga) async {
getChapterPages(MManga manga) async {
final headers = getHeader(manga.baseUrl);
final url = '${manga.baseUrl}${manga.link}';
List<String> pages = [];
@@ -164,7 +164,7 @@ String directoryFromDocument(String res) {
.replaceAll(";", " ");
}
MangaModel parseDirectory(String resSort, MangaModel manga) {
MManga parseDirectory(String resSort, MManga manga) {
final datas = json.decode(resSort) as List;
manga.names = datas.map((e) => e["s"]).toList();
manga.images = datas

View File

@@ -1,7 +1,7 @@
import '../../../model/source.dart';
import '../../../utils/utils.dart';
const nepnepVersion = "0.0.1";
const nepnepVersion = "0.0.2";
const nepnepSourceCodeUrl =
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/manga/multisrc/nepnep/nepnep-v$nepnepVersion.dart";
const defaultDateFormat = "yyyy-MM-dd HH:mm:ss";
@@ -18,7 +18,6 @@ List<Source> _nepnepSourcesList = [
dateFormat: defaultDateFormat,
dateFormatLocale: defaultDateFormatLocale,
version: nepnepVersion,
appMinVerReq: "0.0.5",
sourceCodeUrl: nepnepSourceCodeUrl,
),
Source(
@@ -30,7 +29,6 @@ List<Source> _nepnepSourcesList = [
dateFormat: defaultDateFormat,
dateFormatLocale: defaultDateFormatLocale,
version: nepnepVersion,
appMinVerReq: "0.0.5",
sourceCodeUrl: nepnepSourceCodeUrl,
),
];

View File

@@ -1,7 +1,7 @@
import 'dart:convert';
import 'package:bridge_lib/bridge_lib.dart';
getPopularManga(MangaModel manga) async {
getPopularManga(MManga manga) async {
final url = "${manga.baseUrl}/browse?${lang(manga.lang)}&sort=views_a&page=${manga.page}";
final data = {"url": url, "sourceId": manga.sourceId};
final res = await MBridge.http('GET', json.encode(data));
@@ -16,20 +16,20 @@ String lang(String lang) {
return "langs=$lang";
}
getLatestUpdatesManga(MangaModel manga) async {
getLatestUpdatesManga(MManga manga) async {
final url = "${manga.baseUrl}/browse?${lang(manga.lang)}&sort=update&page=${manga.page}";
final data = {"url": url, "sourceId": manga.sourceId};
final res = await MBridge.http('GET', json.encode(data));
return mangaElementM(res, manga);
}
searchManga(MangaModel manga) async {
searchManga(MManga manga) async {
final data = {"url": "${manga.baseUrl}/search?word=${manga.query}&page=${manga.page}", "sourceId": manga.sourceId};
final res = await MBridge.http('GET', json.encode(data));
return mangaElementM(res, manga);
}
getMangaDetail(MangaModel manga) async {
getMangaDetail(MManga manga) async {
final statusList = [
{
"Ongoing": 0,
@@ -88,7 +88,7 @@ getMangaDetail(MangaModel manga) async {
return manga;
}
getChapterUrl(MangaModel manga) async {
getChapterPages(MManga manga) async {
final datas = {"url": "${manga.baseUrl}${manga.link}", "sourceId": manga.sourceId};
final res = await MBridge.http('GET', json.encode(datas));
if (res.isEmpty) {
@@ -114,7 +114,7 @@ getChapterUrl(MangaModel manga) async {
return pagesUrl;
}
MangaModel mangaElementM(String res, MangaModel manga) async {
MManga mangaElementM(String res, MManga manga) async {
if (res.isEmpty) {
return manga;
}

View File

@@ -1,7 +1,7 @@
import '../../../../model/source.dart';
import '../../../../utils/utils.dart';
const batotoVersion = "0.0.2";
const batotoVersion = "0.0.3";
const batotoSourceCodeUrl =
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/manga/src/all/batoto/batoto-v$batotoVersion.dart";
@@ -128,6 +128,5 @@ List<Source> _batotoSourcesList = languages
isNsfw: isNsfw,
dateFormatLocale: "en",
version: batotoVersion,
appMinVerReq: "0.0.43",
sourceCodeUrl: batotoSourceCodeUrl))
.toList();

View File

@@ -1,8 +1,9 @@
import 'package:bridge_lib/bridge_lib.dart';
import 'dart:convert';
getLatestUpdatesManga(MangaModel manga) async {
final url = "${manga.apiUrl}/v1.0/search?sort=uploaded&page=${manga.page}&tachiyomi=true";
getLatestUpdatesManga(MManga manga) async {
final url =
"${manga.apiUrl}/v1.0/search?sort=uploaded&page=${manga.page}&tachiyomi=true";
final data = {"url": url, "headers": getHeader(manga.baseUrl)};
final res = await MBridge.http('GET', json.encode(data));
if (res.isEmpty) {
@@ -20,7 +21,7 @@ getLatestUpdatesManga(MangaModel manga) async {
return manga;
}
getMangaDetail(MangaModel manga) async {
getMangaDetail(MManga manga) async {
final statusList = [
{
"1": 0,
@@ -32,16 +33,19 @@ getMangaDetail(MangaModel manga) async {
final headers = getHeader(manga.baseUrl);
final urll = "${manga.apiUrl}${manga.link.replaceAll("#", '')}?tachiyomi=true";
final urll =
"${manga.apiUrl}${manga.link.replaceAll("#", '')}?tachiyomi=true";
final data = {"url": urll, "headers": headers};
final res = await MBridge.http('GET', json.encode(data));
if (res.isEmpty) {
return manga;
}
manga.author = MBridge.jsonPathToString(res, r'$.authors[*].name', '');
manga.genre = MBridge.jsonPathToString(res, r'$.genres[*].name', "_.").split("_.");
manga.genre =
MBridge.jsonPathToString(res, r'$.genres[*].name', "_.").split("_.");
manga.description = MBridge.jsonPathToString(res, r'$..desc', '');
manga.status = MBridge.parseStatus(MBridge.jsonPathToString(res, r'$..comic.status', ''), statusList);
manga.status = MBridge.parseStatus(
MBridge.jsonPathToString(res, r'$..comic.status', ''), statusList);
final chapUrlReq =
"${manga.apiUrl}${manga.link.replaceAll("#", '')}chapters?lang=${manga.lang}&tachiyomi=true&page=1";
final dataReq = {"url": chapUrlReq, "headers": headers};
@@ -54,19 +58,32 @@ getMangaDetail(MangaModel manga) async {
final newDataReq = {"url": newChapUrlReq, "headers": headers};
final newRequest = await MBridge.http('GET', json.encode(newDataReq));
manga.urls = MBridge.jsonPathToString(newRequest, r'$.chapters[*].hid', "_.").split("_.");
final chapDate = MBridge.jsonPathToString(newRequest, r'$.chapters[*].created_at', "_.").split("_.");
manga.chaptersDateUploads =MBridge.listParseDateTime(chapDate, "yyyy-MM-dd'T'HH:mm:ss'Z'", "en");
manga.chaptersVolumes = MBridge.jsonPathToString(newRequest, r'$.chapters[*].vol', "_.").split("_.");
manga.chaptersScanlators = MBridge.jsonPathToString(newRequest, r'$.chapters[*].group_name', "_.").split("_.");
manga.names = MBridge.jsonPathToString(newRequest, r'$.chapters[*].title', "_.").split("_.");
manga.chaptersChaps = MBridge.jsonPathToString(newRequest, r'$.chapters[*].chap', "_.").split("_.");
manga.urls = MBridge.jsonPathToString(newRequest, r'$.chapters[*].hid', "_.")
.split("_.");
final chapDate =
MBridge.jsonPathToString(newRequest, r'$.chapters[*].created_at', "_.")
.split("_.");
manga.chaptersDateUploads =
MBridge.listParseDateTime(chapDate, "yyyy-MM-dd'T'HH:mm:ss'Z'", "en");
manga.chaptersVolumes =
MBridge.jsonPathToString(newRequest, r'$.chapters[*].vol', "_.")
.split("_.");
manga.chaptersScanlators =
MBridge.jsonPathToString(newRequest, r'$.chapters[*].group_name', "_.")
.split("_.");
manga.names =
MBridge.jsonPathToString(newRequest, r'$.chapters[*].title', "_.")
.split("_.");
manga.chaptersChaps =
MBridge.jsonPathToString(newRequest, r'$.chapters[*].chap', "_.")
.split("_.");
return manga;
}
getPopularManga(MangaModel manga) async {
final urll = "${manga.apiUrl}/v1.0/search?sort=follow&page=${manga.page}&tachiyomi=true";
getPopularManga(MManga manga) async {
final urll =
"${manga.apiUrl}/v1.0/search?sort=follow&page=${manga.page}&tachiyomi=true";
final data = {"url": urll, "headers": getHeader(manga.baseUrl)};
final res = await MBridge.http('GET', json.encode(data));
if (res.isEmpty) {
@@ -83,7 +100,7 @@ getPopularManga(MangaModel manga) async {
return manga;
}
searchManga(MangaModel manga) async {
searchManga(MManga manga) async {
final urll = "${manga.apiUrl}/v1.0/search?q=${manga.query}&tachiyomi=true";
final data = {"url": urll, "headers": getHeader(manga.baseUrl)};
final res = await MBridge.http('GET', json.encode(data));
@@ -101,20 +118,22 @@ searchManga(MangaModel manga) async {
return manga;
}
getChapterUrl(MangaModel manga) async {
getChapterPages(MManga manga) async {
final url = "${manga.apiUrl}/chapter/${manga.link}?tachiyomi=true";
final data = {"url": url, "headers": getHeader(url)};
final res = await MBridge.http('GET', json.encode(data));
if (res.isEmpty) {
return [];
}
return MBridge.jsonPathToString(res, r'$.chapter.images[*].url', '_.').split('_.');
return MBridge.jsonPathToString(res, r'$.chapter.images[*].url', '_.')
.split('_.');
}
Map<String, String> getHeader(String url) {
final headers = {
"Referer": "$url/",
'User-Agent': "Tachiyomi Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:110.0) Gecko/20100101 Firefox/110.0"
'User-Agent':
"Tachiyomi Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:110.0) Gecko/20100101 Firefox/110.0"
};
return headers;
}

View File

@@ -1,7 +1,7 @@
import '../../../../model/source.dart';
import '../../../../utils/utils.dart';
const comickVersion = "0.0.2";
const comickVersion = "0.0.3";
const comickSourceCodeUrl =
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/manga/src/all/comick/comick-v$comickVersion.dart";

View File

@@ -1,43 +1,198 @@
import 'package:bridge_lib/bridge_lib.dart';
import 'dart:convert';
getPopularManga(MManga manga) async {
int page = (20 * (manga.page - 1));
final url =
"https://api.mangadex.org/manga?limit=20&offset=$page&availableTranslatedLanguage[]=en&includes[]=cover_art${getMDXContentRating()}&order[followedCount]=desc";
final datas = {"url": url};
final res = await MBridge.http('GET', json.encode(datas));
return parseManga(res, manga);
}
getLatestUpdatesManga(MManga manga) async {
int page = (20 * (manga.page - 1));
final urll =
"https://api.mangadex.org/chapter?limit=20&offset=$page&translatedLanguage[]=${manga.lang}&includeFutureUpdates=0&order[publishAt]=desc&includeFuturePublishAt=0&includeEmptyPages=0";
final datas = {"url": urll};
final ress = await MBridge.http('GET', json.encode(datas));
if (ress.isEmpty) {
return manga;
}
final mangaIds = MBridge.listParse(
MBridge.jsonPathToString(ress, r'$.data[*].relationships[*].id', '.--')
.split('.--'),
3);
String mangaa = "".toString();
for (var id in mangaIds) {
mangaa += "&ids[]=$id";
}
final newUrl =
"https://api.mangadex.org/manga?includes[]=cover_art&limit=${mangaIds.length}${getMDXContentRating()}$mangaa";
final datass = {"url": newUrl};
final res = await MBridge.http('GET', json.encode(datass));
return parseManga(res, manga);
}
searchManga(MManga manga) async {
final url =
"https://api.mangadex.org/manga?includes[]=cover_art&offset=0&limit=20&title=${manga.query}${getMDXContentRating()}&order[followedCount]=desc&availableTranslatedLanguage[]=${manga.lang}";
final datas = {"url": url};
final res = await MBridge.http('GET', json.encode(datas));
if (res.isEmpty) {
return manga;
}
return parseManga(res, manga);
}
getMangaDetail(MManga manga) async {
final statusList = [
{
"ongoing": 0,
"completed": 1,
"hiatus": 2,
"cancelled": 3,
}
];
final url =
"https://api.mangadex.org${manga.link}?includes[]=cover_art&includes[]=author&includes[]=artist";
final datas = {"url": url};
final res = await MBridge.http('GET', json.encode(datas));
if (res.isEmpty) {
return manga;
}
manga.author = MBridge.jsonPathToString(
res, r'$..data.relationships[*].attributes.name', ', ');
String expressionDescriptionA = r'$..data.attributes.description.en';
String expressionDescription = MBridge.regExp(
r'$..data.attributes.description[a]', r'\[a\]', ".${manga.lang}", 0, 1);
String description = MBridge.jsonPathToString(res, expressionDescription, '');
if (description.isEmpty) {
description = MBridge.jsonPathToString(res, expressionDescriptionA, '');
}
manga.description = description;
List<String> genres = [];
final genre = MBridge.listParse(
MBridge.jsonPathToString(
res, r'$..data.attributes.tags[*].attributes.name.en', '.-')
.split('.-'),
0);
genres = genre;
String contentRating =
MBridge.jsonPathToString(res, r'$..data.attributes.contentRating', '');
if (contentRating == "safe") {
} else {
genres.add(contentRating);
}
String publicationDemographic = MBridge.jsonPathToString(
res, r'$..data.attributes.publicationDemographic', '');
if (publicationDemographic == "null") {
} else {
genres.add(publicationDemographic);
}
manga.genre = genres;
String statusRes =
MBridge.jsonPathToString(res, r'$..data.attributes.status', '');
manga.status = MBridge.parseStatus(statusRes, statusList);
final mangaId = MBridge.listParse(manga.link.split('/'), 2)[0];
final paginatedChapterList =
await paginatedChapterListRequest(mangaId, 0, manga.lang);
final chapterList =
MBridge.jsonPathToString(paginatedChapterList, r'$.data[*]', '_.')
.split('_.');
int limit = MBridge.intParse(
MBridge.jsonPathToString(paginatedChapterList, r'$.limit', ''));
int offset = MBridge.intParse(
MBridge.jsonPathToString(paginatedChapterList, r'$.offset', ''));
int total = MBridge.intParse(
MBridge.jsonPathToString(paginatedChapterList, r'$.total', ''));
List<MManga> chapterListA = [];
List<String> chapNames = [];
List<String> scanlators = [];
List<String> chapterUrl = [];
List<String> chapterDate = [];
final list = getChapters(
manga, MBridge.intParse("${chapterList.length}"), paginatedChapterList);
chapterListA.add(list);
var hasMoreResults = (limit + offset) < total;
while (hasMoreResults) {
offset += limit;
var newRequest =
await paginatedChapterListRequest(mangaId, offset, manga.lang);
int total =
MBridge.intParse(MBridge.jsonPathToString(newRequest, r'$.total', ''));
final chapterList =
MBridge.jsonPathToString(paginatedChapterList, r'$.data[*]', '_.')
.split('_.');
final list = getChapters(
manga, MBridge.intParse("${chapterList.length}"), newRequest);
chapterListA.add(list);
hasMoreResults = (limit + offset) < total;
}
for (var element in chapterListA) {
for (var name in element.names) {
if (name.isNotEmpty) {
chapNames.add(name);
}
}
}
for (var element in chapterListA) {
for (var url in element.urls) {
if (url.isNotEmpty) {
chapterUrl.add(url);
}
}
}
for (var element in chapterListA) {
for (var chapDate in element.chaptersDateUploads) {
if (chapDate.isNotEmpty) {
chapterDate.add(chapDate);
}
}
}
for (var element in chapterListA) {
for (var scanlator in element.chaptersScanlators) {
if (scanlator.isNotEmpty) {
scanlators.add(scanlator);
}
}
}
manga.urls = chapterUrl;
manga.chaptersDateUploads = chapterDate;
manga.chaptersScanlators = scanlators;
manga.names = chapNames;
return manga;
}
getChapterPages(MManga manga) async {
final url = "https://api.mangadex.org/at-home/server/${manga.link}";
final data = {"url": url};
final res = await MBridge.http('GET', json.encode(data));
if (res.isEmpty) {
return [];
}
final dataRes = json.decode(res);
final host = dataRes["baseUrl"];
final hash = dataRes["chapter"]["hash"];
final chapterDatas = dataRes["chapter"]["data"] as List;
return chapterDatas.map((e) => "$host/data/$hash/$e").toList();
}
String getMDXContentRating() {
String ctnRating =
"&contentRating[]=suggestive&contentRating[]=safe&contentRating[]=erotica&contentRating[]=pornographic";
return ctnRating;
}
getPopularManga(MangaModel manga) async {
int page = (20 * (manga.page - 1));
final url =
"https://api.mangadex.org/manga?limit=20&offset=$page&availableTranslatedLanguage[]=en&includes[]=cover_art${getMDXContentRating()}&order[followedCount]=desc";
final datas = {"url": url, "headers": null};
final res = await MBridge.http('GET', json.encode(datas));
if (res.isEmpty) {
return manga;
}
List<String> data = MBridge.listParse(
MBridge.jsonPathToString(res, r'$.data[*]', '_.').split("_."), 0);
List<String> urlList = [];
List<String> titleList = [];
List<String> imageList = [];
for (var i = 0; i < data.length; i++) {
final expressionId =
MBridge.regExp(r'$.data[a].id', r'\[a\]', "[$i]", 0, 1);
final id = MBridge.jsonPathToString(res, expressionId, '_.');
titleList.add(findTitle(res, i, manga.lang));
urlList.add("/manga/$id");
imageList.add(getCover(res, i, id));
}
manga.names = titleList;
manga.urls = urlList;
manga.images = imageList;
return manga;
}
MangaModel getChapters(
MangaModel manga, int length, String paginatedChapterListA) {
MManga getChapters(MManga manga, int length, String paginatedChapterListA) {
String scanlators = "".toString();
String chapNames = "".toString();
String chapDate = "".toString();
@@ -120,289 +275,52 @@ MangaModel getChapters(
return manga;
}
getMangaDetail(MangaModel manga) async {
final statusList = [
{
"ongoing": 0,
"completed": 1,
"hiatus": 2,
"cancelled": 3,
}
];
final url =
"https://api.mangadex.org${manga.link}?includes[]=cover_art&includes[]=author&includes[]=artist";
final datas = {"url": url, "headers": null};
final res = await MBridge.http('GET', json.encode(datas));
if (res.isEmpty) {
return manga;
}
manga.author = MBridge.jsonPathToString(
res, r'$..data.relationships[*].attributes.name', ', ');
String expressionDescriptionA = r'$..data.attributes.description.en';
String expressionDescription = MBridge.regExp(
r'$..data.attributes.description[a]', r'\[a\]', ".${manga.lang}", 0, 1);
String description = MBridge.jsonPathToString(res, expressionDescription, '');
if (description.isEmpty) {
description = MBridge.jsonPathToString(res, expressionDescriptionA, '');
}
manga.description = description;
List<String> genres = [];
final genre = MBridge.listParse(
MBridge.jsonPathToString(
res, r'$..data.attributes.tags[*].attributes.name.en', '.-')
.split('.-'),
0);
genres = genre;
String contentRating =
MBridge.jsonPathToString(res, r'$..data.attributes.contentRating', '');
if (contentRating == "safe") {
} else {
genres.add(contentRating);
}
String publicationDemographic = MBridge.jsonPathToString(
res, r'$..data.attributes.publicationDemographic', '');
if (publicationDemographic == "null") {
} else {
genres.add(publicationDemographic);
}
manga.genre = genres;
String statusRes =
MBridge.jsonPathToString(res, r'$..data.attributes.status', '');
manga.status = MBridge.parseStatus(statusRes, statusList);
final mangaId = MBridge.listParse(manga.link.split('/'), 2)[0];
final paginatedChapterList =
await paginatedChapterListRequest(mangaId, 0, manga.lang);
final chapterList =
MBridge.jsonPathToString(paginatedChapterList, r'$.data[*]', '_.')
.split('_.');
int limit = MBridge.intParse(
MBridge.jsonPathToString(paginatedChapterList, r'$.limit', ''));
int offset = MBridge.intParse(
MBridge.jsonPathToString(paginatedChapterList, r'$.offset', ''));
int total = MBridge.intParse(
MBridge.jsonPathToString(paginatedChapterList, r'$.total', ''));
List<MangaModel> chapterListA = [];
List<String> chapNames = [];
List<String> scanlators = [];
List<String> chapterUrl = [];
List<String> chapterDate = [];
final list = getChapters(
manga, MBridge.intParse("${chapterList.length}"), paginatedChapterList);
chapterListA.add(list);
var hasMoreResults = (limit + offset) < total;
while (hasMoreResults) {
offset += limit;
var newRequest =
await paginatedChapterListRequest(mangaId, offset, manga.lang);
int total =
MBridge.intParse(MBridge.jsonPathToString(newRequest, r'$.total', ''));
final chapterList =
MBridge.jsonPathToString(paginatedChapterList, r'$.data[*]', '_.')
.split('_.');
final list = getChapters(
manga, MBridge.intParse("${chapterList.length}"), newRequest);
chapterListA.add(list);
hasMoreResults = (limit + offset) < total;
}
for (var element in chapterListA) {
for (var name in element.names) {
if (name.isEmpty) {
} else {
chapNames.add(name);
}
}
}
for (var element in chapterListA) {
for (var url in element.urls) {
if (url.isEmpty) {
} else {
chapterUrl.add(url);
}
}
}
for (var element in chapterListA) {
for (var chapDate in element.chaptersDateUploads) {
if (chapDate.isEmpty) {
} else {
chapterDate.add(chapDate);
}
}
}
for (var element in chapterListA) {
for (var scanlator in element.chaptersScanlators) {
if (scanlator.isEmpty) {
} else {
scanlators.add(scanlator);
}
}
}
manga.urls = chapterUrl;
manga.chaptersDateUploads = chapterDate;
manga.chaptersScanlators = scanlators;
manga.names = chapNames;
return manga;
}
getLatestUpdatesManga(MangaModel manga) async {
int page = (20 * (manga.page - 1));
final urll =
"https://api.mangadex.org/chapter?limit=20&offset=$page&translatedLanguage[]=${manga.lang}&includeFutureUpdates=0&order[publishAt]=desc&includeFuturePublishAt=0&includeEmptyPages=0";
final datas = {"url": urll, "headers": null};
final ress = await MBridge.http('GET', json.encode(datas));
if (ress.isEmpty) {
return manga;
}
final mangaIds = MBridge.listParse(
MBridge.jsonPathToString(ress, r'$.data[*].relationships[*].id', '.--')
.split('.--'),
3);
String mangaa = "".toString();
for (var id in mangaIds) {
mangaa += "&ids[]=$id";
}
final newUrl =
"https://api.mangadex.org/manga?includes[]=cover_art&limit=${mangaIds.length}${getMDXContentRating()}$mangaa";
final datass = {"url": newUrl, "headers": null};
final res = await MBridge.http('GET', json.encode(datass));
List<String> data = MBridge.listParse(
MBridge.jsonPathToString(res, r'$.data[*]', '_.').split("_."), 0);
List<String> urlList = [];
List<String> titleList = [];
List<String> imageList = [];
for (var i = 0; i < data.length; i++) {
final expressionId =
MBridge.regExp(r'$.data[a].id', r'\[a\]', "[$i]", 0, 1);
final id = MBridge.jsonPathToString(res, expressionId, '_.');
titleList.add(findTitle(res, i, manga.lang));
urlList.add("/manga/$id");
imageList.add(getCover(res, i, id));
}
manga.names = titleList;
manga.urls = urlList;
manga.images = imageList;
return manga;
}
searchManga(MangaModel manga) async {
final url =
"https://api.mangadex.org/manga?includes[]=cover_art&offset=0&limit=20&title=${manga.query}${getMDXContentRating()}&order[followedCount]=desc&availableTranslatedLanguage[]=${manga.lang}";
final datas = {"url": url, "headers": null};
final res = await MBridge.http('GET', json.encode(datas));
if (res.isEmpty) {
return manga;
}
List<String> data = MBridge.listParse(
MBridge.jsonPathToString(res, r'$.data[*]', '_.').split("_."), 0);
List<String> urlList = [];
List<String> titleList = [];
List<String> imageList = [];
for (var i = 0; i < data.length; i++) {
final expressionId =
MBridge.regExp(r'$.data[a].id', r'\[a\]', "[$i]", 0, 1);
final id = MBridge.jsonPathToString(res, expressionId, '_.');
titleList.add(findTitle(res, i, manga.lang));
urlList.add("/manga/$id");
imageList.add(getCover(res, i, id));
}
manga.names = titleList;
manga.urls = urlList;
manga.images = imageList;
return manga;
}
getChapterUrl(MangaModel manga) async {
final url = "https://api.mangadex.org/at-home/server/${manga.link}";
final data = {"url": url, "headers": null};
final res = await MBridge.http('GET', json.encode(data));
if (res.isEmpty) {
return [];
}
final host = MBridge.jsonPathToString(res, r'$.baseUrl', '');
final hash = MBridge.jsonPathToString(res, r'$.chapter.hash', '');
List<String> pageSuffix = [];
List<String> pageUrls = [];
List<String> chapterDatas = MBridge.listParse(
MBridge.jsonPathToString(res, r'$.chapter.data[*]', '.--').split('.--'),
0);
for (var d in chapterDatas) {
pageSuffix.add("/data/$hash/$d");
}
for (var url in pageSuffix) {
pageUrls.add("$host$url");
}
return pageUrls;
}
Future<String> paginatedChapterListRequest(
String mangaId, int offset, String lang) async {
final url =
'https://api.mangadex.org/manga/$mangaId/feed?limit=500&offset=$offset&includes[]=user&includes[]=scanlation_group&order[volume]=desc&order[chapter]=desc&translatedLanguage[]=$lang&includeFuturePublishAt=0&includeEmptyPages=0${getMDXContentRating()}';
final datas = {"url": url, "headers": null};
final datas = {"url": url};
return await MBridge.http('GET', json.encode(datas));
}
String findTitle(String dataRes, int mangaIndex, String lang) {
String expressionAltTitlesA = MBridge.regExp(
r'$.data[a].attributes.altTitles[b]', r'\[a\]', "[$mangaIndex]", 0, 1);
String expressionAltTitles =
MBridge.regExp(expressionAltTitlesA, r'\[b\]', "[*].$lang", 0, 1);
String altTitles =
MBridge.jsonPathToString(dataRes, expressionAltTitles, '_.');
if (altTitles.isEmpty) {
expressionAltTitles = MBridge.regExp(
r'$.data[a].attributes.altTitles[?@.en].en',
r'\[a\]',
"[$mangaIndex]",
0,
1);
altTitles = MBridge.jsonPathToString(dataRes, expressionAltTitles, '_.');
}
List<String> dataAltTitles = MBridge.listParse(altTitles.split('_.'), 0);
final expressionTitle = MBridge.regExp(
r'$.data[a].attributes.title.en', r'\[a\]', "[$mangaIndex]", 0, 1);
final title = MBridge.jsonPathToString(dataRes, expressionTitle, '_.');
String findTitle(Map<String, dynamic> dataRes, String lang) {
final altTitlesJ = dataRes["attributes"]["altTitles"];
final titleJ = dataRes["attributes"]["title"];
final title = MBridge.getMapValue(json.encode(titleJ), "en");
if (title.isEmpty) {
return dataAltTitles[0];
} else {
return title;
for (var r in altTitlesJ) {
final altTitle = MBridge.getMapValue(json.encode(r), "en");
if (altTitle.isNotEmpty) {
return altTitle;
}
}
}
return title;
}
String getCover(String dataRes, int mangaIndex, String mangaId) {
final expressionRelationAll = MBridge.regExp(
r'$.data[a].relationships[*]', r'\[a\]', "[$mangaIndex]", 0, 1);
List<String> relationDatas = MBridge.listParse(
MBridge.jsonPathToString(dataRes, expressionRelationAll, '_.')
.split("_."),
0);
String getCover(Map<String, dynamic> dataRes) {
final relationships = dataRes["relationships"];
String coverFileName = "".toString();
for (var j = 0; j < relationDatas.length; j++) {
final expressionData = MBridge.regExp(
r'$.data[a].relationships[b]', r'\[a\]', "[$mangaIndex]", 0, 1);
final expressionRelationType =
MBridge.regExp(expressionData, r'\[b\]', "[$j].type", 0, 1);
final relationType =
MBridge.jsonPathToString(dataRes, expressionRelationType, '');
for (var a in relationships) {
final relationType = a["type"];
if (relationType == "cover_art") {
if (coverFileName.isEmpty) {
final expressionRelationCoverFile = MBridge.regExp(
expressionData, r'\[b\]', "[$j].attributes.fileName", 0, 1);
coverFileName =
MBridge.jsonPathToString(dataRes, expressionRelationCoverFile, '');
coverFileName =
"https://uploads.mangadex.org/covers/$mangaId/$coverFileName";
"https://uploads.mangadex.org/covers/${dataRes["id"]}/${a["attributes"]["fileName"]}";
}
}
}
return coverFileName;
}
MManga parseManga(String res, MManga manga) {
if (res.isEmpty) {
return manga;
}
final datasRes = json.decode(res);
final resJson = datasRes["data"] as List;
manga.names = resJson.map((e) => findTitle(e, manga.lang)).toList();
manga.urls = resJson.map((e) => "/manga/${e["id"]}").toList();
manga.images = resJson.map((e) => getCover(e)).toList();
return manga;
}

View File

@@ -4,7 +4,7 @@ import '../../../../utils/utils.dart';
const apiUrl = 'https://api.mangadex.org';
const baseUrl = 'https://mangadex.org';
const isNsfw = true;
const mangadexVersion = "0.0.2";
const mangadexVersion = "0.0.3";
const mangadexSourceCodeUrl =
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/manga/src/all/mangadex/mangadex-v$mangadexVersion.dart";
String _iconUrl = getIconUrl("mangadex", "all");

View File

@@ -1,7 +1,7 @@
import 'dart:convert';
import 'package:bridge_lib/bridge_lib.dart';
searchManga(MangaModel manga) async {
searchManga(MManga manga) async {
final headers = getHeader(manga.baseUrl);
final url = "${manga.baseUrl}/search?title=${manga.query}&page=${manga.page}";
@@ -11,14 +11,16 @@ searchManga(MangaModel manga) async {
return manga;
}
manga.names = MBridge.xpath(res, '//*[contains(@class, "manga-list-4-list")]/li/a/@title');
manga.images =
MBridge.xpath(res, '//*[contains(@class, "manga-list-4-list")]/li/a/img[@class="manga-list-4-cover"]/@src');
manga.urls = MBridge.xpath(res, '//*[contains(@class, "manga-list-4-list")]/li/a/@href');
manga.names = MBridge.xpath(
res, '//*[contains(@class, "manga-list-4-list")]/li/a/@title');
manga.images = MBridge.xpath(res,
'//*[contains(@class, "manga-list-4-list")]/li/a/img[@class="manga-list-4-cover"]/@src');
manga.urls = MBridge.xpath(
res, '//*[contains(@class, "manga-list-4-list")]/li/a/@href');
return manga;
}
getLatestUpdatesManga(MangaModel manga) async {
getLatestUpdatesManga(MManga manga) async {
final headers = getHeader(manga.baseUrl);
final url = "${manga.baseUrl}/directory/${manga.page}.htm?latest";
@@ -28,14 +30,16 @@ getLatestUpdatesManga(MangaModel manga) async {
return manga;
}
manga.names = MBridge.xpath(res, '//*[ contains(@class, "manga-list-1-list")]/li/a/@title');
manga.images =
MBridge.xpath(res, '//*[ contains(@class, "manga-list-1-list")]/li/a/img[@class="manga-list-1-cover"]/@src');
manga.urls = MBridge.xpath(res, '//*[ contains(@class, "manga-list-1-list")]/li/a/@href');
manga.names = MBridge.xpath(
res, '//*[ contains(@class, "manga-list-1-list")]/li/a/@title');
manga.images = MBridge.xpath(res,
'//*[ contains(@class, "manga-list-1-list")]/li/a/img[@class="manga-list-1-cover"]/@src');
manga.urls = MBridge.xpath(
res, '//*[ contains(@class, "manga-list-1-list")]/li/a/@href');
return manga;
}
getMangaDetail(MangaModel manga) async {
getMangaDetail(MManga manga) async {
final statusList = [
{
"Ongoing": 0,
@@ -49,20 +53,28 @@ getMangaDetail(MangaModel manga) async {
if (res.isEmpty) {
return manga;
}
manga.author = MBridge.xpath(res, '//*[@class="detail-info-right-say"]/a/text()').first;
manga.description = MBridge.xpath(res, '//*[@class="fullcontent"]/text()').first;
final status = MBridge.xpath(res, '//*[@class="detail-info-right-title-tip"]/text()').first;
manga.author =
MBridge.xpath(res, '//*[@class="detail-info-right-say"]/a/text()').first;
manga.description =
MBridge.xpath(res, '//*[@class="fullcontent"]/text()').first;
final status =
MBridge.xpath(res, '//*[@class="detail-info-right-title-tip"]/text()')
.first;
manga.status = MBridge.parseStatus(status, statusList);
manga.genre = MBridge.xpath(res, '//*[@class="detail-info-right-tag-list"]/a/text()');
manga.genre =
MBridge.xpath(res, '//*[@class="detail-info-right-tag-list"]/a/text()');
manga.urls = MBridge.xpath(res, '//*[@class="detail-main-list"]/li/a/@href');
manga.names = MBridge.xpath(res, '//*[@class="detail-main-list"]/li/a/div/p[@class="title3"]/text()');
final chapterDates = MBridge.xpath(res, '//*[@class="detail-main-list"]/li/a/div/p[@class="title2"]/text()');
manga.names = MBridge.xpath(
res, '//*[@class="detail-main-list"]/li/a/div/p[@class="title3"]/text()');
final chapterDates = MBridge.xpath(
res, '//*[@class="detail-main-list"]/li/a/div/p[@class="title2"]/text()');
manga.chaptersDateUploads = MBridge.listParseDateTime(chapterDates, manga.dateFormat, manga.dateFormatLocale);
manga.chaptersDateUploads = MBridge.listParseDateTime(
chapterDates, manga.dateFormat, manga.dateFormatLocale);
return manga;
}
getPopularManga(MangaModel manga) async {
getPopularManga(MManga manga) async {
final headers = getHeader(manga.baseUrl);
final url = "${manga.baseUrl}/directory/${manga.page}.htm";
@@ -72,14 +84,16 @@ getPopularManga(MangaModel manga) async {
return manga;
}
manga.names = MBridge.xpath(res, '//*[ contains(@class, "manga-list-1-list")]/li/a/@title');
manga.images =
MBridge.xpath(res, '//*[ contains(@class, "manga-list-1-list")]/li/a/img[@class="manga-list-1-cover"]/@src');
manga.urls = MBridge.xpath(res, '//*[ contains(@class, "manga-list-1-list")]/li/a/@href');
manga.names = MBridge.xpath(
res, '//*[ contains(@class, "manga-list-1-list")]/li/a/@title');
manga.images = MBridge.xpath(res,
'//*[ contains(@class, "manga-list-1-list")]/li/a/img[@class="manga-list-1-cover"]/@src');
manga.urls = MBridge.xpath(
res, '//*[ contains(@class, "manga-list-1-list")]/li/a/@href');
return manga;
}
getChapterUrl(MangaModel manga) async {
getChapterPages(MManga manga) async {
final headers = getHeader(manga.baseUrl);
final url = "${manga.baseUrl}${manga.link}";
final data = {"url": url, "headers": headers};
@@ -90,32 +104,41 @@ getChapterUrl(MangaModel manga) async {
final pages = MBridge.xpath(res, "//body/div/div/span/a/text()");
List<String> pageUrls = [];
if (pages.isEmpty) {
final script =
MBridge.xpath(res, "//script[contains(text(),'function(p,a,c,k,e,d)')]/text()").first.replaceAll("eval", "");
final script = MBridge.xpath(
res, "//script[contains(text(),'function(p,a,c,k,e,d)')]/text()")
.first
.replaceAll("eval", "");
String deobfuscatedScript = MBridge.evalJs(script);
int a = deobfuscatedScript.indexOf("newImgs=['") + 10;
int b = deobfuscatedScript.indexOf("'];");
List<String> urls = MBridge.listParse(deobfuscatedScript.substring(a, b).split("','"), 0);
List<String> urls = deobfuscatedScript.substring(a, b).split("','");
for (var url in urls) {
pageUrls.add("https:$url");
}
} else {
final pagesNumberList = pages;
int pagesNumber = MBridge.intParse(pagesNumberList[pagesNumberList.length - 2]);
int pagesNumber =
MBridge.intParse(pagesNumberList[pagesNumberList.length - 2]);
int secretKeyScriptLocation = res.indexOf("eval(function(p,a,c,k,e,d)");
int secretKeyScriptEndLocation = res.indexOf("</script>", secretKeyScriptLocation);
String secretKeyScript = res.substring(secretKeyScriptLocation, secretKeyScriptEndLocation).replaceAll("eval", "");
int secretKeyScriptEndLocation =
res.indexOf("</script>", secretKeyScriptLocation);
String secretKeyScript = res
.substring(secretKeyScriptLocation, secretKeyScriptEndLocation)
.replaceAll("eval", "");
String secretKeyDeobfuscatedScript = MBridge.evalJs(secretKeyScript);
int secretKeyStartLoc = secretKeyDeobfuscatedScript.indexOf("'");
int secretKeyEndLoc = secretKeyDeobfuscatedScript.indexOf(";");
String secretKey = secretKeyDeobfuscatedScript.substring(secretKeyStartLoc, secretKeyEndLoc);
String secretKey = secretKeyDeobfuscatedScript.substring(
secretKeyStartLoc, secretKeyEndLoc);
int chapterIdStartLoc = res.indexOf("chapterid");
String chapterId = res.substring(chapterIdStartLoc + 11, res.indexOf(";", chapterIdStartLoc));
String chapterId = res.substring(
chapterIdStartLoc + 11, res.indexOf(";", chapterIdStartLoc));
String pageBase = url.substring(0, url.lastIndexOf("/"));
for (int i = 1; i <= pagesNumber; i++) {
String pageLink = "$pageBase/chapterfun.ashx?cid=$chapterId&page=$i&key=$secretKey";
String responseText = MBridge.stringParse("", 0);
String pageLink =
"$pageBase/chapterfun.ashx?cid=$chapterId&page=$i&key=$secretKey";
String responseText = "".toString();
for (int tr = 1; tr <= 3; tr++) {
if (responseText.isEmpty) {
final headers = {
@@ -127,23 +150,26 @@ getChapterUrl(MangaModel manga) async {
"X-Requested-With": "XMLHttpRequest"
};
final data = {"url": pageLink, "headers": headers};
final response = await MBridge.http('GET', json.encode(data));
responseText = MBridge.stringParse(response, 0);
responseText = await MBridge.http('GET', json.encode(data));
if (responseText.isEmpty) {
secretKey = "";
}
}
}
String deobfuscatedScript = MBridge.evalJs(responseText.replaceAll("eval", ""));
String deobfuscatedScript =
MBridge.evalJs(responseText.replaceAll("eval", ""));
int baseLinkStartPos = deobfuscatedScript.indexOf("pix=") + 5;
int baseLinkEndPos = deobfuscatedScript.indexOf(";", baseLinkStartPos) - 1;
String baseLink = deobfuscatedScript.substring(baseLinkStartPos, baseLinkEndPos);
int baseLinkEndPos =
deobfuscatedScript.indexOf(";", baseLinkStartPos) - 1;
String baseLink =
deobfuscatedScript.substring(baseLinkStartPos, baseLinkEndPos);
int imageLinkStartPos = deobfuscatedScript.indexOf("pvalue=") + 9;
int imageLinkEndPos = deobfuscatedScript.indexOf("\"", imageLinkStartPos);
String imageLink = deobfuscatedScript.substring(imageLinkStartPos, imageLinkEndPos);
String imageLink =
deobfuscatedScript.substring(imageLinkStartPos, imageLinkEndPos);
pageUrls.add("https:$baseLink$imageLink");
}
}

View File

@@ -2,7 +2,7 @@ import '../../../../model/source.dart';
import '../../../../utils/utils.dart';
Source get mangahereSource => _mangahereSource;
const mangahereVersion = "0.0.2";
const mangahereVersion = "0.0.3";
const mangahereSourceCodeUrl =
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/manga/src/en/mangahere/mangahere-v$mangahereVersion.dart";
Source _mangahereSource = Source(

View File

@@ -47,7 +47,7 @@ class Source {
this.version = "",
this.isManga = true,
this.isFullData = false,
this.appMinVerReq = "0.0.46"});
this.appMinVerReq = "0.0.6"});
Map<String, dynamic> toJson() {
return {