import 'package:mangayomi/bridge_lib.dart'; import 'dart:convert'; class MMRCMS extends MProvider { MMRCMS({required this.source}); MSource source; final Client client = Client(); @override Future getPopular(int page) async { final res = (await client.get( Uri.parse( "${source.baseUrl}/filterList?page=$page&sortBy=views&asc=false", ), )).body; List mangaList = []; final urls = xpath(res, '//*[ @class="chart-title"]/@href'); final names = xpath(res, '//*[ @class="chart-title"]/text()'); List images = []; for (var url in urls) { String slug = substringAfterLast(url, '/'); if (source.name == "Manga-FR") { images.add("${source.baseUrl}/uploads/manga/${slug}.jpg"); } else { images.add( "${source.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 getLatestUpdates(int page) async { final res = (await client.get( Uri.parse("${source.baseUrl}/latest-release?page=$page"), )).body; List mangaList = []; final urls = xpath(res, '//*[@class="manga-item"]/h3/a/@href'); final names = xpath(res, '//*[@class="manga-item"]/h3/a/text()'); List images = []; for (var url in urls) { String slug = substringAfterLast(url, '/'); if (source.name == "Manga-FR") { images.add("${source.baseUrl}/uploads/manga/${slug}.jpg"); } else { images.add( "${source.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 search(String query, int page, FilterList filterList) async { final filters = filterList.filters; String url = ""; if (query.isNotEmpty) { url = "${source.baseUrl}/search?query=$query"; } else { url = "${source.baseUrl}/filterList?page=$page"; for (var filter in filters) { if (filter.type == "AuthorFilter") { url += "${ll(url)}author=${Uri.encodeComponent(filter.state)}"; } else if (filter.type == "SortFilter") { url += "${ll(url)}sortBy=${filter.values[filter.state.index].value}"; final asc = filter.state.ascending ? "asc=true" : "asc=false"; url += "${ll(url)}$asc"; } else if (filter.type == "CategoryFilter") { if (filter.state != 0) { final cat = filter.values[filter.state].value; url += "${ll(url)}cat=$cat"; } } else if (filter.type == "BeginsWithFilter") { if (filter.state != 0) { final a = filter.values[filter.state].value; url += "${ll(url)}alpha=$a"; } } } } final res = (await client.get(Uri.parse(url))).body; List mangaList = []; List urls = []; List names = []; List images = []; if (query.isNotEmpty) { final jsonList = json.decode(res)["suggestions"]; for (var da in jsonList) { String value = da["value"]; String data = da["data"]; if (source.name == 'Scan VF') { urls.add('${source.baseUrl}/$data'); } else if (source.name == 'Manga-FR') { urls.add('${source.baseUrl}/lecture-en-ligne/$data'); } else { urls.add('${source.baseUrl}/manga/$data'); } names.add(value); if (source.name == "Manga-FR") { images.add("${source.baseUrl}/uploads/manga/$data.jpg"); } else { images.add( "${source.baseUrl}/uploads/manga/$data/cover/cover_250x350.jpg", ); } } } else { urls = xpath(res, '//div/div/div/a/@href'); names = xpath(res, '//div/div/div/a/text()'); for (var url in urls) { String slug = substringAfterLast(url, '/'); if (source.name == "Manga-FR") { images.add("${source.baseUrl}/uploads/manga/${slug}.jpg"); } else { images.add( "${source.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 getDetail(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 res = (await client.get(Uri.parse(url))).body; final author = 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()', ); if (author.isNotEmpty) { manga.author = author.first; } final status = 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()', ); if (status.isNotEmpty) { manga.status = parseStatus(status.first, statusList); } final description = xpath( res, '//*[@class="well" or @class="manga well"]/p/text()', ); if (description.isNotEmpty) { manga.description = description.first; } manga.genre = 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()', ); var chapUrls = xpath(res, '//*[@class="chapter-title-rtl"]/a/@href'); var chaptersNames = xpath(res, '//*[@class="chapter-title-rtl"]/a/text()'); var chaptersDates = xpath( res, '//*[@class="date-chapter-title-rtl"]/text()', ); var dateUploads = parseDates( chaptersDates, source.dateFormat, source.dateFormatLocale, ); List? 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> getPageList(String url) async { final res = (await client.get(Uri.parse(url))).body; List pagesUrl = []; final pages = 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; } List getFilterList() { return [ HeaderFilter("NOTE: Ignored if using text search!"), SeparatorFilter(), TextFilter("AuthorFilter", "Author"), SelectFilter("CategoryFilter", "Category", 0, [ SelectFilterOption("Any", ""), SelectFilterOption("Action", "Action"), SelectFilterOption("Adventure", "Adventure"), SelectFilterOption("Comedy", "Comedy"), SelectFilterOption("Doujinshi", "Doujinshi"), SelectFilterOption("Drama", "Drama"), SelectFilterOption("Ecchi", "Ecchi"), SelectFilterOption("Fantasy", "Fantasy"), SelectFilterOption("Gender Bender", "Gender Bender"), SelectFilterOption("Harem", "Harem"), SelectFilterOption("Historical", "Historical"), SelectFilterOption("Horror", "Horror"), SelectFilterOption("Josei", "Josei"), SelectFilterOption("Martial Arts", "Martial Arts"), SelectFilterOption("Mature", "Mature"), SelectFilterOption("Mecha", "Mecha"), SelectFilterOption("Mystery", "Mystery"), SelectFilterOption("One Shot", "One Shot"), SelectFilterOption("Psychological", "Psychological"), SelectFilterOption("Romance", "Romance"), SelectFilterOption("School Life", "School Life"), SelectFilterOption("Sci-fi", "Sci-fi"), SelectFilterOption("Seinen", "Seinen"), SelectFilterOption("Shoujo", "Shoujo"), SelectFilterOption("Shoujo Ai", "Shoujo Ai"), SelectFilterOption("Shounen", "Shounen"), SelectFilterOption("Shounen Ai", "Shounen Ai"), SelectFilterOption("Slice of Life", "Slice of Life"), SelectFilterOption("Sports", "Sports"), SelectFilterOption("Supernatural", "Supernatural"), SelectFilterOption("Tragedy", "Tragedy"), SelectFilterOption("Yaoi", "Yaoi"), SelectFilterOption("Yuri", "Yuri"), ]), SelectFilter("BeginsWithFilter", "Begins with", 0, [ SelectFilterOption("Any", ""), SelectFilterOption("#", "#"), SelectFilterOption("A", "A"), SelectFilterOption("B", "B"), SelectFilterOption("C", "C"), SelectFilterOption("D", "D"), SelectFilterOption("E", "E"), SelectFilterOption("F", "F"), SelectFilterOption("G", "G"), SelectFilterOption("H", "H"), SelectFilterOption("I", "I"), SelectFilterOption("J", "J"), SelectFilterOption("K", "K"), SelectFilterOption("L", "L"), SelectFilterOption("M", "M"), SelectFilterOption("N", "N"), SelectFilterOption("O", "O"), SelectFilterOption("P", "P"), SelectFilterOption("Q", "Q"), SelectFilterOption("R", "R"), SelectFilterOption("S", "S"), SelectFilterOption("T", "T"), SelectFilterOption("U", "U"), SelectFilterOption("V", "V"), SelectFilterOption("W", "W"), SelectFilterOption("X", "X"), SelectFilterOption("Y", "Y"), SelectFilterOption("Z", "Z"), ]), SortFilter("SortFilter", "Sort", SortState(0, true), [ SelectFilterOption("Name", "name"), SelectFilterOption("Popularity", "views"), SelectFilterOption("Last update", "last_release"), ]), ]; } String ll(String url) { if (url.contains("?")) { return "&"; } return "?"; } } MMRCMS main(MSource source) { return MMRCMS(source: source); }