Add mangapark.dart

This commit is contained in:
KptnFishy
2025-06-04 20:06:54 +02:00
committed by GitHub
parent 569232f212
commit ce482aff2e

View File

@@ -0,0 +1,545 @@
import 'package:mangayomi/bridge_lib.dart';
import 'dart:convert';
class MangaPark extends MProvider {
MangaPark({required this.source});
MSource source;
final Client client = Client(source);
@override
bool get supportsLatest => true;
@override
Map<String, String> get headers => {};
@override
Future<MPages> getMangaItems(int page, final method) async {
List<MPages> mangaList = [];
final res = await client.post(
Uri.parse("${source.apiUrl}"),
headers: {
"Accept": "*/*",
"accept-language": "en-US,en;q=0.9,de;q=0.8,ja;q=0.7,es;q=0.6,nl;q=0.5",
"content-type": "application/json",
"referer": "https://mangapark.io/",
"cookie": "nsfw=${preferenceNsfwContent()}; imgser=${preferenceImgServer()}; wd=2504x735"
},
body: jsonEncode({
"query": """
query get_latestReleases(\$select: LatestReleases_Select) {
get_latestReleases(select: \$select) {
paging {
total pages page init size skip limit prev next
}
items {
id
data {
id dbStatus name origLang tranLang sfw_result
urlPath urlCover600 urlCoverOri
is_hot is_new follows
last_chapterNodes(amount: 1) {
id
data {
id dateCreate dbStatus isFinal dname urlPath is_new
}
}
}
sser_follow
}
}
}
""",
"variables": {
"select": {
"where": method,
"init": 24,
"size": 24,
"page": page
}
}
}));
final json = jsonDecode(res.body);
final data = json["data"]["get_latestReleases"];
final items = data["items"];
final bool isNextPage = data["paging"]["pages"] > page;
for (var item in items) {
final mangaData = item["data"];
MManga manga = MManga();
manga.name = mangaData["name"];
manga.imageUrl = "${source.baseUrl}${mangaData["urlCover600"]}";
manga.link = "${source.baseUrl}${mangaData["urlPath"]}";
mangaList.add(manga);
}
return MPages(mangaList, isNextPage);
}
@override
Future<MPages> getPopular(int page) async {
return getMangaItems(page, "popular");
}
@override
Future<MPages> getLatestUpdates(int page) async {
return getMangaItems(page, "release");
}
@override
Future<MPages> search(String query, int page, FilterList filterList) async {
List<MManga> mangaList = [];
final filters = filterList.filters;
String url = "";
String genres = "&genres=";
String translFrom = "&orig=";
String translTo = "&lang=";
for (var filter in filters) {
if (filter.type == "SearchFilter") {
if (filter.state.toString() != "") {
query = filter.state.toString();
}
} else if (filter.type == "GenresFilter") {
for (int i = 0; i < filter.state.length; i++) {
if (filter.state[i].state.toString() == "2") {
genres += "|${filter.state[i].value.toString()},";
} else if (filter.state[i].state.toString() == "1") {
genres += "${filter.state[i].value.toString()},";
}
}
} else if (filter.type == "TranslatedFromFilter") {
for (int i = 0; i < filter.state.length; i++) {
if (filter.state[i].state) {
translFrom += "${filter.state[i].value.toString()},";
}
}
} else if (filter.type == "TranslatedToFilter") {
for (int i = 0; i < filter.state.length; i++) {
if (filter.state[i].state) {
translTo += "${filter.state[i].value.toString()},";
}
}
} else if (filter.type == "OrigWorkFilter") {
url += "&status=${filter.values[filter.state].value.toString()}";
} else if (filter.type == "MparkUplFilter") {
url += "&upload=${filter.values[filter.state].value.toString()}";
} else if (filter.type == "ChapCountFilter") {
url += "&chapters=${filter.values[filter.state].value.toString()}";
} else if (filter.type == "SortFilter") {
url += "&sortby=${filter.values[filter.state].value.toString()}";
}
}
url += genres + translFrom + translTo;
final res = await client.get(Uri.parse("${source.baseUrl}/search?word=${Uri.encodeComponent(query.trim())}&page=$page$url"),
headers: {
"Accept": "*/*",
"accept-language": "en-US,en;q=0.9,de;q=0.8,ja;q=0.7,es;q=0.6,nl;q=0.5",
"referer": "https://mangapark.io/",
"cookie": "nsfw=${preferenceNsfwContent()}; imgser=${preferenceImgServer()}; wd=2504x735"
});
final doc = parseHtml(res.body);
final elements = doc.select("div.grid.gap-5.grid-cols-1.border-t.border-t-base-200.pt-5 > div");
if (elements.length == 0) {
return MPages(mangaList, false);
}
for (final element in elements) {
final nameElement = element.selectFirst("h3 > a > span");
final imageElement = element.selectFirst("div > div > a > img");
final urlElement = element.selectFirst("div > div > a");
final name = nameElement.text ?? "No Name";
final image = imageElement.attr("src").contains(source.baseUrl) ? imageElement.attr("src") : "${source.baseUrl}${imageElement.attr("src")}";
final url = urlElement.attr("href").contains(source.baseUrl) ? urlElement.attr("href") : "${source.baseUrl}${urlElement.attr("href")}";
MManga manga = MManga();
manga.name = name;
manga.imageUrl = image;
manga.link = url;
mangaList.add(manga);
}
final lastPageNumber = int.tryParse(doc.selectFirst("div.flex.items-center.flex-wrap.space-x-1.my-10.justify-center > a:last-child")?.text.trim());
bool hasNextPage = (lastPageNumber > page);
return MPages(mangaList, hasNextPage);
}
@override
Future<MManga> getDetail(String url) async {
final statusList = [{
"Pending": 0,
"Ongoing": 0,
"Completed": 1,
"Hiatus": 1,
"Cancelled": 3,
}];
final res = await client.get(Uri.parse("$url"),
headers: {
"Accept": "*/*",
"accept-language": "en-US,en;q=0.9,de;q=0.8,ja;q=0.7,es;q=0.6,nl;q=0.5",
"referer": "https://mangapark.io/",
"cookie": "nsfw=${preferenceNsfwContent()}; imgser=${preferenceImgServer()}; wd=2504x735"
});
final doc = parseHtml(res.body);
final statusElement = doc.selectFirst("div:nth-child(2) > div:nth-child(4) > span.font-bold.uppercase");
final authorElements = doc.select("div.flex.flex-col > div.flex > div.grow.pl-3.space-y-2 > div.mt-2.text-sm > a");
final genreList = doc.select("div.flex.items-center.flex-wrap > span > span:nth-child(1)");
final descriptionElement = doc.selectFirst("div.limit-html-p");
final author = authorElements.isNotEmpty ? authorElements.map((e) => e.text).join(" | ") : "Anonymous";
final genres = genreList.map((e) => (e.text as String).replaceAll(",", "").trim()).toList() ?? [];
final status = statusElement?.text ?? "Pending";
final description = descriptionElement.text ?? "no Description...";
final chapters = getChapters(doc);
MManga manga = MManga();
manga.genre = genres;
manga.author = author;
manga.chapters = chapters;
manga.description = description;
manga.status = parseStatus(status, statusList);
return manga;
}
List<MChapter> getChapters(MDocument doc) {
List<MChapter> chapters = [];
if (doc.selectFirst("div.group.flex.flex-col").outerHtml == null) {
throw("Something went wrong. if this is a age-restricted manga, try to turn of the NSFW filter in the settings, then reload the manga.");
}
MElement chapterList = doc.selectFirst("div.group.flex.flex-col");
for (MElement chapterElement in chapterList.select("div.justify-between")) {
var chapter = MChapter();
final chapterName = chapterElement.selectFirst("div > a");
final scanlatorElement = chapterElement.selectFirst("a.link-hover > span");
final name = chapterName.text ?? "No Name Given";
final url = chapterName.attr("href").contains(source.baseUrl) ? chapterName.attr("href") : "${source.baseUrl}${chapterName.attr("href")}";
final uploadDate = chapterElement.selectFirst("time")?.attr("data-time");
final scanlator = scanlatorElement.text ?? "Anonymous";
chapter.name = name;
chapter.url = url;
chapter.dateUpload = uploadDate;
chapter.scanlator = scanlator;
chapters.add(chapter);
}
return chapters;
}
@override
Future<List<Map<String, dynamic>>> getPageList(String url) async{
List<Map<String, dynamic>> images = [];
final res = await client.get(Uri.parse(url),
headers: {
"cookie": "${preferenceImgServer() == "" ? "" : "imgser=${preferenceImgServer()};"} nsfw=${preferenceNsfwContent()}; wd=2504x1362",
"referer": url,
});
final doc = parseHtml(res.body);
final imageObjects = doc.select('div[data-name="image-item"] img');
for (final imageObject in imageObjects) {
final imageUrl = imageObject.attr("src");
images.add({
"url": imageUrl.trim(),
"headers": {
"referer": url,
}
});
}
return images;
}
@override
List<dynamic> getFilterList() {
return [
TextFilter("SearchFilter", "Search..."),
SelectFilter("SortFilter", "Order By", 0, [
SelectFilterOption("Rating Score", "field_score"),
SelectFilterOption("Most Follows", "field_follow"),
SelectFilterOption("Most Reviews", "field_review"),
SelectFilterOption("Most Comments", "field_comment"),
SelectFilterOption("Most Chapters", "field_chapter"),
SelectFilterOption("New Chapters", "field_update"),
SelectFilterOption("Recently Created", "field_create"),
SelectFilterOption("Name A-Z", "field_name"),
SelectFilterOption("Most Views: Last 60 Minutes", "views_h001"),
SelectFilterOption("Most Views: Last 12 Hours", "views_h012"),
SelectFilterOption("Most Views: Last 24 Hours", "views_h024"),
SelectFilterOption("Most Views: Last 7 Days", "views_d007"),
SelectFilterOption("Most Views: Last 30 Days", "views_d030"),
SelectFilterOption("Most Views: Last 90 Days", "views_d090"),
SelectFilterOption("Most Views: Last 180 Days", "views_d180"),
SelectFilterOption("Most Views: Last 360 Days", "views_d360"),
SelectFilterOption("Most Views: All Time", "views_d000"),
SelectFilterOption("Emotion: Awesome", "emotion_e1"),
SelectFilterOption("Emotion: Funny", "emotion_e2"),
SelectFilterOption("Emotion: Love", "emotion_e3"),
SelectFilterOption("Emotion: Hot", "emotion_e4"),
SelectFilterOption("Emotion: Sweet", "emotion_e5"),
SelectFilterOption("Emotion: Cool", "emotion_e6"),
SelectFilterOption("Emotion: Scared", "emotion_e7"),
SelectFilterOption("Emotion: Angry", "emotion_e8"),
SelectFilterOption("Emotion: Sad", "emotion_e9"),
]),
SeparatorFilter(),
GroupFilter("GenresFilter", "Manga Style", [
TriStateFilter("Artbook", "artbook"),
TriStateFilter("Cartoon", "cartoon"),
TriStateFilter("Comic", "comic"),
TriStateFilter("Doujinshi", "doujinshi"),
TriStateFilter("Imageset", "imageset"),
TriStateFilter("Manga", "manga"),
TriStateFilter("Manhua", "manhua"),
TriStateFilter("Manhwa", "manhwa"),
TriStateFilter("Webtoon", "webtoon"),
TriStateFilter("Western", "western"),
TriStateFilter("Oneshot", "oneshot"),
TriStateFilter("4-Koma", "_4_koma"),
TriStateFilter("Art-by-AI", "ai_art"),
TriStateFilter("Story-by-AI", "ai_story"),
]),
SeparatorFilter(),
GroupFilter("GenresFilter", "General Filters", [
TriStateFilter("Shoujo(G)", "shoujo"),
TriStateFilter("Shounen(B)", "shounen"),
TriStateFilter("Josei(W)", "josei"),
TriStateFilter("Seinen(M)", "seinen"),
TriStateFilter("Yuri(GL)", "yuri"),
TriStateFilter("Yaoi(BL)", "yaoi"),
TriStateFilter("Futa(⚤)", "futa"),
TriStateFilter("Bara(ML)", "bara"),
TriStateFilter("Kodomo(Kid)", "kodomo"),
TriStateFilter("Silver & Golden", "old_people"),
TriStateFilter("Shoujo ai", "shoujo_ai"),
TriStateFilter("Shounen ai", "shounen_ai"),
TriStateFilter("Non-human", "non_human"),
]),
GroupFilter("GenresFilter", "Explicit Filters", [
TriStateFilter("Gore", "gore"),
TriStateFilter("Bloody", "bloody"),
TriStateFilter("Violence", "violence"),
TriStateFilter("Ecchi", "ecchi"),
TriStateFilter("Adult", "adult"),
TriStateFilter("Mature", "mature"),
TriStateFilter("Smut", "smut"),
TriStateFilter("Hentai", "hentai"),
]),
GroupFilter("GenresFilter", "Detailed Filters (A-M)", [
TriStateFilter("Action", "action"),
TriStateFilter("Adaptation", "adaptation"),
TriStateFilter("Adventure", "adventure"),
TriStateFilter("Age Gap", "age_gap"),
TriStateFilter("Aliens", "aliens"),
TriStateFilter("Animals", "animals"),
TriStateFilter("Anthology", "anthology"),
TriStateFilter("Beasts", "beasts"),
TriStateFilter("Bodyswap", "bodyswap"),
TriStateFilter("Blackmail", "blackmail"),
TriStateFilter("Brocon/Siscon", "brocon_siscon"),
TriStateFilter("Cars", "cars"),
TriStateFilter("Cheating/Infidelity", "cheating_infidelity"),
TriStateFilter("Childhood Friends", "childhood_friends"),
TriStateFilter("College life", "college_life"),
TriStateFilter("Comedy", "comedy"),
TriStateFilter("Contest winning", "contest_winning"),
TriStateFilter("Cooking", "cooking"),
TriStateFilter("Crime", "crime"),
TriStateFilter("Crossdressing", "crossdressing"),
TriStateFilter("Cultivation", "cultivation"),
TriStateFilter("Death Game", "death_game"),
TriStateFilter("DegenerateMC", "degeneratemc"),
TriStateFilter("Delinquents", "delinquents"),
TriStateFilter("Dementia", "dementia"),
TriStateFilter("Demons", "demons"),
TriStateFilter("Drama", "drama"),
TriStateFilter("Fantasy", "fantasy"),
TriStateFilter("Fan-Colored", "fan_colored"),
TriStateFilter("Fetish", "fetish"),
TriStateFilter("Full Color", "full_color"),
TriStateFilter("Game", "game"),
TriStateFilter("Gender Bender", "gender_bender"),
TriStateFilter("Genderswap", "genderswap"),
TriStateFilter("Ghosts", "ghosts"),
TriStateFilter("Gyaru", "gyaru"),
TriStateFilter("Harem", "harem"),
TriStateFilter("Harlequin", "harlequin"),
TriStateFilter("Historical", "historical"),
TriStateFilter("Horror", "horror"),
TriStateFilter("Incest", "incest"),
TriStateFilter("Isekai", "isekai"),
TriStateFilter("Kids", "kids"),
TriStateFilter("Loli", "loli"),
TriStateFilter("Magic", "magic"),
TriStateFilter("Magical Girls", "magical_girls"),
TriStateFilter("Martial Arts", "martial_arts"),
TriStateFilter("Master-Servant", "master_servant"),
TriStateFilter("Mecha", "mecha"),
TriStateFilter("Medical", "medical"),
TriStateFilter("Military", "military"),
TriStateFilter("Monster Girls", "monster_girls"),
TriStateFilter("Monsters", "monsters"),
TriStateFilter("Music", "music"),
TriStateFilter("Mystery", "mystery"),
]),
GroupFilter("GenresFilter", "Detailed Filters (N-Z)", [
TriStateFilter("Netori", "netori"),
TriStateFilter("Netorare/NTR", "netorare"),
TriStateFilter("Ninja", "ninja"),
TriStateFilter("Office Workers", "office_workers"),
TriStateFilter("Omegaverse", "omegaverse"),
TriStateFilter("Parody", "parody"),
TriStateFilter("Philosophical", "philosophical"),
TriStateFilter("Police", "police"),
TriStateFilter("Post-Apocalyptic", "post_apocalyptic"),
TriStateFilter("Psychological", "psychological"),
TriStateFilter("Reincarnation", "reincarnation"),
TriStateFilter("Revenge", "revenge"),
TriStateFilter("Reverse Harem", "reverse_harem"),
TriStateFilter("Romance", "romance"),
TriStateFilter("Samurai", "samurai"),
TriStateFilter("School Life", "school_life"),
TriStateFilter("Sci-Fi", "sci_fi"),
TriStateFilter("Shota", "shota"),
TriStateFilter("Showbiz", "showbiz"),
TriStateFilter("Slice of Life", "slice_of_life"),
TriStateFilter("SM/BDSM", "sm_bdsm"),
TriStateFilter("Space", "space"),
TriStateFilter("Sports", "sports"),
TriStateFilter("Spy", "spy"),
TriStateFilter("Step Family", "step_family"),
TriStateFilter("Super Power", "super_power"),
TriStateFilter("Superhero", "superhero"),
TriStateFilter("Supernatural", "supernatural"),
TriStateFilter("Survival", "survival"),
TriStateFilter("Teacher-Student", "teacher_student"),
TriStateFilter("Thriller", "thriller"),
TriStateFilter("Time Travel", "time_travel"),
TriStateFilter("Traditional Games", "traditional_games"),
TriStateFilter("Tragedy", "tragedy"),
TriStateFilter("Vampires", "vampires"),
TriStateFilter("Video Games", "video_games"),
TriStateFilter("Villainess", "villainess"),
TriStateFilter("Virtual Reality", "virtual_reality"),
TriStateFilter("Wuxia", "wuxia"),
TriStateFilter("Xianxia", "xianxia"),
TriStateFilter("Xuanhuan", "xuanhuan"),
TriStateFilter("Zombies", "zombies"),
]),
SeparatorFilter(),
GroupFilter("TranslatedFromFilter", "Original Work Language", [
CheckBoxFilter("Chinese", "zh"),
CheckBoxFilter("English", "en"),
CheckBoxFilter("Japanese", "jp"),
CheckBoxFilter("Korean", "ko"),
]),
GroupFilter("TranslatedToFilter", "Translated Language", [
CheckBoxFilter("Dutch", "nl"),
CheckBoxFilter("English", "en"),
CheckBoxFilter("German", "de"),
CheckBoxFilter("Japanese", "jp"),
CheckBoxFilter("Spanish", "es"),
CheckBoxFilter("Spanish (LA)", "es_419"),
]),
SeparatorFilter(),
SelectFilter("OrigWorkFilter", "Original Work Status", 0, [
SelectFilterOption("Any", ""),
SelectFilterOption("Pending", "pending"),
SelectFilterOption("Ongoing", "ongoing"),
SelectFilterOption("Completed", "completed"),
SelectFilterOption("Hiatus", "hiatus"),
SelectFilterOption("Cancelled", "cancelled"),
]),
SelectFilter("MparkUplFilter", "MangaPark Upload Status", 0, [
SelectFilterOption("Any", ""),
SelectFilterOption("Pending", "pending"),
SelectFilterOption("Ongoing", "ongoing"),
SelectFilterOption("Completed", "completed"),
SelectFilterOption("Hiatus", "hiatus"),
SelectFilterOption("Cancelled", "cancelled"),
]),
SeparatorFilter(),
SelectFilter("ChapCountFilter", "Number of Chapters", 0, [
SelectFilterOption("Any", ""),
SelectFilterOption("0", "0"),
SelectFilterOption("1+", "1"),
SelectFilterOption("10+", "10"),
SelectFilterOption("20+", "20"),
SelectFilterOption("30+", "30"),
SelectFilterOption("40+", "40"),
SelectFilterOption("50+", "50"),
SelectFilterOption("60+", "60"),
SelectFilterOption("70+", "70"),
SelectFilterOption("80+", "80"),
SelectFilterOption("90+", "90"),
SelectFilterOption("100+", "100"),
SelectFilterOption("200+", "200"),
SelectFilterOption("300+", "300"),
SelectFilterOption("299~200", "200-299"),
SelectFilterOption("199~100", "100-199"),
SelectFilterOption("99~90", "90-99"),
SelectFilterOption("89~80", "80-89"),
SelectFilterOption("79~70", "70-79"),
SelectFilterOption("69~60", "60-69"),
SelectFilterOption("59~50", "50-59"),
SelectFilterOption("49~40", "40-49"),
SelectFilterOption("39~30", "30-39"),
SelectFilterOption("29~20", "20-29"),
SelectFilterOption("19~10", "10-19"),
SelectFilterOption("9~1", "1-9"),
]),
];
}
@override
List<dynamic> getSourcePreferences() {
return [
ListPreference(
key: "NsfwFilter1",
title: "Display NSFW content",
summary: "",
valueIndex: 0,
entries: ["False", "True"],
entryValues: [0, 2],
),
ListPreference(
key: "ImgServer",
title: "Choose Image Server",
summary: "",
valueIndex: 0,
entries: ["Default", "mpfip.org", "mpizz.org", "mpmok.org", "mpqom.org", "mpqrc.org", "mprnm.org", "mpubn.org", "mpujj.org", "mpvim.org", "mypypl.org"],
entryValues: ["", "mpfip.org", "mpizz.org", "mpmok.org", "mpqom.org", "mpqrc.org", "mprnm.org", "mpubn.org", "mpujj.org", "mpvim.org", "mypypl.org"],
),
];
}
int preferenceNsfwContent() {
return getPreferenceValue(source.id, "NsfwFilter1");
}
String preferenceImgServer() {
return getPreferenceValue(source.id, "ImgServer");
}
}
MangaPark main(MSource source) {
return MangaPark(source:source);
}