This commit is contained in:
kodjomoustapha
2023-10-30 19:05:35 +01:00
parent f3c6cf8b59
commit b8c4c2c3c3
51 changed files with 3711 additions and 3469 deletions

View File

@@ -1,251 +0,0 @@
import 'dart:convert';
import 'package:bridge_lib/bridge_lib.dart';
searchManga(MManga manga) async {
final headers = getHeader(manga.baseUrl);
MHttpResponse response = MHttpResponse();
if (!useNewQueryEndpoint(manga.source)) {
final url = "${manga.apiUrl}/series/search";
final body = {"term": manga.query};
final data = {"url": url, "headers": headers, "body": body};
response = await MBridge.http('POST', json.encode(data));
} else {
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};
response = await MBridge.http('GET', json.encode(newEndpointData));
}
if (response.hasError) {
return response;
}
return mMangaRes(response, manga);
}
getPopularManga(MManga manga) async {
final headers = getHeader(manga.baseUrl);
MHttpResponse response = MHttpResponse();
if (!useNewQueryEndpoint(manga.source)) {
final url = "${manga.apiUrl}/series/querysearch";
print(url);
final body = {
"page": manga.page,
"order": "desc",
"order_by": "total_views",
"series_status": "Ongoing",
"series_type": "Comic"
};
final data = {
"url": url,
"headers": headers,
"sourceId": manga.sourceId,
"body": body
};
response = await MBridge.http('POST', json.encode(data));
} else {
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
};
response = await MBridge.http('GET', json.encode(newEndpointData));
}
return mMangaRes(response, manga);
}
getLatestUpdatesManga(MManga manga) async {
final headers = getHeader(manga.baseUrl);
MHttpResponse response = MHttpResponse();
if (!useNewQueryEndpoint(manga.source)) {
final url = "${manga.apiUrl}/series/querysearch";
final body = {
"page": manga.page,
"order": "desc",
"order_by": "latest",
"series_status": "Ongoing",
"series_type": "Comic"
};
final data = {
"url": url,
"headers": headers,
"sourceId": manga.sourceId,
"body": body
};
response = await MBridge.http('POST', json.encode(data));
} else {
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};
response = await MBridge.http('GET', json.encode(newEndpointData));
}
return mMangaRes(response, manga);
}
getMangaDetail(MManga manga) async {
String currentSlug = MBridge.substringAfterLast(manga.link, "/");
final headers = getHeader(manga.baseUrl);
final url = "${manga.apiUrl}/series/$currentSlug";
final data = {"url": url, "headers": headers};
final response = await MBridge.http('GET', json.encode(data));
if (response.hasError) {
return response;
}
String res = response.body;
manga.author = MBridge.getMapValue(res, "author");
manga.description = MBridge.getMapValue(res, "description");
manga.genre =
MBridge.jsonPathToString(res, r"$.tags[*].name", "._").split("._");
List<String> chapterTitles = [];
List<String> chapterUrls = [];
List<String> chapterDates = [];
if (!useNewQueryEndpoint(manga.source)) {
for (var chapter in json.decode(res)["chapters"]) {
final chapterName = chapter["chapter_name"];
final chapterSlug = chapter["chapter_slug"];
final chapterId = chapter["id"];
final createdAt = chapter["created_at"];
chapterUrls.add("/series/$currentSlug/$chapterSlug#$chapterId");
chapterTitles.add(chapterName);
chapterDates.add(createdAt);
}
} else {
final seasons = json.decode(res)["seasons"].first;
for (var chapter in seasons["chapters"]) {
final chapterName = chapter["chapter_name"];
final chapterSlug = chapter["chapter_slug"];
final chapterId = chapter["id"];
final createdAt = chapter["created_at"];
chapterUrls.add("/series/$currentSlug/$chapterSlug#$chapterId");
chapterTitles.add(chapterName);
chapterDates.add(createdAt);
}
}
if (!useNewQueryEndpoint(manga.source)) {
manga.urls = chapterUrls.reversed.toList();
manga.names = chapterTitles.reversed.toList();
manga.chaptersDateUploads = MBridge.listParseDateTime(
chapterDates, manga.dateFormat, manga.dateFormatLocale)
.reversed
.toList();
} else {
manga.urls = chapterUrls;
manga.names = chapterTitles;
manga.chaptersDateUploads = MBridge.listParseDateTime(
chapterDates, manga.dateFormat, manga.dateFormatLocale);
}
return manga;
}
getChapterPages(MManga manga) async {
MHttpResponse response = MHttpResponse();
final headers = getHeader(manga.baseUrl);
String res = "".toString();
if (!useslugStrategy(manga.source)) {
String chapterId = MBridge.substringAfter(manga.link, '#');
final url = "${manga.apiUrl}/series/chapter/$chapterId";
final data = {"url": url, "headers": headers};
response = await MBridge.http('GET', json.encode(data));
res = response.body;
} else {
final url = "${manga.baseUrl}${manga.link}";
final data = {"url": url, "headers": headers};
response = await MBridge.http('GET', json.encode(data));
if (response.hasError) {
return response;
}
res = response.body;
List<String> pageUrls = [];
var imagesRes = MBridge.querySelectorAll(res,
selector: "div.min-h-screen > div.container > p.items-center",
typeElement: 1,
attributes: "",
typeRegExp: 0);
pageUrls = MBridge.xpath(imagesRes.first, '//img/@src');
pageUrls.addAll(MBridge.xpath(imagesRes.first, '//img/@data-src'));
return pageUrls.where((e) => e.isNotEmpty).toList();
}
if (response.hasError) {
return response;
}
final pages = MBridge.jsonPathToList(res, r"$.content.images[*]", 0);
List<String> pageUrls = [];
for (var u in pages) {
final url = u.replaceAll('"', "");
if (url.startsWith("http")) {
pageUrls.add(url);
} else {
pageUrls.add("${manga.apiUrl}/$url");
}
}
return pageUrls;
}
Map<String, String> getHeader(String url) {
final headers = {
'Origin': url,
'Referer': '$url/',
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json'
};
return headers;
}
bool useNewQueryEndpoint(String sourceName) {
List<String> sources = ["YugenMangas", "Perf Scan", "Reaper Scans"];
return sources.contains(sourceName);
}
bool useslugStrategy(String sourceName) {
List<String> sources = ["YugenMangas", "Reaper Scans", "Perf Scan"];
return sources.contains(sourceName);
}
MManga mMangaRes(MHttpResponse response, MManga manga) {
String res = response.body;
List<String> names = [];
List<String> urls = [];
List<String> images = [];
if (res.startsWith("{")) {
for (var a in json.decode(res)["data"]) {
String thumbnail = a["thumbnail"];
if (thumbnail.startsWith("https://")) {
images.add(thumbnail);
} else {
images.add("${manga.apiUrl}/cover/$thumbnail");
}
names.add(a["title"]);
final seriesSlug = a["series_slug"];
urls.add("/series/$seriesSlug");
}
} else {
for (var a in json.decode(res)) {
String thumbnail = a["thumbnail"];
if (thumbnail.startsWith("https://")) {
images.add(thumbnail);
} else {
images.add("${manga.apiUrl}/cover/$thumbnail");
}
names.add(a["title"]);
final seriesSlug = a["series_slug"];
urls.add("/series/$seriesSlug");
}
manga.hasNextPage = false;
}
manga.urls = urls;
manga.images = images;
manga.names = names;
return manga;
}

View File

