mirror of
https://github.com/kodjodevf/mangayomi-extensions.git
synced 2026-02-14 02:41:39 +00:00
Refactor manga detail extraction logic
This commit is contained in:
@@ -130,79 +130,75 @@ class MMRCMS extends MProvider {
|
||||
|
||||
@override
|
||||
Future<MManga> 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 document = parseHtml(res);
|
||||
final manga = MManga();
|
||||
|
||||
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);
|
||||
}
|
||||
// Title
|
||||
final mangaTitle = document
|
||||
.selectFirst(".panel-heading, .listmanga-header, .widget-title")
|
||||
?.text;
|
||||
manga.name = mangaTitle;
|
||||
|
||||
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()',
|
||||
// Cover
|
||||
manga.imageUrl = guessCover(
|
||||
url,
|
||||
url: document.selectFirst(".row img.img-responsive")?.getSrc,
|
||||
);
|
||||
|
||||
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()',
|
||||
);
|
||||
// Description
|
||||
manga.description = extractDescription(document);
|
||||
|
||||
var dateUploads = parseDates(
|
||||
chaptersDates,
|
||||
source.dateFormat,
|
||||
source.dateFormatLocale,
|
||||
);
|
||||
document.select('.panel-body h3, .row .dl-horizontal dt').forEach((
|
||||
element,
|
||||
) {
|
||||
final label = _getOwnText(
|
||||
element,
|
||||
).toLowerCase().replaceFirst(RegExp(r' :$'), '');
|
||||
|
||||
final valueElement = element.selectFirst('div.text');
|
||||
if (valueElement.text == null)
|
||||
final valueElement = element.nextElementSibling;
|
||||
|
||||
_assignMangaInfo(manga, label, valueElement);
|
||||
});
|
||||
|
||||
// Chapters
|
||||
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);
|
||||
for (var ch in document.select("ul.chapters > li:not(.btn)")) {
|
||||
chaptersList.add(chapterFromElement(ch, mangaTitle));
|
||||
}
|
||||
manga.chapters = chaptersList;
|
||||
|
||||
return manga;
|
||||
}
|
||||
|
||||
MChapter chapterFromElement(MElement element, String mangaTitle) {
|
||||
final chapter = MChapter();
|
||||
|
||||
final titleWrapper = element.selectFirst(".chapter-title-rtl");
|
||||
final anchor = titleWrapper?.selectFirst("a");
|
||||
|
||||
if (anchor != null) {
|
||||
chapter.url = anchor.getHref ?? '';
|
||||
chapter.name = cleanChapterName(titleWrapper.text, mangaTitle);
|
||||
|
||||
final dateElement = element.selectFirst(".date-chapter-title-rtl");
|
||||
|
||||
if (dateElement != null && dateElement.text.isNotEmpty) {
|
||||
chapter.dateUpload = parseDates(
|
||||
[dateElement.text],
|
||||
source.dateFormat,
|
||||
source.dateFormatLocale,
|
||||
)[0];
|
||||
} else {
|
||||
chapter.dateUpload = DateTime.now().millisecondsSinceEpoch.toString();
|
||||
}
|
||||
}
|
||||
|
||||
return chapter;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<String>> getPageList(String url) async {
|
||||
final res = (await client.get(Uri.parse(url))).body;
|
||||
@@ -318,6 +314,141 @@ class MMRCMS extends MProvider {
|
||||
return Uri.parse(source.baseUrl).resolve(url).toString();
|
||||
}
|
||||
}
|
||||
|
||||
String extractDescription(MDocument document) {
|
||||
final container = document.selectFirst(".row .well");
|
||||
if (container == null) return "";
|
||||
|
||||
String text = container.text;
|
||||
|
||||
container.select("h5").forEach((element) {
|
||||
text = text.replaceAll(element.text, "");
|
||||
});
|
||||
|
||||
return text.replaceAll(RegExp(r'\n{3,}'), '\n\n').trim();
|
||||
}
|
||||
|
||||
String _getOwnText(MElement element) {
|
||||
final text = element.text;
|
||||
final childrenText = element.children.map((e) => e.text).join();
|
||||
return text.replaceFirst(childrenText, '').trim();
|
||||
}
|
||||
|
||||
void _assignMangaInfo(MManga manga, String label, MElement valueElement) {
|
||||
if (_detailAuthor.contains(label)) {
|
||||
manga.author = valueElement.text;
|
||||
} else if (_detailArtist.contains(label)) {
|
||||
manga.artist = valueElement.text;
|
||||
} else if (_detailGenre.contains(label)) {
|
||||
manga.genre = valueElement?.select("a").map((e) => e.text).toList;
|
||||
} else if (_detailStatus.contains(label)) {
|
||||
manga.status = parseStatus(valueElement.text, statusList);
|
||||
}
|
||||
}
|
||||
|
||||
String cleanChapterName(String name, String mangaTitle) {
|
||||
const chapterString = "Chapter";
|
||||
const chapterNamePrefix = "";
|
||||
|
||||
try {
|
||||
final initialName = name.replaceFirst(
|
||||
'$chapterNamePrefix$mangaTitle',
|
||||
chapterString,
|
||||
);
|
||||
|
||||
final parts = initialName.split(':');
|
||||
|
||||
if (parts.isEmpty) return name;
|
||||
|
||||
final firstPart = parts[0].trim();
|
||||
if (parts.length == 1) return firstPart;
|
||||
|
||||
final secondPart = parts.sublist(1).join(':').trim();
|
||||
|
||||
return firstPart == secondPart ? firstPart : "$firstPart: $secondPart";
|
||||
} catch (e) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
const _detailAuthor = {
|
||||
'author(s)',
|
||||
'autor(es)',
|
||||
'auteur(s)',
|
||||
'著作',
|
||||
'yazar(lar)',
|
||||
'mangaka(lar)',
|
||||
'pengarang/penulis',
|
||||
'pengarang',
|
||||
'penulis',
|
||||
'autor',
|
||||
'المؤلف',
|
||||
'перевод',
|
||||
'autor/autorzy',
|
||||
};
|
||||
|
||||
const _detailArtist = {
|
||||
'artist(s)',
|
||||
'artiste(s)',
|
||||
'sanatçi(lar)',
|
||||
'artista(s)',
|
||||
'artist(s)/ilustrator',
|
||||
'الرسام',
|
||||
'seniman',
|
||||
'rysownik/rysownicy',
|
||||
'artista',
|
||||
};
|
||||
|
||||
const _detailGenre = {
|
||||
'categories',
|
||||
'categorías',
|
||||
'catégories',
|
||||
'ジャンル',
|
||||
'kategoriler',
|
||||
'categorias',
|
||||
'kategorie',
|
||||
'التصنيفات',
|
||||
'жанр',
|
||||
'kategori',
|
||||
'tagi',
|
||||
'género',
|
||||
};
|
||||
|
||||
const _detailStatus = {
|
||||
'status',
|
||||
'statut',
|
||||
'estado',
|
||||
'状態',
|
||||
'durum',
|
||||
'الحالة',
|
||||
'статус',
|
||||
};
|
||||
|
||||
const statusList = [
|
||||
{
|
||||
// Ongoing Statuses (0)
|
||||
'ongoing': 0,
|
||||
'مستمرة': 0,
|
||||
'en cours': 0,
|
||||
'em lançamento': 0,
|
||||
'prace w toku': 0,
|
||||
'ativo': 0,
|
||||
'em andamento': 0,
|
||||
'activo': 0,
|
||||
|
||||
// Complete Statuses (1)
|
||||
'complete': 1,
|
||||
'مكتملة': 1,
|
||||
'complet': 1,
|
||||
'completo': 1,
|
||||
'zakończone': 1,
|
||||
'concluído': 1,
|
||||
'finalizado': 1,
|
||||
|
||||
// Dropped Statuses (3)
|
||||
'dropped': 3,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
MMRCMS main(MSource source) {
|
||||
|
||||
Reference in New Issue
Block a user