This commit is contained in:
Moustapha Kodjo Amadou
2025-06-02 13:04:07 +01:00
parent 62d7eee5f2
commit 218d4e5fbd
2 changed files with 120 additions and 67 deletions

View File

@@ -4,6 +4,7 @@ import 'multisrc/mangabox/sources.dart';
import 'multisrc/mangareader/sources.dart'; import 'multisrc/mangareader/sources.dart';
import 'multisrc/mmrcms/sources.dart'; import 'multisrc/mmrcms/sources.dart';
import 'multisrc/nepnep/sources.dart'; import 'multisrc/nepnep/sources.dart';
import 'src/en/mangabuddy/source.dart';
import 'src/en/mangahere/source.dart'; import 'src/en/mangahere/source.dart';
List<Source> dartMangasourceList = [ List<Source> dartMangasourceList = [
@@ -13,4 +14,5 @@ List<Source> dartMangasourceList = [
mangahereSource, mangahereSource,
...nepnepSourcesList, ...nepnepSourcesList,
...mangaboxSourcesList, ...mangaboxSourcesList,
mangabuddySource,
]; ];

View File

@@ -6,7 +6,7 @@ class MangaBuddy extends MProvider {
MSource source; MSource source;
final Client client = Client(source); final Client client = Client();
@override @override
bool get supportsLatest => true; bool get supportsLatest => true;
@@ -14,58 +14,74 @@ class MangaBuddy extends MProvider {
@override @override
Map<String, String> get headers => {}; Map<String, String> get headers => {};
@override
MPages mangaFromElements(List<MElement> elements, bool hasNextPage) { MPages mangaFromElements(List<MElement> elements, bool hasNextPage) {
List<MManga> mangaList = []; List<MManga> mangaList = [];
for (var i = 0; i < elements.length; i++) { for (var i = 0; i < elements.length; i++) {
final title = elements[i].selectFirst("div.meta > div.title > h3 > a"); final title = elements[i].selectFirst("div.meta > div.title > h3 > a");
final imageElement = elements[i].selectFirst("div.thumb > a > img"); final imageElement = elements[i].selectFirst("div.thumb > a > img");
final image = imageElement?.attr("data-src") ?? final image =
imageElement?.getSrc ?? imageElement?.attr("data-src") ?? imageElement?.getSrc ?? "";
"";
MManga manga = MManga(); MManga manga = MManga();
manga.name = title.text ?? title.attr("title"); manga.name = title.text ?? title.attr("title");
manga.imageUrl = image; manga.imageUrl = image;
manga.link = title.attr("href").contains(source.baseUrl) ? title.attr("href") : "${source.baseUrl}${title.attr("href")}"; manga.link = title.attr("href").contains(source.baseUrl)
? title.attr("href")
: "${source.baseUrl}${title.attr("href")}";
mangaList.add(manga); mangaList.add(manga);
} }
return MPages(mangaList, hasNextPage); return MPages(mangaList, hasNextPage);
} }
@override @override
Future<MPages> getPopular(int page) async { Future<MPages> getPopular(int page) async {
final res = await client.get(Uri.parse("${source.baseUrl}/popular?page=$page")); final res = await client.get(
final doc = parseHtml(res.body); Uri.parse("${source.baseUrl}/popular?page=$page"),
);
final doc = parseHtml(res.body);
final nextElement = doc.selectFirst("a.page-link[title='Next']"); final nextElement = doc.selectFirst("a.page-link[title='Next']");
bool hasNext = nextElement.text != null; bool hasNext = nextElement.text != null;
return mangaFromElements(doc.select("div.list.manga-list > div.book-item > div.book-detailed-item"), true); return mangaFromElements(
doc.select(
"div.list.manga-list > div.book-item > div.book-detailed-item",
),
true,
);
} }
@override @override
Future<MPages> getLatestUpdates(int page) async { Future<MPages> getLatestUpdates(int page) async {
final res = await client.get(Uri.parse("${source.baseUrl}/latest?page=$page")); final res = await client.get(
final doc = parseHtml(res.body); Uri.parse("${source.baseUrl}/latest?page=$page"),
);
final doc = parseHtml(res.body);
final nextElement = doc.selectFirst("a.page-link[title='Next']"); final nextElement = doc.selectFirst("a.page-link[title='Next']");
bool hasNext = nextElement.text != null; bool hasNext = nextElement.text != null;
return mangaFromElements(doc.select("div.list.manga-list > div.book-item > div.book-detailed-item"), true); return mangaFromElements(
doc.select(
"div.list.manga-list > div.book-item > div.book-detailed-item",
),
true,
);
} }
@override @override
Future<MPages> search(String initialQuery, int page, FilterList filterList) async { Future<MPages> search(
String initialQuery,
int page,
FilterList filterList,
) async {
final filters = filterList.filters; final filters = filterList.filters;
final filterString = ""; String filterString = "";
final query = initialQuery; String query = initialQuery;
for (var filter in filters) { for (var filter in filters) {
if (filter.type == "SearchFilter") {
if (filter.type == "SearchFilter"){
query = filter.state.toString(); query = filter.state.toString();
} else if (filter.type == "GenresFilter") { } else if (filter.type == "GenresFilter") {
for (var genre in filter.state) { for (var genre in filter.state) {
@@ -74,25 +90,32 @@ class MangaBuddy extends MProvider {
} }
} }
} else if (filter.type == "StatusFilter") { } else if (filter.type == "StatusFilter") {
filterString += ("&status=${filter.values[filter.state].value.toString()}"); filterString +=
("&status=${filter.values[filter.state].value.toString()}");
} else if (filter.type == "OrderFilter") { } else if (filter.type == "OrderFilter") {
filterString += ("&sort=${filter.values[filter.state].value.toString()}"); filterString +=
("&sort=${filter.values[filter.state].value.toString()}");
} }
} }
final res = await client.get(
final res = await client.get(Uri.parse("${source.baseUrl}/search?$filterString&q=$query&page=$page")); Uri.parse("${source.baseUrl}/search?$filterString&q=$query&page=$page"),
);
final doc = parseHtml(res.body); final doc = parseHtml(res.body);
return mangaFromElements(doc.select("div.list.manga-list > div.book-item > div.book-detailed-item"), true); return mangaFromElements(
doc.select(
"div.list.manga-list > div.book-item > div.book-detailed-item",
),
true,
);
} }
@override @override
Future<MManga> getDetail(String url) async { Future<MManga> getDetail(String url) async {
final statusList = [{ final statusList = [
"Ongoing": 0, {"Ongoing": 0, "Completed": 1},
"Completed": 1, ];
}];
final res = await client.get(Uri.parse(url)); final res = await client.get(Uri.parse(url));
final doc = parseHtml(res.body); final doc = parseHtml(res.body);
@@ -102,18 +125,32 @@ class MangaBuddy extends MProvider {
final idRegex = RegExp(r"var\s+bookId\s*=\s*(\d+);"); final idRegex = RegExp(r"var\s+bookId\s*=\s*(\d+);");
final imageElement = doc.selectFirst("div.book-info div.img-cover > img"); final imageElement = doc.selectFirst("div.book-info div.img-cover > img");
final statusElement = doc.selectFirst("div.book-info div.detail > div.meta.box.mt-1.p-10 > p > a[href^='/status/'] > span"); final statusElement = doc.selectFirst(
final authorElements = doc.select("div.book-info div.detail > div.meta.box.mt-1.p-10 > p > a[href^='/authors/'] > span"); "div.book-info div.detail > div.meta.box.mt-1.p-10 > p > a[href^='/status/'] > span",
final genreList = doc.select("div.book-info div.detail > div.meta.box.mt-1.p-10 > p > a[href^='/genres/']"); );
final descriptionElement = doc.selectFirst("div.section-body.summary > p.content"); final authorElements = doc.select(
"div.book-info div.detail > div.meta.box.mt-1.p-10 > p > a[href^='/authors/'] > span",
);
final genreList = doc.select(
"div.book-info div.detail > div.meta.box.mt-1.p-10 > p > a[href^='/genres/']",
);
final descriptionElement = doc.selectFirst(
"div.section-body.summary > p.content",
);
final chapterIdMatch = idRegex.firstMatch(chapterIdElement?.text); final chapterIdMatch = idRegex.firstMatch(chapterIdElement?.text);
final chapterId = chapterIdMatch != null ? chapterIdMatch.group(1) ?? "" : ""; final chapterId = chapterIdMatch != null
? chapterIdMatch.group(1) ?? ""
: "";
final image = imageElement?.attr("data-src") ?? imageElement?.getSrc ?? ""; final image = imageElement?.attr("data-src") ?? imageElement?.getSrc ?? "";
final status = statusElement.text ?? "Ongoing"; final status = statusElement.text ?? "Ongoing";
final author = authorElements.isNotEmpty ? authorElements.map((e) => e.text).join(" | ") : "unknown"; final author = authorElements.isNotEmpty
final genres = genreList.map((e) => (e.text as String).replaceAll(",", "").trim()).toList(); ? authorElements.map((e) => e.text).join(" | ")
: "unknown";
final genres = genreList
.map((e) => (e.text as String).replaceAll(",", "").trim())
.toList();
final description = descriptionElement?.text ?? ""; final description = descriptionElement?.text ?? "";
@@ -123,7 +160,7 @@ class MangaBuddy extends MProvider {
manga.genre = genres; manga.genre = genres;
manga.chapters = await getChapters(chapterId); manga.chapters = await getChapters(chapterId);
manga.status = parseStatus(status, statusList); manga.status = parseStatus(status, statusList);
return manga; return manga;
} }
@@ -131,7 +168,11 @@ class MangaBuddy extends MProvider {
Future<List<MChapter>> getChapters(String chapterId) async { Future<List<MChapter>> getChapters(String chapterId) async {
List<MChapter> chapters = []; List<MChapter> chapters = [];
final res = await client.get(Uri.parse("${source.baseUrl}/api/manga/$chapterId/chapters?source=detail")); final res = await client.get(
Uri.parse(
"${source.baseUrl}/api/manga/$chapterId/chapters?source=detail",
),
);
MDocument doc = parseHtml(res.body); MDocument doc = parseHtml(res.body);
MElement chapterList = doc.selectFirst("ul.chapter-list"); MElement chapterList = doc.selectFirst("ul.chapter-list");
@@ -141,7 +182,9 @@ class MangaBuddy extends MProvider {
final name = chapterElement.selectFirst("strong.chapter-title")?.text; final name = chapterElement.selectFirst("strong.chapter-title")?.text;
final url = chapterElement.selectFirst("a")?.attr("href"); final url = chapterElement.selectFirst("a")?.attr("href");
final uploadDate = chapterElement.selectFirst("time.chapter-update")?.text; final uploadDate = chapterElement
.selectFirst("time.chapter-update")
?.text;
chapter.name = name; chapter.name = name;
chapter.url = url; chapter.url = url;
@@ -153,16 +196,22 @@ class MangaBuddy extends MProvider {
return chapters; return chapters;
} }
@override
int parseDateToUnix(String dateStr) { int parseDateToUnix(String dateStr) {
const monthMap = { const monthMap = {
'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'Jan': 1,
'May': 5, 'Jun': 6, 'Jul': 7, 'Aug': 8, 'Feb': 2,
'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12, 'Mar': 3,
'Apr': 4,
'May': 5,
'Jun': 6,
'Jul': 7,
'Aug': 8,
'Sep': 9,
'Oct': 10,
'Nov': 11,
'Dec': 12,
}; };
final parts = dateStr.split(' '); final parts = dateStr.split(' ');
if (parts.length != 3) return DateTime.now().millisecondsSinceEpoch; if (parts.length != 3) return DateTime.now().millisecondsSinceEpoch;
@@ -185,26 +234,28 @@ class MangaBuddy extends MProvider {
final res = await client.get(Uri.parse("${source.baseUrl}$url")); final res = await client.get(Uri.parse("${source.baseUrl}$url"));
final doc = parseHtml(res.body); final doc = parseHtml(res.body);
final imageScript = doc.select("div#viewer-page.main-container.viewer > script"); final imageScript = doc.select(
"div#viewer-page.main-container.viewer > script",
);
final rawImageText = imageScript[imageScript.length-1]?.text ?? ""; final rawImageText = imageScript[imageScript.length - 1]?.text ?? "";
final imageList = rawImageText.replaceAll("var chapImages =", "").replaceAll("'", "").trim().split(","); final imageList = rawImageText
.replaceAll("var chapImages =", "")
.replaceAll("'", "")
.trim()
.split(",");
for (final image in imageList) { for (final image in imageList) {
images.add({ images.add({
"url": image.trim(), "url": image.trim(),
"headers": { "headers": {"Referer": source.baseUrl},
"Referer": source.baseUrl,
}
}); });
} }
return images; return images;
} }
@override @override
List<dynamic> getFilterList() { List<dynamic> getFilterList() {
return [ return [
@@ -305,5 +356,5 @@ class MangaBuddy extends MProvider {
} }
MangaBuddy main(MSource source) { MangaBuddy main(MSource source) {
return MangaBuddy(source:source); return MangaBuddy(source: source);
} }