@@ -0,0 +1,248 @@
import 'package:mangayomi/bridge_lib.dart';
import 'dart:convert';
class HeanCms extends MSourceProvider {
HeanCms();
@override
Future<MPages> getPopular(MSource sourceInfo, int page) async {
final headers = getHeader(sourceInfo.baseUrl);
String res = "";
if (!useNewQueryEndpoint(sourceInfo.name)) {
final url = "${sourceInfo.apiUrl}/series/querysearch";
final body = {
"page": page,
"order": "desc",
"order_by": "total_views",
"series_status": "Ongoing",
"series_type": "Comic"
};
final data = {"url": url, "headers": headers, "body": body};
res = await MBridge.http('POST', json.encode(data));
} else {
final newEndpointUrl =
"${sourceInfo.apiUrl}/query/?page=$page&query_string=&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));
}
return mMangaRes(res, sourceInfo);
}
@override
Future<MPages> getLatestUpdates(MSource sourceInfo, int page) async {
final headers = getHeader(sourceInfo.baseUrl);
String res = "";
if (!useNewQueryEndpoint(sourceInfo.name)) {
final url = "${sourceInfo.apiUrl}/series/querysearch";
final body = {
"page": page,
"order": "desc",
"order_by": "latest",
"series_status": "Ongoing",
"series_type": "Comic"
};
final data = {"url": url, "headers": headers, "body": body};
res = await MBridge.http('POST', json.encode(data));
} else {
final newEndpointUrl =
"${sourceInfo.apiUrl}/query/?page=$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));
}
return mMangaRes(res, sourceInfo);
}
@override
Future<MPages> search(MSource sourceInfo, String query, int page) async {
final headers = getHeader(sourceInfo.baseUrl);
String res = "";
if (!useNewQueryEndpoint(sourceInfo.source)) {
final url = "${sourceInfo.apiUrl}/series/search";
final body = {"term": query};
final data = {"url": url, "headers": headers, "body": body};
res = await MBridge.http('POST', json.encode(data));
} else {
final newEndpointUrl =
"${sourceInfo.apiUrl}/query/?page=$page&query_string=$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));
}
return mMangaRes(res, sourceInfo);
}
@override
Future<MManga> getDetail(MSource sourceInfo, String url) async {
MManga manga = MManga();
String currentSlug = MBridge.substringAfterLast(url, "/");
final headers = getHeader(sourceInfo.baseUrl);
final data = {
"url": "${sourceInfo.apiUrl}/series/$currentSlug",
"headers": headers
};
final res = await MBridge.http('GET', json.encode(data));
manga.author = MBridge.getMapValue(res, "author");
manga.description = MBridge.getMapValue(res, "description");
manga.genre =
MBridge.jsonPathToString(res, r"$.tags[*].name", "._").split("._");
List<String> chapterTitles = [];
List<String> chapterUrls = [];
List<String> chapterDates = [];
if (!useNewQueryEndpoint(sourceInfo.name)) {
for (var chapter in json.decode(res)["chapters"]) {
final chapterName = chapter["chapter_name"];
final chapterSlug = chapter["chapter_slug"];
final chapterId = chapter["id"];
final createdAt = chapter["created_at"];
chapterUrls.add("/series/$currentSlug/$chapterSlug#$chapterId");
chapterTitles.add(chapterName);
chapterDates.add(createdAt);
}
} else {
final seasons = json.decode(res)["seasons"].first;
for (var chapter in seasons["chapters"]) {
final chapterName = chapter["chapter_name"];
final chapterSlug = chapter["chapter_slug"];
final chapterId = chapter["id"];
final createdAt = chapter["created_at"];
chapterUrls.add("/series/$currentSlug/$chapterSlug#$chapterId");
chapterTitles.add(chapterName);
chapterDates.add(createdAt);
}
}
final dateUploads =
MBridge.parseDates(chapterDates, "dd MMMM yyyy", "fr");
List<MChapter>? chaptersList = [];
for (var i = 0; i < chapterTitles.length; i++) {
MChapter chapter = MChapter();
chapter.name = chapterTitles[i];
chapter.url = chapterUrls[i];
chapter.dateUpload = dateUploads[i];
chaptersList.add(chapter);
}
if (!useNewQueryEndpoint(sourceInfo.name)) {
chaptersList = chaptersList.reversed.toList();
}
manga.chapters = chaptersList;
return manga;
}
@override
Future<List<String>> getPageList(MSource sourceInfo, String url) async {
final headers = getHeader(sourceInfo.baseUrl);
String res = "".toString();
if (!useslugStrategy(sourceInfo.name)) {
String chapterId = MBridge.substringAfter(url, '#');
final data = {
"url": "${sourceInfo.apiUrl}/series/chapter/$chapterId",
"headers": headers
};
res = await MBridge.http('GET', json.encode(data));
} else {
final data = {"url": "${sourceInfo.baseUrl}$url", "headers": headers};
res = await MBridge.http('GET', json.encode(data));
List<String> pageUrls = [];
var imagesRes = MBridge.querySelectorAll(res,
selector: "div.min-h-screen > div.container > p.items-center",
typeElement: 1,
attributes: "",
typeRegExp: 0);
pageUrls = MBridge.xpath(imagesRes.first, '//img/@src');
pageUrls.addAll(MBridge.xpath(imagesRes.first, '//img/@data-src'));
return pageUrls.where((e) => e.isNotEmpty).toList();
}
final pages = MBridge.jsonPathToList(res, r"$.content.images[*]", 0);
List<String> pageUrls = [];
for (var u in pages) {
final url = u.replaceAll('"', "");
if (url.startsWith("http")) {
pageUrls.add(url);
} else {
pageUrls.add("${sourceInfo.apiUrl}/$url");
}
}
return pageUrls;
}
MPages mMangaRes(String res, MSource sourceInfo) {
bool hasNextPage = true;
List<MManga> mangaList = [];
List<String> names = [];
List<String> urls = [];
List<String> images = [];
if (res.startsWith("{")) {
for (var a in json.decode(res)["data"]) {
String thumbnail = a["thumbnail"];
if (thumbnail.startsWith("https://")) {
images.add(thumbnail);
} else {
images.add("${sourceInfo.apiUrl}/cover/$thumbnail");
}
names.add(a["title"]);
final seriesSlug = a["series_slug"];
urls.add("/series/$seriesSlug");
}
} else {
for (var a in json.decode(res)) {
String thumbnail = a["thumbnail"];
if (thumbnail.startsWith("https://")) {
images.add(thumbnail);
} else {
images.add("${sourceInfo.apiUrl}/cover/$thumbnail");
}
names.add(a["title"]);
final seriesSlug = a["series_slug"];
urls.add("/series/$seriesSlug");
}
hasNextPage = false;
}
for (var i = 0; i < names.length; i++) {
MManga manga = MManga();
manga.name = names[i];
manga.imageUrl = images[i];
manga.link = urls[i];
mangaList.add(manga);
}
return MPages(mangaList, hasNextPage);
}
Map<String, String> getHeader(String url) {
final headers = {
'Origin': url,
'Referer': '$url/',
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json'
};
return headers;
}
bool useNewQueryEndpoint(String sourceName) {
List<String> sources = ["YugenMangas", "Perf Scan", "Reaper Scans"];
return sources.contains(sourceName);
}
bool useslugStrategy(String sourceName) {
List<String> sources = ["YugenMangas", "Reaper Scans", "Perf Scan"];
return sources.contains(sourceName);
}
@override
Future<List<MVideo>> getVideoList(MSource sourceInfo, String url) async {
return [];
}
}
HeanCms main() {
return HeanCms();
}

View File

