mangayomi/lib/services/get_manga_detail.dart
kodjodevf d6dec733a7 *fix
2023-04-11 17:38:40 +01:00

612 lines
20 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:mangayomi/models/comick/manga_chapter_detail.dart';
import 'package:mangayomi/models/comick/manga_detail_comick.dart';
import 'package:mangayomi/services/get_popular_manga.dart';
import 'package:mangayomi/services/http_res_to_dom_html.dart';
import 'package:mangayomi/source/source_model.dart';
import 'package:mangayomi/utils/reg_exp_matcher.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'get_manga_detail.g.dart';
class GetMangaDetailModel {
List<String> genre = [];
List<String> chapterTitle = [];
List<String> chapterUrl = [];
List<String> chapterDate = [];
String? author;
String? status;
String? source;
String? url;
String? name;
String? imageUrl;
String? description;
GetMangaDetailModel({
required this.genre,
required this.author,
required this.status,
required this.chapterDate,
required this.chapterTitle,
required this.chapterUrl,
required this.imageUrl,
required this.description,
required this.url,
required this.name,
required this.source,
});
}
_parseStatut(int i) {
if (i == 1) {
return 'Ongoing';
} else if (i == 2) {
return 'Completed';
} else if (i == 3) {
return 'Canceled';
} else if (i == 4) {
return '';
} else {
return 'Unknown';
}
}
Future findCurrentSlug(String oldSlug) async {
var headers = {
'Referer': 'https://comick.app/',
'User-Agent':
'Tachiyomi Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/8\\\$userAgentRandomizer1.0.4\\\$userAgentRandomizer3.1\\\$userAgentRandomizer2 Safari/537.36'
};
var request = http.Request('GET',
Uri.parse('https://api.comick.fun/tachiyomi/mapping?slugs=$oldSlug'));
request.headers.addAll(headers);
http.StreamedResponse response = await request.send();
if (response.statusCode == 200) {
return await response.stream.bytesToString();
} else {
return response.reasonPhrase;
}
}
beautifyChapterName(String? vol, String? chap, String? title, String? lang) {
return "${vol!.isNotEmpty ? chap!.isEmpty ? "Volume $vol " : "Vol. $vol " : ""}${chap!.isNotEmpty ? vol.isEmpty ? lang == "fr" ? "Chapitre $chap" : "Chapter $chap" : "Ch. $chap " : ""}${title!.isNotEmpty ? chap.isEmpty ? title : " : $title" : ""}";
}
@riverpod
Future<GetMangaDetailModel> getMangaDetail(GetMangaDetailRef ref,
{required String imageUrl,
required String url,
required String name,
required String lang,
required String source}) async {
List<String> genre = [];
String? author;
String? status;
List<String> chapterTitle = [];
List<String> chapterUrl = [];
List<String> chapterDate = [];
source = source.toLowerCase();
String? description;
/********/
/*comick*/
/********/
if (getWpMangTypeSource(source) == TypeSource.comick) {
var headers = {
'Referer': 'https://comick.app/',
'User-Agent':
'Tachiyomi Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/8\\\$userAgentRandomizer1.0.4\\\$userAgentRandomizer3.1\\\$userAgentRandomizer2 Safari/537.36'
};
var request = http.Request(
'GET', Uri.parse('https://api.comick.fun$url?tachiyomi=true'));
request.headers.addAll(headers);
http.StreamedResponse response = await request.send();
if (response.statusCode == 200) {
var mangaDetail = jsonDecode(await response.stream.bytesToString())
as Map<String, dynamic>;
var mangaDetailLMap = MangaDetailModelComick.fromJson(mangaDetail);
RegExp regExp = RegExp(r'name:\s*(.*?),');
String authorr =
regExp.firstMatch(mangaDetailLMap.authors![0].toString())?.group(1) ??
'';
String statuss = _parseStatut(mangaDetailLMap.comic!.status!);
status = statuss;
author = authorr;
RegExp regExp1 = RegExp(r'name:\s*(.*?)}');
for (var ok in mangaDetailLMap.genres!) {
genre.add(regExp1.firstMatch(ok.toString())!.group(1)!);
}
description = mangaDetailLMap.comic!.desc;
String tt = await findCurrentSlug(mangaDetailLMap.comic!.slug!);
String mangaId = tt.split('":"').last.replaceAll('"}', '');
String limit = mangaDetailLMap.comic!.chapterCount.toString();
var requestt = http.Request(
'GET',
Uri.parse(
'https://api.comick.fun/comic/$mangaId/chapters?lang=$lang&limit=$limit'));
requestt.headers.addAll(headers);
http.StreamedResponse responsee = await requestt.send();
if (responsee.statusCode == 200) {
List<String> chapterTitles = [];
List<String> chapterUrls = [];
List<String> chapterDates = [];
var chapterDetail = jsonDecode(await responsee.stream.bytesToString())
as Map<String, dynamic>;
var chapterDetailMap = MangaChapterModelComick.fromJson(chapterDetail);
for (var chapter in chapterDetailMap.chapters!) {
chapterUrls.add(
"/comic/${mangaDetailLMap.comic!.slug}/${chapter.hid}-chapter-${chapter.chap}-en");
chapterDates.add(chapter.createdAt!.toString().substring(0, 10));
chapterTitles.add(beautifyChapterName(chapter.vol ?? "",
chapter.chap ?? "", chapter.title ?? "", lang));
}
List<String> chapterTitless = [];
for (var i = 0; i < chapterTitles.length; i++) {
if (!chapterTitless.contains(chapterTitles[i])) {
chapterTitle.add(chapterTitles[i]);
chapterUrl.add(chapterUrls[i]);
chapterDate.add(chapterDates[i].replaceAll('-', "/"));
}
chapterTitless.add(chapterTitles[i]);
}
}
}
}
/*************/
/*mangathemesia*/
/**************/
if (getWpMangTypeSource(source) == TypeSource.mangathemesia) {
final dom = await httpResToDom(url: url, headers: {});
if (dom
.querySelectorAll(
'div.bigcontent, div.animefull, div.main-info, div.postbody')
.isNotEmpty) {
final resHtml = dom.querySelector(
'div.bigcontent, div.animefull, div.main-info, div.postbody');
if (resHtml!.querySelectorAll('.tsinfo .imptdt').isNotEmpty) {
status = resHtml
.querySelectorAll('.tsinfo .imptdt')
.where((e) =>
e.innerHtml.contains("Status") ||
e.innerHtml.contains("Situação"))
.map((e) => e.innerHtml.contains("Situação")
? e.text.replaceAll('Situação', '').trim()
: e.text.replaceAll('Status', '').trim())
.toList()
.last;
} else if (resHtml.querySelectorAll('.infotable tr').isNotEmpty) {
status = resHtml
.querySelectorAll('.infotable tr')
.where((e) =>
e.innerHtml.toLowerCase().contains('statut') ||
e.innerHtml.toLowerCase().contains('status'))
.map((e) => e.querySelector('td:last-child')!.text)
.toList()
.first;
} else if (resHtml.querySelectorAll('.fmed').isNotEmpty) {
status = resHtml
.querySelectorAll('.tsinfo .imptdt')
.map((e) => e.text.replaceAll('Status', '').trim())
.toList()
.first;
} else {
status = "";
}
//2
if (resHtml.querySelectorAll('.fmed').isNotEmpty) {
author = resHtml
.querySelectorAll('.fmed')
.where((e) => e.innerHtml.contains("Author"))
.map((e) => e.text.replaceAll('Author', '').trim())
.toList()
.first;
} else if (resHtml.querySelectorAll('.tsinfo .imptdt').isNotEmpty) {
author = resHtml
.querySelectorAll('.tsinfo .imptdt')
.where((e) =>
e.innerHtml.contains("Author") ||
e.innerHtml.contains("Auteur") ||
e.innerHtml.contains("Autor"))
.map((e) => e.innerHtml.contains("Autor")
? e.text.replaceAll('Autor', '').trim()
: e.innerHtml.contains("Autheur")
? e.text.replaceAll('Auteur', '').trim()
: e.text.replaceAll('Author', '').trim())
.toList()
.first;
} else if (resHtml.querySelectorAll('.infotable tr').isNotEmpty) {
author = resHtml
.querySelectorAll('.infotable tr')
.where((e) =>
e.innerHtml.toLowerCase().contains('auteur') ||
e.innerHtml.toLowerCase().contains('author'))
.map((e) => e.querySelector('td:last-child')!.text)
.toList()
.first;
} else {
author = "";
}
description = resHtml
.querySelector(".desc, .entry-content[itemprop=description]")!
.text;
if (resHtml
.querySelectorAll('div.gnr a, .mgen a, .seriestugenre a')
.isNotEmpty) {
final tt = resHtml
.querySelectorAll('div.gnr a, .mgen a, .seriestugenre a')
.map((e) => e.text.trim())
.toList();
for (var ok in tt) {
genre.add(ok);
}
} else {
genre.add('');
}
if (resHtml.querySelectorAll('#chapterlist a').isNotEmpty) {
final udl = resHtml
.querySelectorAll('#chapterlist a ')
.where((e) => e.attributes.containsKey('href'))
.map((e) => e.attributes['href'])
.toList();
for (var ok in udl) {
chapterUrl.add(ok!);
}
}
if (resHtml.querySelectorAll('.lch a, .chapternum').isNotEmpty) {
final tt = resHtml
.querySelectorAll('.lch a, .chapternum')
.map((e) => e.text.trim())
.toList();
tt.removeWhere((element) => element.contains('{{number}}'));
for (var ok in tt) {
chapterTitle.add(ok.trimLeft());
}
}
if (resHtml.querySelectorAll('.chapterdate').isNotEmpty) {
final tt = resHtml
.querySelectorAll('.chapterdate')
.map((e) => e.text.trim())
.toList();
tt.removeWhere((element) => element.contains('{{date}}'));
for (var ok in tt) {
chapterDate.add(ok);
}
}
}
}
/***********/
/*mangakawaii*/
/***********/
else if (source == "mangakawaii") {
final dom = await httpResToDom(
url: 'https://www.mangakawaii.io$url',
headers: {"Accept-Language": "fr"});
List detail = [];
imageUrl =
"https://cdn.mangakawaii.pics/uploads$url/cover/cover_250x350.jpg";
if (dom.querySelectorAll('dd.text-justify.text-break').isNotEmpty) {
final tt = dom
.querySelectorAll('dd.text-justify.text-break')
.map((e) => e.text.trim())
.toList();
description = tt[0];
}
if (dom
.querySelectorAll('span.badge.bg-success.text-uppercase')
.isNotEmpty) {
final tt = dom
.querySelectorAll('span.badge.bg-success.text-uppercase')
.map((e) => e.text.trim())
.toList();
detail.add(tt[0]);
} else {
detail.add("");
}
if (dom.querySelectorAll('a[href*=author]').isNotEmpty) {
final tt = dom
.querySelectorAll('a[href*=author]')
.map((e) => e.text.trim())
.toList();
detail.add(tt[0]);
} else {
detail.add("");
}
if (dom.querySelectorAll('a[href*=category]').isNotEmpty) {
final tt = dom
.querySelectorAll('a[href*=category]')
.map((e) => e.text.trim())
.toList();
for (var ok in tt) {
genre.add(ok);
}
}
detail = detail.toSet().toList();
status = detail[0];
author = detail[1];
if (dom.querySelectorAll("tr[class*='volume-']").isNotEmpty) {
final url = dom.querySelectorAll("tr[class*='volume-']").map((e) {
RegExp exp = RegExp(r'<a href="([^"]+)"');
Iterable<Match> matches = exp.allMatches(e.outerHtml);
String? firstMatch = matches.first.group(1);
return firstMatch;
}).toList();
final htm = await httpResToDom(
url: 'https://www.mangakawaii.io${url[0]}',
headers: {"Accept-Language": "fr"});
if (htm
.querySelectorAll(
'#bottom_nav_reader > div > div > ul.chapter-pager.navbar-nav > li.nav-item.dropup.d-inline-block > ul > li > a')
.isNotEmpty) {
final tt = htm
.querySelectorAll(
'#bottom_nav_reader > div > div > ul.chapter-pager.navbar-nav > li.nav-item.dropup.d-inline-block > ul > li > a')
.map((e) => e.innerHtml)
.toList();
final urlz = htm
.querySelectorAll(
"#bottom_nav_reader > div > div > ul.chapter-pager.navbar-nav > li.nav-item.dropup.d-inline-block > ul > li ")
.map((e) => e.innerHtml)
.toList();
for (var ok in urlz) {
chapterUrl.add(ok.split('href="')[1].split('"').first);
}
for (var ok in tt) {
chapterTitle.add(ok);
}
if (dom.querySelectorAll("tr[class*='volume-']").isNotEmpty) {
final url = dom
.querySelectorAll("tr[class*='volume-']")
.map((e) => e
.querySelectorAll('td.table__date')
.map((e) => e.text.trim())
.toList()[0])
.toList();
if (urlz.length > url.length) {
for (var _ in urlz) {
chapterDate.add(DateTime.now()
.toString()
.substring(0, 10)
.replaceAll('-', "/"));
}
} else {
for (var ok in url) {
chapterDate.add(ok
.split(" ")
.first
.toString()
.substring(0, 10)
.replaceAll('.', "/"));
}
}
}
}
}
}
/***********/
/*mmrcms*/
/***********/
else if (getWpMangTypeSource(source) == TypeSource.mmrcms) {
final dom = await httpResToDom(url: url, headers: {});
description = dom
.querySelectorAll('.row .well p')
.map((e) => e.text.trim())
.toList()
.first;
status = dom
.querySelectorAll('.row .dl-horizontal dt')
.where((e) =>
e.innerHtml.toString().toLowerCase().contains("status") ||
e.innerHtml.toString().toLowerCase().contains("statut") ||
e.innerHtml.toString().toLowerCase().contains("estado") ||
e.innerHtml.toString().toLowerCase().contains("durum"))
.map((e) => e.nextElementSibling!.text.trim())
.toList()
.first;
if (dom.querySelectorAll(".row .dl-horizontal dt").isNotEmpty) {
author = dom
.querySelectorAll('.row .dl-horizontal dt')
.where((e) =>
e.innerHtml.toString().toLowerCase().contains("auteur(s)") ||
e.innerHtml.toString().toLowerCase().contains("author(s)") ||
e.innerHtml.toString().toLowerCase().contains("autor(es)") ||
e.innerHtml.toString().toLowerCase().contains("yazar(lar)") ||
e.innerHtml.toString().toLowerCase().contains("mangaka(lar)") ||
e.innerHtml
.toString()
.toLowerCase()
.contains("pengarang/penulis") ||
e.innerHtml.toString().toLowerCase().contains("autor") ||
e.innerHtml.toString().toLowerCase().contains("penulis"))
.map((e) => e.nextElementSibling!.text
.trim()
.replaceAll(RegExp(r"\s+\b|\b\s"), ""))
.toList()
.first;
final genr = dom
.querySelectorAll('.row .dl-horizontal dt')
.where((e) =>
e.innerHtml.toString().toLowerCase().contains("categories") ||
e.innerHtml.toString().toLowerCase().contains("categorías") ||
e.innerHtml.toString().toLowerCase().contains("catégories") ||
e.innerHtml.toString().toLowerCase().contains("kategoriler") ||
e.innerHtml.toString().toLowerCase().contains("categorias") ||
e.innerHtml.toString().toLowerCase().contains("kategorie") ||
e.innerHtml.toString().toLowerCase().contains("kategori") ||
e.innerHtml.toString().toLowerCase().contains("tagi"))
.map((e) => e.nextElementSibling!.text.trim())
.toList();
if (genr.isNotEmpty) {
genre = genr.first.replaceAll(RegExp(r"\s+\b|\b\s"), "").split(',');
}
}
final rrr = dom.querySelectorAll(".row [class^=img-responsive]");
final data = rrr.map((e) => e.outerHtml).toList();
if (source.toLowerCase() == 'jpmangas' ||
source.toLowerCase() == 'fr scan') {
imageUrl = regSrcMatcher(data.first).replaceAll('//', 'https://');
} else {
imageUrl = regSrcMatcher(data.first);
}
final ttt = dom
.querySelectorAll("ul[class^=chapters] > li:not(.btn), table.table tr");
if (ttt.isNotEmpty) {
final data = ttt
.map((e) => e.querySelector("[class^=chapter-title-rtl]")!)
.toList();
var name = data;
for (var iaa in name) {
chapterTitle.add(iaa.getElementsByTagName("a").first.text);
chapterUrl
.add(regHrefMatcher(iaa.getElementsByTagName("a").first.outerHtml));
}
final date = ttt
.map((e) => e
.getElementsByClassName("date-chapter-title-rtl")
.map((e) => e.text.trim())
.first)
.toList();
for (var da in date) {
chapterDate.add(da);
}
}
}
/***********/
/*mangahere*/
/***********/
else if (source == "mangahere") {
final dom = await httpResToDom(
url: "http://www.mangahere.cc$url",
headers: {
"Referer": "https://www.mangahere.cc/",
"Cookie": "isAdult=1"
});
if (dom
.querySelectorAll(
' body > div > div > div.detail-info-right > p.detail-info-right-title > span.detail-info-right-title-tip')
.isNotEmpty) {
final tt = dom
.querySelectorAll(
' body > div > div > div.detail-info-right > p.detail-info-right-title > span.detail-info-right-title-tip')
.map((e) => e.text.trim())
.toList();
status = tt[0];
} else {
status = "";
}
if (dom
.querySelectorAll(
' body > div > div > div.detail-info-right > p.detail-info-right-say > a')
.isNotEmpty) {
final tt = dom
.querySelectorAll(
' body > div > div > div.detail-info-right > p.detail-info-right-say > a')
.map((e) => e.text.trim())
.toList();
author = tt[0];
} else {
author = "";
}
if (dom
.querySelectorAll(
'body > div > div > div.detail-info-right > p.detail-info-right-content')
.isNotEmpty) {
final tt = dom
.querySelectorAll(
'body > div > div > div.detail-info-right > p.detail-info-right-content')
.map((e) => e.text.trim())
.toList();
description = tt.first;
}
if (dom.querySelectorAll('ul > li > a').isNotEmpty) {
final udl = dom
.querySelectorAll('ul > li > a ')
.where((e) => e.attributes.containsKey('href'))
.map((e) => e.attributes['href'])
.toList();
for (var ok in udl) {
chapterUrl.add(ok!);
}
}
if (dom.querySelectorAll('ul > li > a > div > p.title3').isNotEmpty) {
final tt = dom
.querySelectorAll('ul > li > a > div > p.title3')
.map((e) => e.text.trim())
.toList();
for (var ok in tt) {
chapterTitle.add(ok);
}
}
if (dom.querySelectorAll('ul > li > a > div > p.title2').isNotEmpty) {
final tt = dom
.querySelectorAll('ul > li > a > div > p.title2')
.map((e) => e.text.trim())
.toList();
for (var ok in tt) {
chapterDate.add(ok);
}
}
if (dom
.querySelectorAll(
' body > div > div > div.detail-info-right > p.detail-info-right-tag-list > a')
.isNotEmpty) {
final tt = dom
.querySelectorAll(
' body > div > div > div.detail-info-right > p.detail-info-right-tag-list > a')
.map((e) => e.text.trim())
.toList();
for (var ok in tt) {
genre.add(ok);
}
}
}
return GetMangaDetailModel(
chapterDate: chapterDate,
chapterTitle: chapterTitle,
chapterUrl: chapterUrl,
status: status,
genre: genre,
author: author,
description: description,
name: name,
url: url,
source: source,
imageUrl: imageUrl,
);
}