Merge pull request #296 from xMohnad/manga/mmrcms

Manga/mmrcms
This commit is contained in:
Moustapha Kodjo Amadou
2025-06-25 18:41:34 +01:00
committed by GitHub
2 changed files with 79 additions and 141 deletions

View File

@@ -21,9 +21,7 @@ class MMRCMS extends MProvider {
@override @override
Future<MPages> getPopular(int page) async { Future<MPages> getPopular(int page) async {
final res = (await client.get( final res = (await client.get(
Uri.parse( Uri.parse("${getBaseUrl()}/filterList?page=$page&sortBy=views&asc=false"),
"${source.baseUrl}/filterList?page=$page&sortBy=views&asc=false",
),
)).body; )).body;
final document = parseHtml(res); final document = parseHtml(res);
final mangaList = <MManga>[]; final mangaList = <MManga>[];
@@ -40,7 +38,7 @@ class MMRCMS extends MProvider {
if (page == 1) latestTitles.clear(); if (page == 1) latestTitles.clear();
final res = (await client.get( final res = (await client.get(
Uri.parse("${source.baseUrl}/latest-release?page=$page"), Uri.parse("${getBaseUrl()}/latest-release?page=$page"),
)).body; )).body;
final document = parseHtml(res); final document = parseHtml(res);
@@ -60,72 +58,32 @@ class MMRCMS extends MProvider {
@override @override
Future<MPages> search(String query, int page, FilterList filterList) async { Future<MPages> search(String query, int page, FilterList filterList) async {
final filters = filterList.filters; String url = getBaseUrl();
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<MManga> mangaList = []; List<MManga> mangaList = [];
List<String> urls = []; bool hasNextPage = false;
List<String> names = [];
List<String> images = [];
if (query.isNotEmpty) { if (query.isNotEmpty) {
url = "$url/search?query=$query";
final res = (await client.get(Uri.parse(url))).body;
final jsonList = json.decode(res)["suggestions"]; final jsonList = json.decode(res)["suggestions"];
for (var da in jsonList) { for (var da in jsonList) {
String value = da["value"]; String value = da["value"];
String data = da["data"]; String data = da["data"];
if (source.name == 'Scan VF') { final mangaSubString = getMangaSubString();
urls.add('${source.baseUrl}/$data'); final path = mangaSubString.isEmpty ? data : '$mangaSubString/$data';
} else {
urls.add('${source.baseUrl}/manga/$data'); mangaList.add(
} MManga(
names.add(value); name: value,
images.add( link: '${getBaseUrl()}/$path',
"${source.baseUrl}/uploads/manga/$data/cover/cover_250x350.jpg", imageUrl: guessCover('/$path'),
),
); );
} }
} else {
urls = xpath(res, '//div/div/div/a/@href');
names = xpath(res, '//div/div/div/a/text()');
for (var mangaUrl in urls) {
images.add(guessCover(mangaUrl));
}
}
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); return MPages(mangaList, hasNextPage);
} }
@override @override
@@ -217,84 +175,64 @@ class MMRCMS extends MProvider {
return pagesUrl; return pagesUrl;
} }
@override
List<dynamic> getFilterList() { List<dynamic> getFilterList() {
return [];
}
@override
List<dynamic> getSourcePreferences() {
return [ return [
HeaderFilter("NOTE: Ignored if using text search!"), EditTextPreference(
SeparatorFilter(), key: "domain_url",
TextFilter("AuthorFilter", "Author"), title: getTitleByLang(source.lang),
SelectFilter("CategoryFilter", "Category", 0, [ summary: "",
SelectFilterOption("Any", ""), value: source.baseUrl,
SelectFilterOption("Action", "Action"), dialogTitle: "URL",
SelectFilterOption("Adventure", "Adventure"), dialogMessage: "",
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 getBaseUrl() {
final baseUrl = getPreferenceValue(source.id, "domain_url")?.trim();
if (baseUrl == null || baseUrl.isEmpty) {
return source.baseUrl;
}
return baseUrl.endsWith("/")
? baseUrl.substring(0, baseUrl.length - 1)
: baseUrl;
}
String getTitleByLang(String? lang) {
const titles = {
'ar': 'تحرير الرابط',
'en': 'Edit URL',
'fr': 'Modifier lURL',
'es': 'Editar URL',
'de': 'URL bearbeiten',
'tr': 'URLyi düzenle',
'ru': 'Редактировать URL',
'id': 'Edit URL',
'pt': 'Editar URL',
'it': 'Modifica URL',
'ja': 'URLを編集',
'zh': '编辑网址',
'ko': 'URL 편집',
'fa': 'ویرایش نشانی',
};
return titles[lang?.toLowerCase()] ?? titles['en']!;
}
String getMangaSubString() {
const sourceTypeMap = {'Scan VF': "", "Read Comics Online": "comic"};
return sourceTypeMap[source.name] ?? "manga";
}
String ll(String url) { String ll(String url) {
if (url.contains("?")) { if (url.contains("?")) {
return "&"; return "&";
@@ -303,13 +241,14 @@ class MMRCMS extends MProvider {
} }
String guessCover(String mangaUrl, {String? url}) { String guessCover(String mangaUrl, {String? url}) {
String baseUrl = getBaseUrl();
if (url == null || url?.endsWith("no-image.png")) { if (url == null || url?.endsWith("no-image.png")) {
String slug = substringAfterLast(mangaUrl, '/'); String slug = substringAfterLast(mangaUrl, '/');
return "${source.baseUrl}/uploads/manga/${slug}/cover/cover_250x350.jpg"; return "${baseUrl}/uploads/manga/${slug}/cover/cover_250x350.jpg";
} else if (url?.startsWith(source.baseUrl)) { } else if (url?.startsWith(baseUrl)) {
return url; return url;
} else { } else {
return Uri.parse(source.baseUrl).resolve(url).toString(); return Uri.parse(baseUrl).resolve(url).toString();
} }
} }

View File

@@ -3,7 +3,7 @@ import 'src/fr/scanvf/scanvf.dart';
import 'src/ar/onma/onma.dart'; import 'src/ar/onma/onma.dart';
import 'src/en/readcomicsonline/readcomicsonline.dart'; import 'src/en/readcomicsonline/readcomicsonline.dart';
const mmrcmsVersion = "0.0.7"; const mmrcmsVersion = "0.0.8";
const mmrcmsSourceCodeUrl = const mmrcmsSourceCodeUrl =
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/manga/multisrc/mmrcms/mmrcms.dart"; "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/manga/multisrc/mmrcms/mmrcms.dart";
@@ -18,10 +18,9 @@ List<Source> _mmrcmsSourcesList =
readcomicsonlineSource, readcomicsonlineSource,
] ]
.map( .map(
(e) => (e) => e
e ..itemType = ItemType.manga
..itemType = ItemType.manga ..sourceCodeUrl = mmrcmsSourceCodeUrl
..sourceCodeUrl = mmrcmsSourceCodeUrl ..version = mmrcmsVersion,
..version = mmrcmsVersion,
) )
.toList(); .toList();