@@ -1,7 +1,7 @@
import '../../../model/source.dart';
import '../../../utils/utils.dart';
const heancmsVersion = "0.0.3";
const heancmsVersion = "0.0.35";
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,289 +0,0 @@
import 'dart:convert';
import 'package:bridge_lib/bridge_lib.dart';
getPopularManga(MManga manga) async {
final url = "${manga.baseUrl}/manga/page/${manga.page}/?m_orderby=views";
final data = {"url": url, "sourceId": manga.sourceId};
final response = await MBridge.http('GET', json.encode(data));
if (response.hasError) {
return response;
}
String res = response.body;
manga.urls = MBridge.xpath(res, '//*[@class^="post-title"]/h3/a/@href');
var images = MBridge.xpath(res, '//*[@id^="manga-item"]/a/img/@data-src');
if (images.isEmpty) {
images = MBridge.xpath(res, '//*[@id^="manga-item"]/a/img/@data-lazy-src');
if (images.isEmpty) {
images = MBridge.xpath(res, '//*[@id^="manga-item"]/a/img/@srcset');
if (images.isEmpty) {
images = MBridge.xpath(res, '//*[@id^="manga-item"]/a/img/@src');
}
}
}
manga.images = images;
manga.names = MBridge.xpath(res, '//*[@id^="manga-item"]/a/@title');
return manga;
}
getMangaDetail(MManga manga) async {
final statusList = [
{
"OnGoing": 0,
"Продолжается": 0,
"Updating": 0,
"Em Lançamento": 0,
"Em lançamento": 0,
"Em andamento": 0,
"Em Andamento": 0,
"En cours": 0,
"Ativo": 0,
"Lançando": 0,
"Đang Tiến Hành": 0,
"Devam Ediyor": 0,
"Devam ediyor": 0,
"In Corso": 0,
"In Arrivo": 0,
"مستمرة": 0,
"مستمر": 0,
"En Curso": 0,
"En curso": 0,
"Emision": 0,
"En marcha": 0,
"Publicandose": 0,
"En emision": 0,
"连载中": 0,
"Completed": 1,
"Completo": 1,
"Completado": 1,
"Concluído": 1,
"Concluido": 1,
"Finalizado": 1,
"Terminé": 1,
"Hoàn Thành": 1,
"مكتملة": 1,
"مكتمل": 1,
"已完结": 1,
"On Hold": 2,
"Pausado": 2,
"En espera": 2,
"Canceled": 3,
"Cancelado": 3,
}
];
MHttpResponse response = MHttpResponse();
final datas = {"url": manga.link, "sourceId": manga.sourceId};
response = await MBridge.http('GET', json.encode(datas));
if (response.hasError) {
return response;
}
String res = response.body;
manga.author = MBridge.querySelectorAll(res,
selector: "div.author-content > a",
typeElement: 0,
attributes: "",
typeRegExp: 0)
.first;
manga.description = MBridge.querySelectorAll(res,
selector:
"div.description-summary div.summary__content, div.summary_content div.post-content_item > h5 + div, div.summary_content div.manga-excerpt, div.sinopsis div.contenedor, .description-summary > p",
typeElement: 0,
attributes: "",
typeRegExp: 0)
.first;
manga.imageUrl = MBridge.querySelectorAll(res,
selector: "div.summary_image img",
typeElement: 2,
attributes: "",
typeRegExp: 2)
.first;
final mangaId = MBridge.querySelectorAll(res,
selector: "div[id^=manga-chapters-holder]",
typeElement: 3,
attributes: "data-id",
typeRegExp: 0)
.first;
manga.status = MBridge.parseStatus(
MBridge.querySelectorAll(res,
selector: "div.summary-content",
typeElement: 0,
attributes: "",
typeRegExp: 0)
.last,
statusList);
manga.genre = MBridge.querySelectorAll(res,
selector: "div.genres-content a",
typeElement: 0,
attributes: "",
typeRegExp: 0);
final baseUrl = "${manga.baseUrl}/";
final headers = {
"Referer": baseUrl,
"Content-Type": "application/x-www-form-urlencoded",
"X-Requested-With": "XMLHttpRequest"
};
final url =
"${baseUrl}wp-admin/admin-ajax.php?action=manga_get_chapters&manga=$mangaId";
final datasP = {"url": url, "headers": headers, "sourceId": manga.sourceId};
response = await MBridge.http('POST', json.encode(datasP));
if (response.statusCode != 200) {
final urlP = "${manga.link}ajax/chapters";
final datasP = {
"url": urlP,
"headers": headers,
"sourceId": manga.sourceId
};
response = await MBridge.http('POST', json.encode(datasP));
}
String resP = response.body;
manga.urls = MBridge.xpath(resP, "//li/a/@href");
var chaptersNames = MBridge.xpath(resP, "//li/a/text()");
var dateF = MBridge.xpath(resP, "//li/span/i/text()");
if (dateF.isEmpty) {
final resWebview = await MBridge.getHtmlViaWebview(manga.link,
"//*[@id='manga-chapters-holder']/div[2]/div/ul/li/a/@href");
manga.urls = MBridge.xpath(resWebview,
"//*[@id='manga-chapters-holder']/div[2]/div/ul/li/a/@href");
chaptersNames = MBridge.xpath(resWebview,
"//*[@id='manga-chapters-holder']/div[2]/div/ul/li/a/text()");
dateF = MBridge.xpath(resWebview,
"//*[@id='manga-chapters-holder']/div[2]/div/ul/li/span/i/text()");
}
manga.names = chaptersNames;
if (dateF.length == chaptersNames.length) {
manga.chaptersDateUploads = MBridge.listParseDateTime(
dateF, manga.dateFormat, manga.dateFormatLocale);
} else if (dateF.length < chaptersNames.length) {
final length = chaptersNames.length - dateF.length;
String date = "${DateTime.now().millisecondsSinceEpoch}";
for (var i = 0; i < length - 1; i++) {
date += "--..${DateTime.now().millisecondsSinceEpoch}";
}
final dateFF = MBridge.listParseDateTime(
dateF, manga.dateFormat, manga.dateFormatLocale);
List<String> chapterDate = date.split('--..');
for (var date in dateFF) {
chapterDate.add(date);
}
manga.chaptersDateUploads = chapterDate;
}
return manga;
}
getChapterPages(MManga manga) async {
final datas = {"url": manga.link, "sourceId": manga.sourceId};
final response = await MBridge.http('GET', json.encode(datas));
if (response.hasError) {
return response;
}
String res = response.body;
final pagesSelectorRes = MBridge.querySelectorAll(res,
selector:
"div.page-break, li.blocks-gallery-item, .reading-content, .text-left img",
typeElement: 1,
attributes: "",
typeRegExp: 0)
.first;
final imgs = MBridge.querySelectorAll(pagesSelectorRes,
selector: "img", typeElement: 2, attributes: "", typeRegExp: 2);
var pageUrls = [];
if (imgs.length == 1) {
final pages = MBridge.querySelectorAll(res,
selector: "#single-pager",
typeElement: 2,
attributes: "",
typeRegExp: 0)
.first;
final pagesNumber = MBridge.querySelectorAll(pages,
selector: "option", typeElement: 2, attributes: "", typeRegExp: 0);
for (var i = 0; i < pagesNumber.length; i++) {
final val = i + 1;
if (i.toString().length == 1) {
pageUrls.add(MBridge.querySelectorAll(pagesSelectorRes,
selector: "img", typeElement: 2, attributes: "", typeRegExp: 2)
.first
.replaceAll("01", '0$val'));
} else {
pageUrls.add(MBridge.querySelectorAll(pagesSelectorRes,
selector: "img", typeElement: 2, attributes: "", typeRegExp: 2)
.first
.replaceAll("01", val.toString()));
}
}
} else {
return imgs;
}
return pageUrls;
}
getLatestUpdatesManga(MManga manga) async {
final url = "${manga.baseUrl}/manga/page/${manga.page}/?m_orderby=latest";
final datas = {"url": url, "sourceId": manga.sourceId};
final response = await MBridge.http('GET', json.encode(datas));
if (response.hasError) {
return response;
}
String res = response.body;
manga.urls = MBridge.xpath(res, '//*[@class^="post-title"]/h3/a/@href');
var images = MBridge.xpath(res, '//*[@id^="manga-item"]/a/img/@data-src');
if (images.isEmpty) {
images = MBridge.xpath(res, '//*[@id^="manga-item"]/a/img/@data-lazy-src');
if (images.isEmpty) {
images = MBridge.xpath(res, '//*[@id^="manga-item"]/a/img/@srcset');
if (images.isEmpty) {
images = MBridge.xpath(res, '//*[@id^="manga-item"]/a/img/@src');
}
}
}
manga.images = images;
manga.names = MBridge.xpath(res, '//*[@id^="manga-item"]/a/@title');
return manga;
}
searchManga(MManga manga) async {
final urll = "${manga.baseUrl}/?s=${manga.query}&post_type=wp-manga";
final datas = {"url": urll, "sourceId": manga.sourceId};
final response = await MBridge.http('GET', json.encode(datas));
if (response.hasError) {
return response;
}
String res = response.body;
manga.urls =
MBridge.xpath(res, '//*[@class^="tab-thumb c-image-hover"]/a/@href');
var images = MBridge.xpath(
res, '//*[@class^="tab-thumb c-image-hover"]/a/img/@data-src');
if (images.isEmpty) {
images = MBridge.xpath(
res, '//*[@class^="tab-thumb c-image-hover"]/a/img/@data-lazy-src');
if (images.isEmpty) {
images = MBridge.xpath(
res, '//*[@class^="tab-thumb c-image-hover"]/a/img/@srcset');
if (images.isEmpty) {
images = MBridge.xpath(
res, '//*[@class^="tab-thumb c-image-hover"]/a/img/@src');
}
}
}
manga.images = images;
manga.names =
MBridge.xpath(res, '//*[@class^="tab-thumb c-image-hover"]/a/@title');
return manga;
}
Map<String, String> getHeader(String url) {
final headers = {
"Referer": "$url/",
};
return headers;
}

View File

@@ -0,0 +1,326 @@
import 'package:mangayomi/bridge_lib.dart';
import 'dart:convert';
class Madara extends MSourceProvider {
Madara();
@override
Future<MPages> getPopular(MSource sourceInfo, int page) async {
final url = "${sourceInfo.baseUrl}/manga/page/$page/?m_orderby=views";
final data = {"url": url, "sourceId": sourceInfo.id};
final res = await MBridge.http('GET', json.encode(data));
List<MManga> mangaList = [];
final urls = MBridge.xpath(res, '//*[@class^="post-title"]/h3/a/@href');
final names = MBridge.xpath(res, '//*[@id^="manga-item"]/a/@title');
var images = MBridge.xpath(res, '//*[@id^="manga-item"]/a/img/@data-src');
if (images.isEmpty) {
images =
MBridge.xpath(res, '//*[@id^="manga-item"]/a/img/@data-lazy-src');
if (images.isEmpty) {
images = MBridge.xpath(res, '//*[@id^="manga-item"]/a/img/@srcset');
if (images.isEmpty) {
images = MBridge.xpath(res, '//*[@id^="manga-item"]/a/img/@src');
}
}
}
for (var i = 0; i < names.length; i++) {
MManga manga = MManga();
manga.name = names[i];
manga.imageUrl = images[i];
manga.link = urls[i];
mangaList.add(manga);
}
return MPages(mangaList, true);
}
@override
Future<MPages> getLatestUpdates(MSource sourceInfo, int page) async {
final url = "${sourceInfo.baseUrl}/manga/page/$page/?m_orderby=latest";
final data = {"url": url, "sourceId": sourceInfo.id};
final res = await MBridge.http('GET', json.encode(data));
List<MManga> mangaList = [];
final urls = MBridge.xpath(res, '//*[@class^="post-title"]/h3/a/@href');
final names = MBridge.xpath(res, '//*[@id^="manga-item"]/a/@title');
var images = MBridge.xpath(res, '//*[@id^="manga-item"]/a/img/@data-src');
if (images.isEmpty) {
images =
MBridge.xpath(res, '//*[@id^="manga-item"]/a/img/@data-lazy-src');
if (images.isEmpty) {
images = MBridge.xpath(res, '//*[@id^="manga-item"]/a/img/@srcset');
if (images.isEmpty) {
images = MBridge.xpath(res, '//*[@id^="manga-item"]/a/img/@src');
}
}
}
for (var i = 0; i < names.length; i++) {
MManga manga = MManga();
manga.name = names[i];
manga.imageUrl = images[i];
manga.link = urls[i];
mangaList.add(manga);
}
return MPages(mangaList, true);
}
@override
Future<MPages> search(MSource sourceInfo, String query, int page) async {
final data = {
"url": "${sourceInfo.baseUrl}/?s=$query&post_type=wp-manga",
"sourceId": sourceInfo.id
};
final res = await MBridge.http('GET', json.encode(data));
List<MManga> mangaList = [];
final urls =
MBridge.xpath(res, '//*[@class^="tab-thumb c-image-hover"]/a/@href');
final names =
MBridge.xpath(res, '//*[@class^="tab-thumb c-image-hover"]/a/@title');
var images = MBridge.xpath(
res, '//*[@class^="tab-thumb c-image-hover"]/a/img/@data-src');
if (images.isEmpty) {
images = MBridge.xpath(
res, '//*[@class^="tab-thumb c-image-hover"]/a/img/@data-lazy-src');
if (images.isEmpty) {
images = MBridge.xpath(
res, '//*[@class^="tab-thumb c-image-hover"]/a/img/@srcset');
if (images.isEmpty) {
images = MBridge.xpath(
res, '//*[@class^="tab-thumb c-image-hover"]/a/img/@src');
}
}
}
for (var i = 0; i < names.length; i++) {
MManga manga = MManga();
manga.name = names[i];
manga.imageUrl = images[i];
manga.link = urls[i];
mangaList.add(manga);
}
return MPages(mangaList, true);
}
@override
Future<MManga> getDetail(MSource sourceInfo, String url) async {
final statusList = [
{
"OnGoing": 0,
"Продолжается": 0,
"Updating": 0,
"Em Lançamento": 0,
"Em lançamento": 0,
"Em andamento": 0,
"Em Andamento": 0,
"En cours": 0,
"Ativo": 0,
"Lançando": 0,
"Đang Tiến Hành": 0,
"Devam Ediyor": 0,
"Devam ediyor": 0,
"In Corso": 0,
"In Arrivo": 0,
"مستمرة": 0,
"مستمر": 0,
"En Curso": 0,
"En curso": 0,
"Emision": 0,
"En marcha": 0,
"Publicandose": 0,
"En emision": 0,
"连载中": 0,
"Completed": 1,
"Completo": 1,
"Completado": 1,
"Concluído": 1,
"Concluido": 1,
"Finalizado": 1,
"Terminé": 1,
"Hoàn Thành": 1,
"مكتملة": 1,
"مكتمل": 1,
"已完结": 1,
"On Hold": 2,
"Pausado": 2,
"En espera": 2,
"Canceled": 3,
"Cancelado": 3,
}
];
MManga manga = MManga();
String res = "";
final datas = {"url": url, "sourceId": sourceInfo.id};
res = await MBridge.http('GET', json.encode(datas));
manga.author = MBridge.querySelectorAll(res,
selector: "div.author-content > a",
typeElement: 0,
attributes: "",
typeRegExp: 0)
.first;
manga.description = MBridge.querySelectorAll(res,
selector:
"div.description-summary div.summary__content, div.summary_content div.post-content_item > h5 + div, div.summary_content div.manga-excerpt, div.sinopsis div.contenedor, .description-summary > p",
typeElement: 0,
attributes: "",
typeRegExp: 0)
.first;
manga.imageUrl = MBridge.querySelectorAll(res,
selector: "div.summary_image img",
typeElement: 2,
attributes: "",
typeRegExp: 2)
.first;
final mangaId = MBridge.querySelectorAll(res,
selector: "div[id^=manga-chapters-holder]",
typeElement: 3,
attributes: "data-id",
typeRegExp: 0)
.first;
manga.status = MBridge.parseStatus(
MBridge.querySelectorAll(res,
selector: "div.summary-content",
typeElement: 0,
attributes: "",
typeRegExp: 0)
.last,
statusList);
manga.genre = MBridge.querySelectorAll(res,
selector: "div.genres-content a",
typeElement: 0,
attributes: "",
typeRegExp: 0);
final baseUrl = "${sourceInfo.baseUrl}/";
final headers = {
"Referer": baseUrl,
"Content-Type": "application/x-www-form-urlencoded",
"X-Requested-With": "XMLHttpRequest"
};
final urll =
"${baseUrl}wp-admin/admin-ajax.php?action=manga_get_chapters&manga=$mangaId";
final datasP = {"url": urll, "headers": headers, "sourceId": sourceInfo.id};
res = await MBridge.http('POST', json.encode(datasP));
if (res == "400") {
final urlP = "${url}ajax/chapters";
final datasP = {
"url": urlP,
"headers": headers,
"sourceId": sourceInfo.id
};
res = await MBridge.http('POST', json.encode(datasP));
}
var chapUrls = MBridge.xpath(res, "//li/a/@href");
var chaptersNames = MBridge.xpath(res, "//li/a/text()");
var dateF = MBridge.xpath(res, "//li/span/i/text()");
if (dateF.isEmpty) {
final resWebview = await MBridge.getHtmlViaWebview(
url, "//*[@id='manga-chapters-holder']/div[2]/div/ul/li/a/@href");
chapUrls = MBridge.xpath(resWebview,
"//*[@id='manga-chapters-holder']/div[2]/div/ul/li/a/@href");
chaptersNames = MBridge.xpath(resWebview,
"//*[@id='manga-chapters-holder']/div[2]/div/ul/li/a/text()");
dateF = MBridge.xpath(resWebview,
"//*[@id='manga-chapters-holder']/div[2]/div/ul/li/span/i/text()");
}
var dateUploads = MBridge.parseDates(
dateF, sourceInfo.dateFormat, sourceInfo.dateFormatLocale);
if (dateF.length < chaptersNames.length) {
final length = chaptersNames.length - dateF.length;
String date = "${DateTime.now().millisecondsSinceEpoch}";
for (var i = 0; i < length - 1; i++) {
date += "--..${DateTime.now().millisecondsSinceEpoch}";
}
final dateFF = MBridge.parseDates(
dateF, sourceInfo.dateFormat, sourceInfo.dateFormatLocale);
List<String> chapterDate = date.split('--..');
for (var date in dateFF) {
chapterDate.add(date);
}
dateUploads = chapterDate;
}
List<MChapter>? chaptersList = [];
for (var i = 0; i < chaptersNames.length; i++) {
MChapter chapter = MChapter();
chapter.name = chaptersNames[i];
chapter.url = chapUrls[i];
chapter.dateUpload = dateUploads[i];
chaptersList.add(chapter);
}
manga.chapters = chaptersList;
return manga;
}
@override
Future<List<String>> getPageList(MSource sourceInfo, String url) async {
final datas = {"url": url, "sourceId": sourceInfo.id};
final res = await MBridge.http('GET', json.encode(datas));
final pagesSelectorRes = MBridge.querySelectorAll(res,
selector:
"div.page-break, li.blocks-gallery-item, .reading-content, .text-left img",
typeElement: 1,
attributes: "",
typeRegExp: 0)
.first;
final imgs = MBridge.querySelectorAll(pagesSelectorRes,
selector: "img", typeElement: 2, attributes: "", typeRegExp: 2);
var pageUrls = [];
if (imgs.length == 1) {
final pages = MBridge.querySelectorAll(res,
selector: "#single-pager",
typeElement: 2,
attributes: "",
typeRegExp: 0)
.first;
final pagesNumber = MBridge.querySelectorAll(pages,
selector: "option", typeElement: 2, attributes: "", typeRegExp: 0);
for (var i = 0; i < pagesNumber.length; i++) {
final val = i + 1;
if (i.toString().length == 1) {
pageUrls.add(MBridge.querySelectorAll(pagesSelectorRes,
selector: "img",
typeElement: 2,
attributes: "",
typeRegExp: 2)
.first
.replaceAll("01", '0$val'));
} else {
pageUrls.add(MBridge.querySelectorAll(pagesSelectorRes,
selector: "img",
typeElement: 2,
attributes: "",
typeRegExp: 2)
.first
.replaceAll("01", val.toString()));
}
}
} else {
return imgs;
}
return pageUrls;
}
@override
Future<List<MVideo>> getVideoList(MSource sourceInfo, String url) async {
return [];
}
}
Madara main() {
return Madara();
}

View File

@@ -1,7 +1,7 @@
import '../../../model/source.dart';
import '../../../utils/utils.dart';
const madaraVersion = "0.0.3";
const madaraVersion = "0.0.35";
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,193 +0,0 @@
import 'dart:convert';
import 'package:bridge_lib/bridge_lib.dart';
getPopularManga(MManga manga) async {
final url =
"${manga.baseUrl}${getMangaUrlDirectory(manga.source)}/?page=${manga.page}&order=popular";
final data = {"url": url, "sourceId": manga.sourceId};
final response = await MBridge.http('GET', json.encode(data));
if (response.hasError) {
return response;
}
String res = response.body;
manga.urls =
MBridge.xpath(res, '//*[ @class="imgu" or @class="bsx"]/a/@href');
manga.names =
MBridge.xpath(res, '//*[ @class="imgu" or @class="bsx"]/a/@title');
manga.images = MBridge.xpath(
res, '//*[ @class="imgu" or @class="bsx"]/a/div[1]/img/@src');
return manga;
}
getLatestUpdatesManga(MManga manga) async {
final url =
"${manga.baseUrl}${getMangaUrlDirectory(manga.source)}/?page=${manga.page}&order=update";
final data = {"url": url, "sourceId": manga.sourceId};
final response = await MBridge.http('GET', json.encode(data));
if (response.hasError) {
return response;
}
String res = response.body;
manga.urls =
MBridge.xpath(res, '//*[ @class="imgu" or @class="bsx"]/a/@href');
manga.names =
MBridge.xpath(res, '//*[ @class="imgu" or @class="bsx"]/a/@title');
manga.images = MBridge.xpath(
res, '//*[ @class="imgu" or @class="bsx"]/a/div[1]/img/@src');
return manga;
}
getMangaDetail(MManga manga) async {
final statusList = [
{
"مستمرة": 0,
"En curso": 0,
"Ongoing": 0,
"On going": 0,
"Ativo": 0,
"En Cours": 0,
"Berjalan": 0,
"Продолжается": 0,
"Updating": 0,
"Lançando": 0,
"In Arrivo": 0,
"OnGoing": 0,
"Đang tiến hành": 0,
"em lançamento": 0,
"Онгоінг": 0,
"Publishing": 0,
"Curso": 0,
"En marcha": 0,
"Publicandose": 0,
"连载中": 0,
"Devam Ediyor": 0,
"Em Andamento": 0,
"In Corso": 0,
"Güncel": 0,
"Emision": 0,
"En emision": 0,
"مستمر": 0,
"Đã hoàn thành": 1,
"مكتملة": 1,
"Завершено": 1,
"Complété": 1,
"Fini": 1,
"Terminé": 1,
"Tamamlandı": 1,
"Tamat": 1,
"Completado": 1,
"Concluído": 1,
"Finished": 1,
"Completed": 1,
"Completo": 1,
"Concluido": 1,
"已完结": 1,
"Finalizado": 1,
"Completata": 1,
"One-Shot": 1,
"Bitti": 1,
"hiatus": 2,
}
];
final datas = {"url": manga.link, "sourceId": manga.sourceId};
final response = await MBridge.http('GET', json.encode(datas));
if (response.hasError) {
return response;
}
String res = response.body;
manga.author = MBridge.xpath(
res,
'//*[@class="imptdt" and contains(text(), "Author") or @class="infotable" and contains(text(), "Author") or @class="infotable" and contains(text(), "Auteur") or @class="fmed" and contains(text(), "Auteur") or @class="infotable" and contains(text(), "Autor")]/text()',
'')
.first
.replaceAll("Autor", "")
.replaceAll("Author", "")
.replaceAll("Auteur", "")
.replaceAll("[Add, ]", "");
manga.description = MBridge.querySelectorAll(res,
selector: ".desc, .entry-content[itemprop=description]",
typeElement: 0,
attributes: "",
typeRegExp: 0)
.first;
final status = MBridge.xpath(
res,
'//*[@class="imptdt" and contains(text(), "Status") or @class="imptdt" and contains(text(), "Estado") or @class="infotable" and contains(text(), "Status") or @class="infotable" and contains(text(), "Statut") or @class="imptdt" and contains(text(), "Statut")]/text()',
'')
.first
.replaceAll("Status", "")
.replaceAll("Estado", "")
.replaceAll("Statut", "");
manga.status = MBridge.parseStatus(status, statusList);
manga.genre = MBridge.xpath(res,
'//*[@class="gnr" or @class="mgen" or @class="seriestugenre" ]/a/text()');
manga.urls = MBridge.xpath(res,
'//*[@class="bxcl" or @class="cl" or @class="chbox" or @class="eph-num" or @id="chapterlist"]/div/a[not(@href="#/chapter-{{number}}")]/@href');
manga.names = MBridge.xpath(res,
'//*[@class="bxcl" or @class="cl" or @class="chbox" or @class="eph-num" or @id="chapterlist"]/div/a/span[@class="chapternum" and not(text()="Chapter {{number}}") or @class="lch" and not(text()="Chapter {{number}}")]/text()');
final chaptersDateUploads = MBridge.xpath(res,
'//*[@class="bxcl" or @class="cl" or @class="chbox" or @class="eph-num" or @id="chapterlist"]/div/a/span[@class="chapterdate" and not(text()="{{date}}")]/text()');
manga.chaptersDateUploads = MBridge.listParseDateTime(
chaptersDateUploads, manga.dateFormat, manga.dateFormatLocale);
return manga;
}
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 response = await MBridge.http('GET', json.encode(data));
if (response.hasError) {
return response;
}
String res = response.body;
manga.urls =
MBridge.xpath(res, '//*[ @class="imgu" or @class="bsx"]/a/@href');
manga.names =
MBridge.xpath(res, '//*[ @class="imgu" or @class="bsx"]/a/@title');
manga.images = MBridge.xpath(
res, '//*[ @class="imgu" or @class="bsx"]/a/div[1]/img/@src');
return manga;
}
getChapterPages(MManga manga) async {
final datas = {"url": manga.link, "sourceId": manga.sourceId};
final response = await MBridge.http('GET', json.encode(datas));
if (response.hasError) {
return response;
}
String res = response.body;
var pages = [];
List<String> pagesUrl = [];
pages = MBridge.xpath(res, '//*[@id="readerarea"]/p/img/@src');
if (pages.isEmpty || pages.length == 1) {
pages = MBridge.xpath(res, '//*[@id="readerarea"]/img/@src');
}
if (pages.isEmpty || pages.length == 1) {
final images =
MBridge.regExp(res, "\"images\"\\s*:\\s*(\\[.*?])", "", 1, 1);
final pages = MBridge.jsonDecodeToList(images, 0);
for (var page in pages) {
pagesUrl.add(page);
}
} else {
return pages;
}
return pagesUrl;
}
String getMangaUrlDirectory(String sourceName) {
if (sourceName == "Sushi-Scan") {
return "/catalogue";
}
return "/manga";
}

View File

@@ -0,0 +1,208 @@
import 'package:mangayomi/bridge_lib.dart';
import 'dart:convert';
class MangaReader extends MSourceProvider {
MangaReader();
@override
Future<MPages> getPopular(MSource sourceInfo, int page) async {
final url =
"${sourceInfo.baseUrl}${getMangaUrlDirectory(sourceInfo.name)}/?page=$page&order=popular";
final data = {"url": url, "sourceId": sourceInfo.id};
final res = await MBridge.http('GET', json.encode(data));
return mangaRes(res);
}
@override
Future<MPages> getLatestUpdates(MSource sourceInfo, int page) async {
final url =
"${sourceInfo.baseUrl}${getMangaUrlDirectory(sourceInfo.name)}/?page=$page&order=update";
final data = {"url": url, "sourceId": sourceInfo.id};
final res = await MBridge.http('GET', json.encode(data));
return mangaRes(res);
}
@override
Future<MPages> search(MSource sourceInfo, String query, int page) async {
final url =
"${sourceInfo.baseUrl}${getMangaUrlDirectory(sourceInfo.name)}/?&title=$query&page=$page";
final data = {"url": url, "sourceId": sourceInfo.id};
final res = await MBridge.http('GET', json.encode(data));
return mangaRes(res);
}
@override
Future<MManga> getDetail(MSource sourceInfo, String url) async {
final statusList = [
{
"مستمرة": 0,
"En curso": 0,
"Ongoing": 0,
"On going": 0,
"Ativo": 0,
"En Cours": 0,
"Berjalan": 0,
"Продолжается": 0,
"Updating": 0,
"Lançando": 0,
"In Arrivo": 0,
"OnGoing": 0,
"Đang tiến hành": 0,
"em lançamento": 0,
"Онгоінг": 0,
"Publishing": 0,
"Curso": 0,
"En marcha": 0,
"Publicandose": 0,
"连载中": 0,
"Devam Ediyor": 0,
"Em Andamento": 0,
"In Corso": 0,
"Güncel": 0,
"Emision": 0,
"En emision": 0,
"مستمر": 0,
"Đã hoàn thành": 1,
"مكتملة": 1,
"Завершено": 1,
"Complété": 1,
"Fini": 1,
"Terminé": 1,
"Tamamlandı": 1,
"Tamat": 1,
"Completado": 1,
"Concluído": 1,
"Finished": 1,
"Completed": 1,
"Completo": 1,
"Concluido": 1,
"已完结": 1,
"Finalizado": 1,
"Completata": 1,
"One-Shot": 1,
"Bitti": 1,
"hiatus": 2,
}
];
MManga manga = MManga();
final datas = {"url": url, "sourceId": sourceInfo.id};
final res = await MBridge.http('GET', json.encode(datas));
manga.author = MBridge.xpath(
res,
'//*[@class="imptdt" and contains(text(), "Author") or @class="infotable" and contains(text(), "Author") or @class="infotable" and contains(text(), "Auteur") or @class="fmed" and contains(text(), "Auteur") or @class="infotable" and contains(text(), "Autor")]/text()',
'')
.first
.replaceAll("Autor", "")
.replaceAll("Author", "")
.replaceAll("Auteur", "")
.replaceAll("[Add, ]", "");
manga.description = MBridge.querySelectorAll(res,
selector: ".desc, .entry-content[itemprop=description]",
typeElement: 0,
attributes: "",
typeRegExp: 0)
.first;
final status = MBridge.xpath(
res,
'//*[@class="imptdt" and contains(text(), "Status") or @class="imptdt" and contains(text(), "Estado") or @class="infotable" and contains(text(), "Status") or @class="infotable" and contains(text(), "Statut") or @class="imptdt" and contains(text(), "Statut")]/text()',
'')
.first
.replaceAll("Status", "")
.replaceAll("Estado", "")
.replaceAll("Statut", "");
manga.status = MBridge.parseStatus(status, statusList);
manga.genre = MBridge.xpath(res,
'//*[@class="gnr" or @class="mgen" or @class="seriestugenre" ]/a/text()');
var chapUrls = MBridge.xpath(res,
'//*[@class="bxcl" or @class="cl" or @class="chbox" or @class="eph-num" or @id="chapterlist"]/div/a[not(@href="#/chapter-{{number}}")]/@href');
var chaptersNames = MBridge.xpath(res,
'//*[@class="bxcl" or @class="cl" or @class="chbox" or @class="eph-num" or @id="chapterlist"]/div/a/span[@class="chapternum" and not(text()="Chapter {{number}}") or @class="lch" and not(text()="Chapter {{number}}")]/text()');
var chapterDates = MBridge.xpath(res,
'//*[@class="bxcl" or @class="cl" or @class="chbox" or @class="eph-num" or @id="chapterlist"]/div/a/span[@class="chapterdate" and not(text()="{{date}}")]/text()');
var dateUploads = MBridge.parseDates(
chapterDates, sourceInfo.dateFormat, sourceInfo.dateFormatLocale);
List<MChapter>? chaptersList = [];
for (var i = 0; i < chaptersNames.length; i++) {
MChapter chapter = MChapter();
chapter.name = chaptersNames[i];
chapter.url = chapUrls[i];
chapter.dateUpload = dateUploads[i];
chaptersList.add(chapter);
}
manga.chapters = chaptersList;
return manga;
}
@override
Future<List<String>> getPageList(MSource sourceInfo, String url) async {
final datas = {"url": url, "sourceId": sourceInfo.id};
final res = await MBridge.http('GET', json.encode(datas));
List<String> pages = [];
List<String> pagesUrl = [];
pages = MBridge.xpath(res, '//*[@id="readerarea"]/p/img/@src');
if (pages.isEmpty || pages.length == 1) {
pages = MBridge.xpath(res, '//*[@id="readerarea"]/img/@src');
}
if (pages.isEmpty || pages.length == 1) {
final images =
MBridge.regExp(res, "\"images\"\\s*:\\s*(\\[.*?])", "", 1, 1);
final pages = MBridge.jsonDecodeToList(images, 0);
for (var page in pages) {
pagesUrl.add(page);
}
} else {
return pages;
}
return pagesUrl;
}
MPages mangaRes(String res) {
List<MManga> mangaList = [];
final urls =
MBridge.xpath(res, '//*[ @class="imgu" or @class="bsx"]/a/@href');
final names =
MBridge.xpath(res, '//*[ @class="imgu" or @class="bsx"]/a/@title');
final images = MBridge.xpath(
res, '//*[ @class="imgu" or @class="bsx"]/a/div[1]/img/@src');
for (var i = 0; i < names.length; i++) {
MManga manga = MManga();
manga.name = names[i];
manga.imageUrl = images[i];
manga.link = urls[i];
mangaList.add(manga);
}
return MPages(mangaList, true);
}
String getMangaUrlDirectory(String sourceName) {
if (sourceName == "Sushi-Scan") {
return "/catalogue";
}
return "/manga";
}
@override
Future<List<MVideo>> getVideoList(MSource sourceInfo, String url) async {
return [];
}
}
MangaReader main() {
return MangaReader();
}

View File

@@ -1,7 +1,7 @@
import '../../../model/source.dart';
import '../../../utils/utils.dart';
const mangareaderVersion = "0.0.4";
const mangareaderVersion = "0.0.45";
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,155 +0,0 @@
import 'dart:convert';
import 'package:bridge_lib/bridge_lib.dart';
searchManga(MManga manga) async {
final url = "${manga.baseUrl}/search?query=${manga.query}";
final data = {"url": url, "sourceId": manga.sourceId};
final response = await MBridge.http('GET', json.encode(data));
if (response.hasError) {
return response;
}
String res = response.body;
final jsonList = json.decode(res)["suggestions"];
List<String> urls = [];
List<String> names = [];
List<String> images = [];
for (var da in jsonList) {
String value = da["value"];
String data = da["data"];
if (manga.source == 'Scan VF') {
urls.add('${manga.baseUrl}/$data');
} else if (manga.source == 'Manga-FR') {
urls.add('${manga.baseUrl}/lecture-en-ligne/$data');
} else {
urls.add('${manga.baseUrl}/manga/$data');
}
names.add(value);
if (manga.source == "Manga-FR") {
images.add("${manga.baseUrl}/uploads/manga/$data.jpg");
} else {
images
.add("${manga.baseUrl}/uploads/manga/$data/cover/cover_250x350.jpg");
}
}
manga.names = names;
manga.urls = urls;
manga.images = images;
return manga;
}
getPopularManga(MManga manga) async {
final url =
"${manga.baseUrl}/filterList?page=${manga.page}&sortBy=views&asc=false";
final data = {"url": url, "sourceId": manga.sourceId};
final response = await MBridge.http('GET', json.encode(data));
if (response.hasError) {
return response;
}
String res = response.body;
manga.urls = MBridge.xpath(res, '//*[ @class="chart-title"]/@href');
manga.names = MBridge.xpath(res, '//*[ @class="chart-title"]/text()');
List<String> images = [];
for (var url in manga.urls) {
String slug = MBridge.substringAfterLast(url, '/');
if (manga.source == "Manga-FR") {
images.add("${manga.baseUrl}/uploads/manga/${slug}.jpg");
} else {
images.add(
"${manga.baseUrl}/uploads/manga/${slug}/cover/cover_250x350.jpg");
}
}
manga.images = images;
return manga;
}
getMangaDetail(MManga manga) async {
final statusList = [
{
"complete": 1,
"complet": 1,
"completo": 1,
"zakończone": 1,
"concluído": 1,
"مكتملة": 1,
"ongoing": 0,
"en cours": 0,
"em lançamento": 0,
"prace w toku": 0,
"ativo": 0,
"مستمرة": 0,
"em andamento": 0
}
];
final datas = {"url": manga.link, "sourceId": manga.sourceId};
final response = await MBridge.http('GET', json.encode(datas));
if (response.hasError) {
return response;
}
String res = response.body;
manga.author = MBridge.xpath(res,
'//*[@class="dl-horizontal"]/dt[contains(text(), "Auteur(s)") or contains(text(), "Author(s)") or contains(text(), "Autor(es)") or contains(text(), "Yazar(lar) or contains(text(), "Mangaka(lar)")]//following-sibling::dd[1]/text()')
.first;
final status = MBridge.xpath(res,
'//*[@class="dl-horizontal"]/dt[contains(text(), "Statut") or contains(text(), "Status") or contains(text(), "Estado") or contains(text(), "Durum")]/following-sibling::dd[1]/text()')
.first;
manga.status = MBridge.parseStatus(status, statusList);
manga.description =
MBridge.xpath(res, '//*[@class="well" or @class="manga well"]/p/text()')
.first;
manga.genre = MBridge.xpath(res,
'//*[@class="dl-horizontal"]/dt[contains(text(), "Categories") or contains(text(), "Categorias") or contains(text(), "Categorías") or contains(text(), "Catégories") or contains(text(), "Kategoriler" or contains(text(), "Kategorie") or contains(text(), "Kategori") or contains(text(), "Tagi"))]/following-sibling::dd[1]/text()');
manga.names = MBridge.xpath(res, '//*[@class="chapter-title-rtl"]/a/text()');
manga.urls = MBridge.xpath(res, '//*[@class="chapter-title-rtl"]/a/@href');
final date =
MBridge.xpath(res, '//*[@class="date-chapter-title-rtl"]/text()');
manga.chaptersDateUploads =
MBridge.listParseDateTime(date, "d MMM. yyyy", "en_US");
return manga;
}
getLatestUpdatesManga(MManga manga) async {
final url = "${manga.baseUrl}/latest-release?page=${manga.page}";
final data = {"url": url, "sourceId": manga.sourceId};
final response = await MBridge.http('GET', json.encode(data));
if (response.hasError) {
return response;
}
String res = response.body;
manga.urls = MBridge.xpath(res, '//*[@class="manga-item"]/h3/a/@href');
manga.names = MBridge.xpath(res, '//*[@class="manga-item"]/h3/a/text()');
List<String> images = [];
for (var url in manga.urls) {
String slug = MBridge.substringAfterLast(url, '/');
if (manga.source == "Manga-FR") {
images.add("${manga.baseUrl}/uploads/manga/${slug}.jpg");
} else {
images.add(
"${manga.baseUrl}/uploads/manga/${slug}/cover/cover_250x350.jpg");
}
}
manga.images = images;
return manga;
}
getChapterPages(MManga manga) async {
final datas = {"url": manga.link, "sourceId": manga.sourceId};
final response = await MBridge.http('GET', json.encode(datas));
if (response.hasError) {
return response;
}
String res = response.body;
List<String> pagesUrl = [];
final pages = MBridge.xpath(
res, '//*[@id="all"]/img[@class="img-responsive"]/@data-src');
for (var page in pages) {
if (page.startsWith('//')) {
pagesUrl.add(page.replaceAll('//', 'https://'));
} else {
pagesUrl.add(page);
}
}
return pagesUrl;
}

View File

@@ -0,0 +1,203 @@
import 'package:mangayomi/bridge_lib.dart';
import 'dart:convert';
class MMCRCms extends MSourceProvider {
MMCRCms();
@override
Future<MPages> getPopular(MSource sourceInfo, int page) async {
final url =
"${sourceInfo.baseUrl}/filterList?page=$page&sortBy=views&asc=false";
final data = {"url": url, "sourceId": sourceInfo.id};
final res = await MBridge.http('GET', json.encode(data));
List<MManga> mangaList = [];
final urls = MBridge.xpath(res, '//*[ @class="chart-title"]/@href');
final names = MBridge.xpath(res, '//*[ @class="chart-title"]/text()');
List<String> images = [];
for (var url in urls) {
String slug = MBridge.substringAfterLast(url, '/');
if (sourceInfo.name == "Manga-FR") {
images.add("${sourceInfo.baseUrl}/uploads/manga/${slug}.jpg");
} else {
images.add(
"${sourceInfo.baseUrl}/uploads/manga/${slug}/cover/cover_250x350.jpg");
}
}
for (var i = 0; i < names.length; i++) {
MManga manga = MManga();
manga.name = names[i];
manga.imageUrl = images[i];
manga.link = urls[i];
mangaList.add(manga);
}
return MPages(mangaList, true);
}
@override
Future<MPages> getLatestUpdates(MSource sourceInfo, int page) async {
final url = "${sourceInfo.baseUrl}/latest-release?page=$page";
final data = {"url": url, "sourceId": sourceInfo.id};
final res = await MBridge.http('GET', json.encode(data));
List<MManga> mangaList = [];
final urls = MBridge.xpath(res, '//*[@class="manga-item"]/h3/a/@href');
final names = MBridge.xpath(res, '//*[@class="manga-item"]/h3/a/text()');
List<String> images = [];
for (var url in urls) {
String slug = MBridge.substringAfterLast(url, '/');
if (sourceInfo.name == "Manga-FR") {
images.add("${sourceInfo.baseUrl}/uploads/manga/${slug}.jpg");
} else {
images.add(
"${sourceInfo.baseUrl}/uploads/manga/${slug}/cover/cover_250x350.jpg");
}
}
for (var i = 0; i < names.length; i++) {
MManga manga = MManga();
manga.name = names[i];
manga.imageUrl = images[i];
manga.link = urls[i];
mangaList.add(manga);
}
return MPages(mangaList, true);
}
@override
Future<MPages> search(MSource sourceInfo, String query, int page) async {
final url = "${sourceInfo.baseUrl}/search?query=$query";
final data = {"url": url, "sourceId": sourceInfo.id};
final res = await MBridge.http('GET', json.encode(data));
List<MManga> mangaList = [];
final jsonList = json.decode(res)["suggestions"];
List<String> urls = [];
List<String> names = [];
List<String> images = [];
for (var da in jsonList) {
String value = da["value"];
String data = da["data"];
if (sourceInfo.name == 'Scan VF') {
urls.add('${sourceInfo.baseUrl}/$data');
} else if (sourceInfo.name == 'Manga-FR') {
urls.add('${sourceInfo.baseUrl}/lecture-en-ligne/$data');
} else {
urls.add('${sourceInfo.baseUrl}/manga/$data');
}
names.add(value);
if (sourceInfo.name == "Manga-FR") {
images.add("${sourceInfo.baseUrl}/uploads/manga/$data.jpg");
} else {
images.add(
"${sourceInfo.baseUrl}/uploads/manga/$data/cover/cover_250x350.jpg");
}
}
for (var i = 0; i < names.length; i++) {
MManga manga = MManga();
manga.name = names[i];
manga.imageUrl = images[i];
manga.link = urls[i];
mangaList.add(manga);
}
return MPages(mangaList, true);
}
@override
Future<MManga> getDetail(MSource sourceInfo, String url) async {
final statusList = [
{
"complete": 1,
"complet": 1,
"completo": 1,
"zakończone": 1,
"concluído": 1,
"مكتملة": 1,
"ongoing": 0,
"en cours": 0,
"em lançamento": 0,
"prace w toku": 0,
"ativo": 0,
"مستمرة": 0,
"em andamento": 0
}
];
MManga manga = MManga();
final datas = {"url": url, "sourceId": sourceInfo.id};
final res = await MBridge.http('GET', json.encode(datas));
manga.author = MBridge.xpath(res,
'//*[@class="dl-horizontal"]/dt[contains(text(), "Auteur(s)") or contains(text(), "Author(s)") or contains(text(), "Autor(es)") or contains(text(), "Yazar(lar) or contains(text(), "Mangaka(lar)")]//following-sibling::dd[1]/text()')
.first;
final status = MBridge.xpath(res,
'//*[@class="dl-horizontal"]/dt[contains(text(), "Statut") or contains(text(), "Status") or contains(text(), "Estado") or contains(text(), "Durum")]/following-sibling::dd[1]/text()')
.first;
manga.status = MBridge.parseStatus(status, statusList);
manga.description =
MBridge.xpath(res, '//*[@class="well" or @class="manga well"]/p/text()')
.first;
manga.genre = MBridge.xpath(res,
'//*[@class="dl-horizontal"]/dt[contains(text(), "Categories") or contains(text(), "Categorias") or contains(text(), "Categorías") or contains(text(), "Catégories") or contains(text(), "Kategoriler" or contains(text(), "Kategorie") or contains(text(), "Kategori") or contains(text(), "Tagi"))]/following-sibling::dd[1]/text()');
final baseUrl = "${sourceInfo.baseUrl}/";
final headers = {
"Referer": baseUrl,
"Content-Type": "application/x-www-form-urlencoded",
"X-Requested-With": "XMLHttpRequest"
};
var chapUrls =
MBridge.xpath(res, '//*[@class="chapter-title-rtl"]/a/@href');
var chaptersNames =
MBridge.xpath(res, '//*[@class="chapter-title-rtl"]/a/text()');
var chaptersDates =
MBridge.xpath(res, '//*[@class="date-chapter-title-rtl"]/text()');
var dateUploads = MBridge.parseDates(
chaptersDates, sourceInfo.dateFormat, sourceInfo.dateFormatLocale);
List<MChapter>? chaptersList = [];
for (var i = 0; i < chaptersNames.length; i++) {
MChapter chapter = MChapter();
chapter.name = chaptersNames[i];
chapter.url = chapUrls[i];
chapter.dateUpload = dateUploads[i];
chaptersList.add(chapter);
}
manga.chapters = chaptersList;
return manga;
}
@override
Future<List<String>> getPageList(MSource sourceInfo, String url) async {
final datas = {"url": url, "sourceId": sourceInfo.id};
final res = await MBridge.http('GET', json.encode(datas));
List<String> pagesUrl = [];
final pages = MBridge.xpath(
res, '//*[@id="all"]/img[@class="img-responsive"]/@data-src');
for (var page in pages) {
if (page.startsWith('//')) {
pagesUrl.add(page.replaceAll('//', 'https://'));
} else {
pagesUrl.add(page);
}
}
return pagesUrl;
}
@override
Future<List<MVideo>> getVideoList(MSource sourceInfo, String url) async {
return [];
}
}
MMCRCms main() {
return MMCRCms();
}

View File

@@ -1,7 +1,7 @@
import '../../../model/source.dart';
import '../../../utils/utils.dart';
const mmrcmsVersion = "0.0.3";
const mmrcmsVersion = "0.0.35";
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,224 +0,0 @@
import 'dart:convert';
import 'package:bridge_lib/bridge_lib.dart';
getPopularManga(MManga manga) async {
final data = {"url": "${manga.baseUrl}/search/"};
final response = await MBridge.http('GET', json.encode(data));
if (response.hasError) {
return response;
}
String res = response.body;
final directory = directoryFromDocument(res);
final resSort = MBridge.sortMapList(json.decode(directory), "vm", 1);
return parseDirectory(resSort, manga);
}
getLatestUpdatesManga(MManga manga) async {
final data = {"url": "${manga.baseUrl}/search/"};
final response = await MBridge.http('GET', json.encode(data));
if (response.hasError) {
return response;
}
String res = response.body;
final directory = directoryFromDocument(res);
final resSort = MBridge.sortMapList(json.decode(directory), "lt", 1);
return parseDirectory(resSort, manga);
}
searchManga(MManga manga) async {
final data = {"url": "${manga.baseUrl}/search/"};
final response = await MBridge.http('GET', json.encode(data));
if (response.hasError) {
return response;
}
String res = response.body;
final directory = directoryFromDocument(res);
final resSort = MBridge.sortMapList(json.decode(directory), "lt", 1);
final datas = json.decode(resSort) as List;
final queryRes = datas.where((e) {
String name = e['s'];
return name.toLowerCase().contains(manga.query.toLowerCase());
}).toList();
manga.hasNextPage = false;
if (queryRes.length > 50) {
manga.hasNextPage = true;
}
return parseDirectory(json.encode(queryRes), manga);
}
getMangaDetail(MManga manga) async {
final statusList = [
{"Ongoing": 0, "Completed": 1, "Cancelled": 3, "Hiatus": 2}
];
final headers = getHeader(manga.baseUrl);
final url = '${manga.baseUrl}/manga/${manga.link}';
final data = {"url": url, "headers": headers};
final response = await MBridge.http('GET', json.encode(data));
if (response.hasError) {
return response;
}
String res = response.body;
manga.author = MBridge.xpath(res,
'//li[contains(@class,"list-group-item") and contains(text(),"Author")]/a/text()')
.first;
manga.description = MBridge.xpath(res,
'//li[contains(@class,"list-group-item") and contains(text(),"Description:")]/div/text()')
.first;
final status = MBridge.xpath(res,
'//li[contains(@class,"list-group-item") and contains(text(),"Status")]/a/text()')
.first;
manga.status = MBridge.parseStatus(toStatus(status), statusList);
manga.genre = MBridge.xpath(res,
'//li[contains(@class,"list-group-item") and contains(text(),"Genre(s)")]/a/text()');
final script =
MBridge.xpath(res, '//script[contains(text(), "MainFunction")]/text()')
.first;
final vmChapters = MBridge.substringBefore(
MBridge.substringAfter(script, "vm.Chapters = "), ";");
final chapters = json.decode(vmChapters) as List;
manga.names = chapters.map((ch) {
String name = ch['ChapterName'] ?? "";
String indexChapter = ch['Chapter'];
if (name.isEmpty) {
name = '${ch['Type']} ${chapterImage(indexChapter, true)}';
}
return name;
}).toList();
manga.urls = chapters
.map((ch) =>
'/read-online/${MBridge.substringAfter(manga.link, "/manga/")}${chapterURLEncode(ch['Chapter'])}')
.toList();
final chapterDates = chapters.map((ch) => ch['Date']).toList();
manga.chaptersDateUploads = MBridge.listParseDateTime(
chapterDates, manga.dateFormat, manga.dateFormatLocale);
return manga;
}
getChapterPages(MManga manga) async {
final headers = getHeader(manga.baseUrl);
final url = '${manga.baseUrl}${manga.link}';
List<String> pages = [];
final data = {"url": url, "headers": headers};
final response = await MBridge.http('GET', json.encode(data));
if (response.hasError) {
return response;
}
String res = response.body;
final script =
MBridge.xpath(res, '//script[contains(text(), "MainFunction")]/text()')
.first;
final chapScript = json.decode(MBridge.substringBefore(
MBridge.substringAfter(script, "vm.CurChapter = "), ";"));
final pathName = MBridge.substringBefore(
MBridge.substringAfter(script, "vm.CurPathName = \"", ""), "\"");
var directory = chapScript['Directory'] ?? '';
if (directory.length > 0) {
directory += '/';
}
final mangaName = MBridge.substringBefore(
MBridge.substringAfter(manga.link, "/read-online/"), "-chapter");
var chNum = chapterImage(chapScript['Chapter'], false);
var totalPages = MBridge.intParse(chapScript['Page']);
for (int page = 1; page <= totalPages; page++) {
String paddedPageNumber = "$page".padLeft(3, '0');
String pageUrl =
'https://$pathName/manga/$mangaName/$directory$chNum-$paddedPageNumber.png';
pages.add(pageUrl);
}
return pages;
}
String chapterImage(String e, bool cleanString) {
var a = e.substring(1, e.length - 1);
if (cleanString) {
a = MBridge.regExp(a, r'^0+', "", 0, 0);
}
var b = MBridge.intParse(e.substring(e.length - 1));
if (b == 0 && a.isNotEmpty) {
return a;
} else if (b == 0 && a.isEmpty) {
return '0';
} else {
return '$a.$b';
}
}
String toStatus(String status) {
if (status.contains("Ongoing")) {
return "Ongoing";
} else if (status.contains("Complete")) {
return "Complete";
} else if (status.contains("Cancelled")) {
return "Cancelled";
} else if (status.contains("Hiatus")) {
return "Hiatus";
}
return "";
}
String directoryFromDocument(String res) {
final script =
MBridge.xpath(res, '//script[contains(text(), "MainFunction")]/text()')
.first;
return MBridge.substringBefore(
MBridge.substringAfter(script, "vm.Directory = "), "vm.GetIntValue")
.replaceAll(";", " ");
}
MManga parseDirectory(String resSort, MManga manga) {
final datas = json.decode(resSort) as List;
manga.names = datas.map((e) => e["s"]).toList();
manga.images = datas
.map((e) => 'https://temp.compsci88.com/cover/${e['i']}.jpg')
.toList();
manga.urls = datas.map((e) => e["i"]).toList();
return manga;
}
Map<String, String> getHeader(String url) {
final headers = {
'Referer': '$url/',
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/77.0"
};
return headers;
}
String chapterURLEncode(String e) {
var index = ''.toString();
var t = MBridge.intParse(e.substring(0, 1));
if (t != 1) {
index = '-index-$t';
}
var dgt = 0;
var inta = MBridge.intParse(e);
if (inta < 100100) {
dgt = 4;
} else if (inta < 101000) {
dgt = 3;
} else if (inta < 110000) {
dgt = 2;
} else {
dgt = 1;
}
final n = e.substring(dgt, e.length - 1);
var suffix = ''.toString();
final path = MBridge.intParse(e.substring(e.length - 1));
if (path != 0) {
suffix = '.$path';
}
return '-chapter-$n$suffix$index.html';
}

View File

@@ -0,0 +1,246 @@
import 'package:mangayomi/bridge_lib.dart';
import 'dart:convert';
class NepNep extends MSourceProvider {
NepNep();
@override
Future<MPages> getPopular(MSource sourceInfo, int page) async {
final data = {"url": "${sourceInfo.baseUrl}/search/"};
final res = await MBridge.http('GET', json.encode(data));
final directory = directoryFromDocument(res);
final resSort = MBridge.sortMapList(json.decode(directory), "vm", 1);
return parseDirectory(resSort);
}
@override
Future<MPages> getLatestUpdates(MSource sourceInfo, int page) async {
final data = {"url": "${sourceInfo.baseUrl}/search/"};
final res = await MBridge.http('GET', json.encode(data));
final directory = directoryFromDocument(res);
final resSort = MBridge.sortMapList(json.decode(directory), "lt", 1);
return parseDirectory(resSort);
}
@override
Future<MPages> search(MSource sourceInfo, String query, int page) async {
final data = {"url": "${sourceInfo.baseUrl}/search/"};
final res = await MBridge.http('GET', json.encode(data));
final directory = directoryFromDocument(res);
final resSort = MBridge.sortMapList(json.decode(directory), "lt", 1);
final datas = json.decode(resSort) as List;
final queryRes = datas.where((e) {
String name = e['s'];
return name.toLowerCase().contains(query.toLowerCase());
}).toList();
return parseDirectory(json.encode(queryRes));
}
@override
Future<MManga> getDetail(MSource sourceInfo, String url) async {
final statusList = [
{"Ongoing": 0, "Completed": 1, "Cancelled": 3, "Hiatus": 2}
];
final headers = getHeader(sourceInfo.baseUrl);
final data = {
"url": '${sourceInfo.baseUrl}/manga/$url',
"headers": headers
};
final res = await MBridge.http('GET', json.encode(data));
MManga manga = MManga();
manga.author = MBridge.xpath(res,
'//li[contains(@class,"list-group-item") and contains(text(),"Author")]/a/text()')
.first;
manga.description = MBridge.xpath(res,
'//li[contains(@class,"list-group-item") and contains(text(),"Description:")]/div/text()')
.first;
final status = MBridge.xpath(res,
'//li[contains(@class,"list-group-item") and contains(text(),"Status")]/a/text()')
.first;
manga.status = MBridge.parseStatus(toStatus(status), statusList);
manga.genre = MBridge.xpath(res,
'//li[contains(@class,"list-group-item") and contains(text(),"Genre(s)")]/a/text()');
final script =
MBridge.xpath(res, '//script[contains(text(), "MainFunction")]/text()')
.first;
final vmChapters = MBridge.substringBefore(
MBridge.substringAfter(script, "vm.Chapters = "), ";");
final chapters = json.decode(vmChapters) as List;
var chapUrls = chapters
.map((ch) =>
'/read-online/${MBridge.substringAfter(url, "/manga/")}${chapterURLEncode(ch['Chapter'])}')
.toList();
var chaptersNames = chapters.map((ch) {
String name = ch['ChapterName'] ?? "";
String indexChapter = ch['Chapter'];
if (name.isEmpty) {
name = '${ch['Type']} ${chapterImage(indexChapter, true)}';
}
return name;
}).toList();
var chaptersDates = chapters.map((ch) => ch['Date']).toList();
var dateUploads = MBridge.parseDates(
chaptersDates, sourceInfo.dateFormat, sourceInfo.dateFormatLocale);
List<MChapter> chaptersList = [];
for (var ch in chapters) {
MChapter chapter = MChapter();
String name = ch['ChapterName'] ?? "";
String indexChapter = ch['Chapter'];
if (name.isEmpty) {
name = '${ch['Type']} ${chapterImage(indexChapter, true)}';
}
chapter.name = name;
chapter.url =
'/read-online/${MBridge.substringAfter(url, "/manga/")}${chapterURLEncode(ch['Chapter'])}';
chapter.dateUpload = MBridge.parseDates(
[ch['Date']], sourceInfo.dateFormat, sourceInfo.dateFormatLocale)
.first;
chaptersList.add(chapter);
}
manga.chapters = chaptersList;
return manga;
}
@override
Future<List<String>> getPageList(MSource sourceInfo, String url) async {
final headers = getHeader(sourceInfo.baseUrl);
List<String> pages = [];
final data = {"url": '${sourceInfo.baseUrl}$url', "headers": headers};
print(data);
final res = await MBridge.http('GET', json.encode(data));
final script =
MBridge.xpath(res, '//script[contains(text(), "MainFunction")]/text()')
.first;
final chapScript = json.decode(MBridge.substringBefore(
MBridge.substringAfter(script, "vm.CurChapter = "), ";"));
final pathName = MBridge.substringBefore(
MBridge.substringAfter(script, "vm.CurPathName = \"", ""), "\"");
var directory = chapScript['Directory'] ?? '';
if (directory.length > 0) {
directory += '/';
}
final mangaName = MBridge.substringBefore(
MBridge.substringAfter(url, "/read-online/"), "-chapter");
var chNum = chapterImage(chapScript['Chapter'], false);
var totalPages = int.parse(chapScript['Page']);
for (int page = 1; page <= totalPages; page++) {
String paddedPageNumber = "$page".padLeft(3, '0');
String pageUrl =
'https://$pathName/manga/$mangaName/$directory$chNum-$paddedPageNumber.png';
pages.add(pageUrl);
}
return pages;
}
String directoryFromDocument(String res) {
final script =
MBridge.xpath(res, '//script[contains(text(), "MainFunction")]/text()')
.first;
return MBridge.substringBefore(
MBridge.substringAfter(script, "vm.Directory = "), "vm.GetIntValue")
.replaceAll(";", " ");
}
MPages parseDirectory(String res) {
List<MManga> mangaList = [];
final datas = json.decode(res) as List;
for (var data in datas) {
MManga manga = MManga();
manga.name = data["s"];
manga.imageUrl = 'https://temp.compsci88.com/cover/${data['i']}.jpg';
manga.link = data["i"];
mangaList.add(manga);
}
return MPages(mangaList, true);
}
Map<String, String> getHeader(String url) {
final headers = {
'Referer': '$url/',
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/77.0"
};
return headers;
}
String chapterImage(String e, bool cleanString) {
var a = e.substring(1, e.length - 1);
if (cleanString) {
a = MBridge.regExp(a, r'^0+', "", 0, 0);
}
var b = int.parse(e.substring(e.length - 1));
if (b == 0 && a.isNotEmpty) {
return a;
} else if (b == 0 && a.isEmpty) {
return '0';
} else {
return '$a.$b';
}
}
String toStatus(String status) {
if (status.contains("Ongoing")) {
return "Ongoing";
} else if (status.contains("Complete")) {
return "Complete";
} else if (status.contains("Cancelled")) {
return "Cancelled";
} else if (status.contains("Hiatus")) {
return "Hiatus";
}
return "";
}
String chapterURLEncode(String e) {
var index = ''.toString();
var t = int.parse(e.substring(0, 1));
if (t != 1) {
index = '-index-$t';
}
var dgt = 0;
var inta = int.parse(e);
if (inta < 100100) {
dgt = 4;
} else if (inta < 101000) {
dgt = 3;
} else if (inta < 110000) {
dgt = 2;
} else {
dgt = 1;
}
final n = e.substring(dgt, e.length - 1);
var suffix = ''.toString();
final path = int.parse(e.substring(e.length - 1));
if (path != 0) {
suffix = '.$path';
}
return '-chapter-$n$suffix$index.html';
}
@override
Future<List<MVideo>> getVideoList(MSource sourceInfo, String url) async {
return [];
}
}
NepNep main() {
return NepNep();
}

View File

@@ -1,7 +1,7 @@
import '../../../model/source.dart';
import '../../../utils/utils.dart';
const nepnepVersion = "0.0.2";
const nepnepVersion = "0.0.25";
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";