mirror of
https://github.com/kodjodevf/mangayomi.git
synced 2026-03-11 21:35:32 +00:00
refactor code
This commit is contained in:
parent
a27cd5ae8d
commit
f7affe2114
44 changed files with 1992 additions and 1590 deletions
|
|
@ -1,5 +1,4 @@
|
|||
// ignore_for_file: depend_on_referenced_packages
|
||||
import 'dart:developer';
|
||||
import 'dart:io';
|
||||
import 'package:fast_cached_network_image/fast_cached_network_image.dart';
|
||||
import 'package:flex_color_scheme/flex_color_scheme.dart';
|
||||
|
|
@ -16,7 +15,7 @@ import 'package:mangayomi/models/history.dart';
|
|||
import 'package:mangayomi/utils/constant.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/router/router.dart';
|
||||
import 'package:mangayomi/source/source_model.dart';
|
||||
import 'package:mangayomi/models/source_model.dart';
|
||||
import 'package:mangayomi/views/manga/reader/providers/reader_controller_provider.dart';
|
||||
import 'package:mangayomi/views/more/settings/appearance/providers/blend_level_state_provider.dart';
|
||||
import 'package:mangayomi/views/more/settings/appearance/providers/flex_scheme_color_state_provider.dart';
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:mangayomi/models/download_model.dart';
|
||||
import 'package:mangayomi/utils/constant.dart';
|
||||
import 'package:mangayomi/source/source_model.dart';
|
||||
import 'package:mangayomi/models/source_model.dart';
|
||||
import 'package:mangayomi/views/manga/reader/providers/reader_controller_provider.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,31 +1,28 @@
|
|||
// ignore_for_file: depend_on_referenced_packages
|
||||
// ignore_for_file: depend_o
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'package:html/dom.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:html/dom.dart' as dom;
|
||||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/models/comick/chapter_page_comick.dart';
|
||||
import 'package:mangayomi/models/source_model.dart';
|
||||
import 'package:mangayomi/providers/hive_provider.dart';
|
||||
import 'package:mangayomi/providers/storage_provider.dart';
|
||||
import 'package:mangayomi/services/http_service/cloudflare/cloudflare_bypass.dart';
|
||||
import 'package:mangayomi/services/get_popular_manga.dart';
|
||||
import 'package:mangayomi/services/http_service/http_service.dart';
|
||||
import 'package:mangayomi/source/source_model.dart';
|
||||
import 'package:mangayomi/sources/src/all/comick/src/comick.dart';
|
||||
import 'package:mangayomi/sources/src/en/mangahere/src/mangahere.dart';
|
||||
import 'package:mangayomi/sources/src/fr/japscan/src/japscan.dart';
|
||||
import 'package:mangayomi/sources/src/fr/mangakawaii/src/mangakawaii.dart';
|
||||
import 'package:mangayomi/sources/src/multi/mangathemesia/src/mangathemesia.dart';
|
||||
import 'package:mangayomi/sources/src/multi/mmrcms/src/mmrcms.dart';
|
||||
import 'package:mangayomi/sources/utils/utils.dart';
|
||||
import 'package:mangayomi/utils/reg_exp_matcher.dart';
|
||||
import 'package:mangayomi/views/more/settings/providers/incognito_mode_state_provider.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
import 'package:flutter_js/flutter_js.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
part 'get_manga_chapter_url.g.dart';
|
||||
|
||||
class GetMangaChapterUrlModel {
|
||||
Directory? path;
|
||||
List urll = [];
|
||||
List pageUrls = [];
|
||||
List<bool> isLocaleList = [];
|
||||
GetMangaChapterUrlModel(
|
||||
{required this.path, required this.urll, required this.isLocaleList});
|
||||
{required this.path, required this.pageUrls, required this.isLocaleList});
|
||||
}
|
||||
|
||||
@riverpod
|
||||
|
|
@ -33,127 +30,35 @@ Future<GetMangaChapterUrlModel> getMangaChapterUrl(
|
|||
GetMangaChapterUrlRef ref, {
|
||||
required Chapter chapter,
|
||||
}) async {
|
||||
bool isOk = false;
|
||||
Directory? path;
|
||||
List urll = [];
|
||||
String? baseUrl;
|
||||
String? zjsUrl;
|
||||
List pageUrls = [];
|
||||
final manga = chapter.manga.value!;
|
||||
zjs() async {
|
||||
final html = await cloudflareBypassHtml(
|
||||
url: zjsUrl!, source: manga.source!.toLowerCase(), useUserAgent: true);
|
||||
dom.Document htmll = dom.Document.html(baseUrl!);
|
||||
final strings = html
|
||||
.replaceAll(RegExp(r'\\[(.*?)\\]'), '')
|
||||
.split(",")
|
||||
.map((s) => s.trim().replaceAll("'", "").split('').reversed.join());
|
||||
final stringLookupTables = strings
|
||||
.where((s) =>
|
||||
s.length == 62 &&
|
||||
s.split('').toSet().toList().sorted().join() ==
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
|
||||
.toList();
|
||||
|
||||
if (stringLookupTables.length != 2) {
|
||||
throw Exception("Expected only two lookup tables in ZJS");
|
||||
}
|
||||
|
||||
final scrambledData =
|
||||
htmll.getElementById("data")!.attributes['data-data']!;
|
||||
|
||||
for (var i = 0; i <= 1; i++) {
|
||||
final otherIndex = i == 0 ? 1 : 0;
|
||||
|
||||
final lookupTable = Map.fromIterables(stringLookupTables[i].split(''),
|
||||
stringLookupTables[otherIndex].split(''));
|
||||
try {
|
||||
final unscrambledData = scrambledData
|
||||
.split('')
|
||||
.map((char) => lookupTable[char] ?? char)
|
||||
.join();
|
||||
final decoded = utf8.decode(base64.decode(unscrambledData));
|
||||
final data = jsonDecode(decoded);
|
||||
urll = data["imagesLink"].map((it) => it).toList();
|
||||
} catch (_) {}
|
||||
}
|
||||
isOk = true;
|
||||
}
|
||||
|
||||
List<bool> isLocaleList = [];
|
||||
String source = manga.source!.toLowerCase();
|
||||
List pagesUrl = ref.watch(hiveBoxMangaProvider).get(
|
||||
List hivePagesUrls = ref.watch(hiveBoxMangaProvider).get(
|
||||
"${manga.lang}-${manga.source}/${manga.name}/${chapter.name}-pageurl",
|
||||
defaultValue: []);
|
||||
final incognitoMode = ref.watch(incognitoModeStateProvider);
|
||||
path = await StorageProvider().getMangaChapterDirectory(chapter);
|
||||
|
||||
if (pagesUrl.isNotEmpty) {
|
||||
urll = pagesUrl;
|
||||
if (hivePagesUrls.isNotEmpty) {
|
||||
pageUrls = hivePagesUrls;
|
||||
}
|
||||
|
||||
/*********/
|
||||
/*comick*/
|
||||
/********/
|
||||
else if (getWpMangTypeSource(source) == TypeSource.comick) {
|
||||
String mangaId = chapter.url!.split('/').last.split('-').first;
|
||||
|
||||
final response = await httpGet(
|
||||
url: 'https://api.comick.fun/chapter/$mangaId?tachiyomi=true',
|
||||
source: source,
|
||||
resDom: false) as String?;
|
||||
var data = jsonDecode(response!) as Map<String, dynamic>;
|
||||
var page = ChapterPageComick.fromJson(data);
|
||||
for (var url in page.chapter!.images!) {
|
||||
urll.add(url.url);
|
||||
}
|
||||
else if (getWpMangTypeSource(source) == TypeSource.comick) {
|
||||
pageUrls = await Comick().getMangaChapterUrl(chapter: chapter);
|
||||
}
|
||||
|
||||
/*************/
|
||||
/*mangathemesia*/
|
||||
/**************/
|
||||
|
||||
else if (getWpMangTypeSource(source) == TypeSource.mangathemesia) {
|
||||
final dom = await httpGet(
|
||||
useUserAgent: true,
|
||||
url: chapter.url!,
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
if (dom!.querySelectorAll('#readerarea').isNotEmpty) {
|
||||
final ta =
|
||||
dom.querySelectorAll('#readerarea').map((e) => e.outerHtml).toList();
|
||||
final RegExp regex = RegExp(r'<img[^>]+src="([^"]+)"');
|
||||
final Iterable<Match> matches = regex.allMatches(ta.first);
|
||||
|
||||
final List<String?> urls = matches.map((m) => m.group(1)).toList();
|
||||
Iterable<Match> matchess = [];
|
||||
if (dom.querySelectorAll(' #select-paged ').isNotEmpty) {
|
||||
final ee = dom
|
||||
.querySelectorAll(' #select-paged ')
|
||||
.map((e) => e.outerHtml)
|
||||
.toList();
|
||||
final RegExp regexx = RegExp(r'value="([^"]+)"');
|
||||
matchess = regexx.allMatches(ee.first);
|
||||
}
|
||||
|
||||
final List<String?> urlss = matchess.map((m) => m.group(1)).toList();
|
||||
if (urls.length == 1 && urls.isNotEmpty) {
|
||||
for (var i = 0; i < urlss.length; i++) {
|
||||
if (urlss[i]!.length == 1) {
|
||||
urll.add(
|
||||
urls.first!.replaceAll("001", '00${int.parse(urlss[i]!) + 1}'));
|
||||
} else if (urlss[i]!.length == 2) {
|
||||
urll.add(
|
||||
urls.first!.replaceAll("001", '0${int.parse(urlss[i]!) + 1}'));
|
||||
} else if (urlss[i]!.length == 3) {
|
||||
urll.add(
|
||||
urls.first!.replaceAll("001", '${int.parse(urlss[i]!) + 1}'));
|
||||
}
|
||||
}
|
||||
} else if (urls.length > 1 && urls.isNotEmpty) {
|
||||
for (var tt in urls) {
|
||||
urll.add(tt);
|
||||
}
|
||||
}
|
||||
}
|
||||
pageUrls = await MangaThemeSia().getMangaChapterUrl(chapter: chapter);
|
||||
}
|
||||
|
||||
/***********/
|
||||
|
|
@ -161,25 +66,7 @@ Future<GetMangaChapterUrlModel> getMangaChapterUrl(
|
|||
/***********/
|
||||
|
||||
else if (source == 'mangakawaii') {
|
||||
final response =
|
||||
await httpGet(url: chapter.url!, source: source, resDom: false)
|
||||
as String?;
|
||||
var chapterSlug = RegExp("""var chapter_slug = "([^"]*)";""")
|
||||
.allMatches(response!)
|
||||
.last
|
||||
.group(1);
|
||||
var mangaSlug = RegExp("""var oeuvre_slug = "([^"]*)";""")
|
||||
.allMatches(response)
|
||||
.last
|
||||
.group(1);
|
||||
var pages = RegExp('''"page_image":"([^"]*)"''')
|
||||
.allMatches(response)
|
||||
.map((e) => e.group(1));
|
||||
|
||||
for (var tt in pages) {
|
||||
urll.add(
|
||||
'https://cdn.mangakawaii.pics/uploads/manga/$mangaSlug/chapters_fr/$chapterSlug/$tt');
|
||||
}
|
||||
pageUrls = await MangaKawaii().getMangaChapterUrl(chapter: chapter);
|
||||
}
|
||||
|
||||
/***********/
|
||||
|
|
@ -187,168 +74,32 @@ Future<GetMangaChapterUrlModel> getMangaChapterUrl(
|
|||
/***********/
|
||||
|
||||
else if (getWpMangTypeSource(source) == TypeSource.mmrcms) {
|
||||
final dom = await httpGet(
|
||||
useUserAgent: true,
|
||||
url: chapter.url!,
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
if (dom!.querySelectorAll('#all > .img-responsive').isNotEmpty) {
|
||||
urll = dom.querySelectorAll('#all > .img-responsive').map((e) {
|
||||
final RegExp regexx = RegExp(r'data-src="([^"]+)"');
|
||||
if (manga.source!.toLowerCase() == 'jpmangas' ||
|
||||
manga.source!.toLowerCase() == 'fr scan') {
|
||||
return regexx
|
||||
.allMatches(e.outerHtml)
|
||||
.first
|
||||
.group(1)!
|
||||
.replaceAll('//', 'https://')
|
||||
.replaceAll(RegExp(r"\s+\b|\b\s"), "");
|
||||
}
|
||||
return regexx
|
||||
.allMatches(e.outerHtml)
|
||||
.first
|
||||
.group(1)!
|
||||
.replaceAll(RegExp(r"\s+\b|\b\s"), "");
|
||||
}).toList();
|
||||
}
|
||||
pageUrls = await Mmrcms().getMangaChapterUrl(chapter: chapter);
|
||||
}
|
||||
|
||||
/***********/
|
||||
/*mangahere*/
|
||||
/***********/
|
||||
|
||||
else if (source == 'mangahere') {
|
||||
JavascriptRuntime? flutterJs;
|
||||
flutterJs = getJavascriptRuntime();
|
||||
extractSecretKey(String response, JavascriptRuntime? flutterJs) {
|
||||
var secretKeyScriptLocation =
|
||||
response.indexOf("eval(function(p,a,c,k,e,d)");
|
||||
var secretKeyScriptEndLocation =
|
||||
response.indexOf("</script>", secretKeyScriptLocation);
|
||||
var secretKeyScript = response
|
||||
.substring(secretKeyScriptLocation, secretKeyScriptEndLocation)
|
||||
.replaceAll("eval", "");
|
||||
var secretKeyDeobfuscatedScript =
|
||||
flutterJs!.evaluate(secretKeyScript).toString();
|
||||
var secretKeyStartLoc = secretKeyDeobfuscatedScript.indexOf("'");
|
||||
var secretKeyEndLoc = secretKeyDeobfuscatedScript.indexOf(";");
|
||||
|
||||
var secretKeyResultScript = secretKeyDeobfuscatedScript.substring(
|
||||
secretKeyStartLoc, secretKeyEndLoc);
|
||||
|
||||
return secretKeyResultScript;
|
||||
}
|
||||
|
||||
var link = "http://www.mangahere.cc${chapter.url!}";
|
||||
final response =
|
||||
await httpGet(url: link, source: source, resDom: false) as String?;
|
||||
|
||||
dom.Document htmll = dom.Document.html(response!);
|
||||
int? pagesNumber = -1;
|
||||
if (htmll.querySelectorAll('body > div > div > span > a:').isNotEmpty) {
|
||||
final ta = htmll
|
||||
.querySelectorAll('body > div > div > span > a:')
|
||||
.map((e) => e.text.trim())
|
||||
.toList();
|
||||
ta.removeLast();
|
||||
pagesNumber = int.parse(ta.last);
|
||||
}
|
||||
if (pagesNumber == -1) {
|
||||
final script = htmll
|
||||
.getElementsByTagName("script")
|
||||
.firstWhere((e) => e.innerHtml.contains(
|
||||
"function(p,a,c,k,e,d)",
|
||||
))
|
||||
.innerHtml
|
||||
.replaceAll("eval", "");
|
||||
|
||||
String deobfuscatedScript = flutterJs.evaluate(script).toString();
|
||||
List<String> urlss = deobfuscatedScript
|
||||
.substring(
|
||||
deobfuscatedScript.indexOf("newImgs=['") + "newImgs=['".length,
|
||||
deobfuscatedScript.indexOf("'];"))
|
||||
.split("','");
|
||||
for (var tt in urlss) {
|
||||
urll.add("https:$tt");
|
||||
}
|
||||
} else {
|
||||
var secretKey = extractSecretKey(response, flutterJs);
|
||||
|
||||
var chapterIdStartLoc = response.indexOf("chapterid");
|
||||
var chapterId = response
|
||||
.substring(
|
||||
chapterIdStartLoc + 11, response.indexOf(";", chapterIdStartLoc))
|
||||
.trim();
|
||||
|
||||
var pageBase = link.substring(0, link.lastIndexOf("/"));
|
||||
|
||||
for (int i = 1; i <= pagesNumber; i++) {
|
||||
var pageLink =
|
||||
"$pageBase/chapterfun.ashx?cid=$chapterId&page=$i&key=$secretKey";
|
||||
var responseText = "";
|
||||
|
||||
for (int tr = 1; tr <= 3; tr++) {
|
||||
var response = await http.get(Uri.parse(pageLink), headers: {
|
||||
"Referer": link,
|
||||
"Accept": "*/*",
|
||||
"Accept-Language": "en-US,en;q=0.9",
|
||||
"Connection": "keep-alive",
|
||||
"Host": "www.mangahere.cc",
|
||||
"X-Requested-With": "XMLHttpRequest"
|
||||
});
|
||||
responseText = response.body;
|
||||
if (responseText.isNotEmpty) {
|
||||
break;
|
||||
} else {
|
||||
secretKey = "";
|
||||
}
|
||||
}
|
||||
|
||||
var deobfuscatedScript =
|
||||
flutterJs.evaluate(responseText.replaceAll("eval", "")).toString();
|
||||
|
||||
var baseLinkStartPos = deobfuscatedScript.indexOf("pix=") + 5;
|
||||
var baseLinkEndPos =
|
||||
deobfuscatedScript.indexOf(";", baseLinkStartPos) - 1;
|
||||
var baseLink =
|
||||
deobfuscatedScript.substring(baseLinkStartPos, baseLinkEndPos);
|
||||
|
||||
var imageLinkStartPos = deobfuscatedScript.indexOf("pvalue=") + 9;
|
||||
var imageLinkEndPos =
|
||||
deobfuscatedScript.indexOf("\"", imageLinkStartPos);
|
||||
var imageLink =
|
||||
deobfuscatedScript.substring(imageLinkStartPos, imageLinkEndPos);
|
||||
urll.add("https:$baseLink$imageLink");
|
||||
}
|
||||
|
||||
flutterJs.dispose();
|
||||
}
|
||||
} else if (source == 'japscan') {
|
||||
final response = await httpGet(
|
||||
useUserAgent: true,
|
||||
url: chapter.url!,
|
||||
source: source,
|
||||
resDom: false) as String?;
|
||||
RegExp regex = RegExp(r'<script src="/zjs/(.*?)"');
|
||||
Match? match = regex.firstMatch(response!);
|
||||
String zjsurl = match!.group(1)!;
|
||||
baseUrl = response;
|
||||
zjsUrl = "https://www.japscan.lol/zjs/$zjsurl";
|
||||
zjs();
|
||||
await Future.doWhile(() async {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
if (isOk == true) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
pageUrls = await Mangahere().getMangaChapterUrl(chapter: chapter);
|
||||
}
|
||||
if (urll.isNotEmpty) {
|
||||
|
||||
/***********/
|
||||
/*japscan*/
|
||||
/***********/
|
||||
|
||||
else if (source == 'japscan') {
|
||||
pageUrls = await Japscan().getMangaChapterUrl(chapter: chapter);
|
||||
}
|
||||
|
||||
if (pageUrls.isNotEmpty) {
|
||||
if (!incognitoMode) {
|
||||
ref.watch(hiveBoxMangaProvider).put(
|
||||
"${manga.lang}-${manga.source}/${manga.name}/${chapter.name}-pageurl",
|
||||
urll);
|
||||
pageUrls);
|
||||
}
|
||||
for (var i = 0; i < urll.length; i++) {
|
||||
for (var i = 0; i < pageUrls.length; i++) {
|
||||
if (await File("${path!.path}" "${padIndex(i + 1)}.jpg").exists()) {
|
||||
isLocaleList.add(true);
|
||||
} else {
|
||||
|
|
@ -358,5 +109,5 @@ Future<GetMangaChapterUrlModel> getMangaChapterUrl(
|
|||
}
|
||||
|
||||
return GetMangaChapterUrlModel(
|
||||
path: path, urll: urll, isLocaleList: isLocaleList);
|
||||
path: path, pageUrls: pageUrls, isLocaleList: isLocaleList);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ part of 'get_manga_chapter_url.dart';
|
|||
// **************************************************************************
|
||||
|
||||
String _$getMangaChapterUrlHash() =>
|
||||
r'bb23f4789336a4970dddaaf61707998a9c79bcb5';
|
||||
r'4daf1dc296255c64ca0ee2cf963dd98b3595d93c';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -1,89 +1,16 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
import 'package:html/dom.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:mangayomi/models/chapter.dart';
|
||||
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_service/http_res_to_dom_html.dart';
|
||||
import 'package:mangayomi/services/http_service/http_service.dart';
|
||||
import 'package:mangayomi/source/source_model.dart';
|
||||
import 'package:mangayomi/utils/headers.dart';
|
||||
import 'package:mangayomi/utils/reg_exp_matcher.dart';
|
||||
import 'package:mangayomi/models/source_model.dart';
|
||||
import 'package:mangayomi/sources/service/service.dart';
|
||||
import 'package:mangayomi/sources/src/all/comick/src/comick.dart';
|
||||
import 'package:mangayomi/sources/src/en/mangahere/src/mangahere.dart';
|
||||
import 'package:mangayomi/sources/src/fr/japscan/src/japscan.dart';
|
||||
import 'package:mangayomi/sources/src/fr/mangakawaii/src/mangakawaii.dart';
|
||||
import 'package:mangayomi/sources/src/multi/mangathemesia/src/mangathemesia.dart';
|
||||
import 'package:mangayomi/sources/src/multi/mmrcms/src/mmrcms.dart';
|
||||
import 'package:mangayomi/sources/utils/utils.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
part 'get_manga_detail.g.dart';
|
||||
|
||||
class GetMangaDetailModel {
|
||||
List<String> genre = [];
|
||||
List<Chapter> chapters = [];
|
||||
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.chapters,
|
||||
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 request = http.Request('GET',
|
||||
Uri.parse('https://api.comick.fun/tachiyomi/mapping?slugs=$oldSlug'));
|
||||
|
||||
request.headers.addAll(headers("comick"));
|
||||
|
||||
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" : ""}";
|
||||
}
|
||||
|
||||
String utilDate(String data) {
|
||||
DateTime date = DateTime.parse(data);
|
||||
return date.millisecondsSinceEpoch.toString();
|
||||
}
|
||||
|
||||
parseDate(String data, String source) {
|
||||
source = source.toLowerCase();
|
||||
DateTime date = DateFormat(getFormatDate(source), getFormatDateLocale(source))
|
||||
.parse(data);
|
||||
return date.millisecondsSinceEpoch.toString();
|
||||
}
|
||||
|
||||
@riverpod
|
||||
Future<GetMangaDetailModel> getMangaDetail(GetMangaDetailRef ref,
|
||||
{required String imageUrl,
|
||||
|
|
@ -91,305 +18,30 @@ Future<GetMangaDetailModel> getMangaDetail(GetMangaDetailRef ref,
|
|||
required String title,
|
||||
required String lang,
|
||||
required String source}) async {
|
||||
List<String> genre = [];
|
||||
String? author;
|
||||
String? status;
|
||||
List<String> chapterTitle = [];
|
||||
List<String> chapterUrl = [];
|
||||
List<String> chapterDate = [];
|
||||
String? description;
|
||||
List<Chapter> chapters = [];
|
||||
List<String> scanlators = [];
|
||||
GetMangaDetailModel? mangadetail;
|
||||
|
||||
/********/
|
||||
/*comick*/
|
||||
/********/
|
||||
|
||||
if (getWpMangTypeSource(source.toLowerCase()) == TypeSource.comick) {
|
||||
final response = await httpGet(
|
||||
url: 'https://api.comick.fun$url?tachiyomi=true',
|
||||
source: source,
|
||||
resDom: false) as String?;
|
||||
var mangaDetail = jsonDecode(response!) 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();
|
||||
|
||||
final responsee = await httpGet(
|
||||
url:
|
||||
'https://api.comick.fun/comic/$mangaId/chapters?lang=$lang&limit=$limit',
|
||||
source: source,
|
||||
resDom: false) as String?;
|
||||
var chapterDetail = jsonDecode(responsee!) as Map<String, dynamic>;
|
||||
var chapterDetailMap = MangaChapterModelComick.fromJson(chapterDetail);
|
||||
for (var chapter in chapterDetailMap.chapters!) {
|
||||
scanlators.add(chapter.groupName!.isNotEmpty
|
||||
? chapter.groupName!.first.toString() != 'null'
|
||||
? chapter.groupName!.first
|
||||
: ""
|
||||
: "");
|
||||
chapterUrl.add(
|
||||
"/comic/${mangaDetailLMap.comic!.slug}/${chapter.hid}-chapter-${chapter.chap}-en");
|
||||
chapterDate.add(parseDate(chapter.createdAt!, source));
|
||||
|
||||
chapterTitle.add(beautifyChapterName(
|
||||
chapter.vol ?? "", chapter.chap ?? "", chapter.title ?? "", lang));
|
||||
}
|
||||
mangadetail = await Comick().getMangaDetail(
|
||||
imageUrl: imageUrl, url: url, title: title, lang: lang, source: source);
|
||||
}
|
||||
/*************/
|
||||
/*mangathemesia*/
|
||||
/**************/
|
||||
|
||||
if (getWpMangTypeSource(source.toLowerCase()) == TypeSource.mangathemesia) {
|
||||
final dom = await httpGet(
|
||||
url: url,
|
||||
source: source,
|
||||
resDom: true,
|
||||
useUserAgent: true) as Document?;
|
||||
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(parseDate(ok, source));
|
||||
}
|
||||
}
|
||||
}
|
||||
mangadetail = await MangaThemeSia().getMangaDetail(
|
||||
imageUrl: imageUrl, url: url, title: title, lang: lang, source: source);
|
||||
}
|
||||
/***********/
|
||||
/*mangakawaii*/
|
||||
/***********/
|
||||
else if (source.toLowerCase() == "mangakawaii") {
|
||||
final dom = await httpGet(
|
||||
url: 'https://www.mangakawaii.io$url',
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
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(parseDate(
|
||||
"${DateTime.now().day}.${DateTime.now().month}.${DateTime.now().year}",
|
||||
source));
|
||||
}
|
||||
} else {
|
||||
for (var ok in url) {
|
||||
chapterDate.add(parseDate(
|
||||
ok.split(" ").first.toString().substring(0, 10), source));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mangadetail = await MangaKawaii().getMangaDetail(
|
||||
imageUrl: imageUrl, url: url, title: title, lang: lang, source: source);
|
||||
}
|
||||
|
||||
/***********/
|
||||
|
|
@ -397,293 +49,25 @@ Future<GetMangaDetailModel> getMangaDetail(GetMangaDetailRef ref,
|
|||
/***********/
|
||||
|
||||
else if (getWpMangTypeSource(source.toLowerCase()) == TypeSource.mmrcms) {
|
||||
final dom =
|
||||
await httpGet(url: url, source: source, resDom: true) as Document?;
|
||||
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(parseDate(da, source));
|
||||
}
|
||||
}
|
||||
mangadetail = await Mmrcms().getMangaDetail(
|
||||
imageUrl: imageUrl, url: url, title: title, lang: lang, source: source);
|
||||
}
|
||||
|
||||
/***********/
|
||||
/*mangahere*/
|
||||
/***********/
|
||||
else if (source.toLowerCase() == "mangahere") {
|
||||
final dom = await httpGet(
|
||||
url: "http://www.mangahere.cc$url",
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
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(parseDate(ok, source));
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
} else if (source.toLowerCase() == "japscan") {
|
||||
final dom =
|
||||
await httpGet(url: url, source: source, resDom: true) as Document?;
|
||||
if (dom!.querySelectorAll('.col-7 > p').isNotEmpty) {
|
||||
final images =
|
||||
dom.querySelectorAll('.col-5 ').map((e) => e.outerHtml).toList();
|
||||
RegExp exp = RegExp(r'src="([^"]+)"');
|
||||
|
||||
String? srcValue = exp.firstMatch(images[0])?.group(1);
|
||||
imageUrl = 'https://www.japscan.lol$srcValue';
|
||||
|
||||
if (dom.querySelectorAll('.col-7 > p').isNotEmpty) {
|
||||
final stat = dom
|
||||
.querySelectorAll('.col-7 > p')
|
||||
.where((element) => element.innerHtml.contains('Statut:'))
|
||||
.map((e) => e.text)
|
||||
.toList();
|
||||
if (stat.isNotEmpty) {
|
||||
status = stat[0].replaceAll('Statut:', '').trim();
|
||||
}
|
||||
|
||||
final auth = dom
|
||||
.querySelectorAll('.col-7 > p')
|
||||
.where((element) => element.innerHtml.contains('Auteur(s):'))
|
||||
.map((e) => e.text)
|
||||
.toList();
|
||||
if (auth.isNotEmpty) {
|
||||
author = auth[0].replaceAll('Auteur(s):', '').trim();
|
||||
}
|
||||
} else {
|
||||
author = "";
|
||||
status = "";
|
||||
}
|
||||
|
||||
final genres = dom
|
||||
.querySelectorAll('.col-7 > p')
|
||||
.where((element) => element.innerHtml.contains('Genre(s):'))
|
||||
.map((e) => e.text.replaceAll('Genre(s):', '').trim())
|
||||
.toList();
|
||||
if (genres.isNotEmpty) {
|
||||
for (var ok in genres[0].split(',')) {
|
||||
genre.add(ok);
|
||||
}
|
||||
}
|
||||
|
||||
final synop = dom
|
||||
.querySelectorAll('p.list-group-item ')
|
||||
.map((e) => e.text.trim())
|
||||
.toList();
|
||||
if (synop.isNotEmpty) {
|
||||
description = synop[0];
|
||||
}
|
||||
}
|
||||
|
||||
final urls =
|
||||
dom.querySelectorAll('.col-8 ').map((e) => e.outerHtml).toList();
|
||||
|
||||
for (var ok in urls) {
|
||||
RegExp exp = RegExp(r'href="([^"]+)"');
|
||||
|
||||
String? srcValue = exp.firstMatch(ok)?.group(1);
|
||||
chapterUrl.add('https://www.japscan.lol$srcValue');
|
||||
}
|
||||
|
||||
final chapterTitlee =
|
||||
dom.querySelectorAll('.col-8').map((e) => e.text.trim()).toList();
|
||||
|
||||
if (chapterTitlee.isNotEmpty) {
|
||||
for (var ok in chapterTitlee) {
|
||||
chapterTitle.add(ok);
|
||||
}
|
||||
}
|
||||
|
||||
final chapterDatee =
|
||||
dom.querySelectorAll('.col-4').map((e) => e.text.trim()).toList();
|
||||
if (chapterDatee.isNotEmpty) {
|
||||
for (var ok in chapterDatee) {
|
||||
chapterDate.add(parseDate(ok, source));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (chapterDate.isNotEmpty &&
|
||||
chapterTitle.isNotEmpty &&
|
||||
chapterUrl.isNotEmpty) {
|
||||
for (var i = 0; i < chapterUrl.length; i++) {
|
||||
chapters.add(Chapter(
|
||||
name: chapterTitle[i],
|
||||
url: chapterUrl[i],
|
||||
dateUpload: chapterDate[i],
|
||||
isBookmarked: false,
|
||||
scanlator: scanlators.isEmpty ? "" : scanlators[i],
|
||||
isRead: false,
|
||||
lastPageRead: '',
|
||||
mangaId: null));
|
||||
}
|
||||
mangadetail = await Mangahere().getMangaDetail(
|
||||
imageUrl: imageUrl, url: url, title: title, lang: lang, source: source);
|
||||
}
|
||||
|
||||
return GetMangaDetailModel(
|
||||
status: status,
|
||||
genre: genre,
|
||||
author: author,
|
||||
description: description,
|
||||
name: title,
|
||||
url: url,
|
||||
source: source,
|
||||
imageUrl: imageUrl,
|
||||
chapters: chapters,
|
||||
);
|
||||
/***********/
|
||||
/*japscan*/
|
||||
/***********/
|
||||
|
||||
else if (source.toLowerCase() == "japscan") {
|
||||
mangadetail = await Japscan().getMangaDetail(
|
||||
imageUrl: imageUrl, url: url, title: title, lang: lang, source: source);
|
||||
}
|
||||
return mangadetail!;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'get_manga_detail.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$getMangaDetailHash() => r'42e2ad9fac5c3a0db0a6aefe8f77f2c97eaaf235';
|
||||
String _$getMangaDetailHash() => r'989fdfaf80bf546d1f9910b0715afc9a0e64f33a';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -1,171 +1,43 @@
|
|||
// ignore_for_file: unused_local_variable
|
||||
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'package:html/dom.dart';
|
||||
import 'package:mangayomi/models/comick/popular_manga_comick.dart';
|
||||
import 'package:mangayomi/services/http_service/http_service.dart';
|
||||
import 'package:mangayomi/source/source_list.dart';
|
||||
import 'package:mangayomi/source/source_model.dart';
|
||||
import 'package:mangayomi/models/source_model.dart';
|
||||
import 'package:mangayomi/sources/service/service.dart';
|
||||
import 'package:mangayomi/sources/src/all/comick/src/comick.dart';
|
||||
import 'package:mangayomi/sources/src/en/mangahere/src/mangahere.dart';
|
||||
import 'package:mangayomi/sources/src/fr/japscan/src/japscan.dart';
|
||||
import 'package:mangayomi/sources/src/fr/mangakawaii/src/mangakawaii.dart';
|
||||
import 'package:mangayomi/sources/src/multi/mangathemesia/src/mangathemesia.dart';
|
||||
import 'package:mangayomi/sources/src/multi/mmrcms/src/mmrcms.dart';
|
||||
import 'package:mangayomi/sources/utils/utils.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
part 'get_popular_manga.g.dart';
|
||||
|
||||
class GetMangaModel {
|
||||
late List<String?> url;
|
||||
late List<String?> name;
|
||||
late List<String?> image;
|
||||
GetMangaModel({
|
||||
required this.name,
|
||||
required this.url,
|
||||
required this.image,
|
||||
});
|
||||
}
|
||||
|
||||
String getWpMangaUrl(String source) {
|
||||
String url = "";
|
||||
for (var i = 0; i < sourcesList.length; i++) {
|
||||
if (sourcesList[i].sourceName.toLowerCase() == source.toLowerCase()) {
|
||||
url = sourcesList[i].url;
|
||||
}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
TypeSource getWpMangTypeSource(String source) {
|
||||
TypeSource? typeSource;
|
||||
for (var i = 0; i < sourcesList.length; i++) {
|
||||
if (sourcesList[i].sourceName.toLowerCase() == source.toLowerCase()) {
|
||||
typeSource = sourcesList[i].typeSource;
|
||||
}
|
||||
}
|
||||
return typeSource!;
|
||||
}
|
||||
|
||||
String getFormatDate(String source) {
|
||||
String? dateFormat;
|
||||
for (var i = 0; i < sourcesList.length; i++) {
|
||||
if (sourcesList[i].sourceName.toLowerCase() == source.toLowerCase()) {
|
||||
dateFormat = sourcesList[i].dateFormat;
|
||||
}
|
||||
}
|
||||
return dateFormat!;
|
||||
}
|
||||
|
||||
String getFormatDateLocale(String source) {
|
||||
String? dateFormatLocale;
|
||||
for (var i = 0; i < sourcesList.length; i++) {
|
||||
if (sourcesList[i].sourceName.toLowerCase() == source.toLowerCase()) {
|
||||
dateFormatLocale = sourcesList[i].dateFormatLocale;
|
||||
}
|
||||
}
|
||||
return dateFormatLocale!;
|
||||
}
|
||||
|
||||
bool isCloudflare(String source) {
|
||||
bool? isCloudflare;
|
||||
for (var i = 0; i < sourcesList.length; i++) {
|
||||
if (sourcesList[i].sourceName.toLowerCase() == source.toLowerCase()) {
|
||||
isCloudflare = sourcesList[i].isCloudflare;
|
||||
}
|
||||
}
|
||||
return isCloudflare!;
|
||||
}
|
||||
|
||||
@riverpod
|
||||
Future<GetMangaModel> getPopularManga(GetPopularMangaRef ref,
|
||||
{required String source, required int page}) async {
|
||||
List<String?> url = [];
|
||||
List<String?> name = [];
|
||||
List<String?> image = [];
|
||||
GetMangaModel? popularManga;
|
||||
source = source.toLowerCase();
|
||||
|
||||
/*********/
|
||||
/*comick*/
|
||||
/*******/
|
||||
if (getWpMangTypeSource(source) == TypeSource.comick) {
|
||||
final response = await httpGet(
|
||||
url:
|
||||
'https://api.comick.fun/v1.0/search?sort=follow&page=$page&tachiyomi=true',
|
||||
source: source,
|
||||
resDom: false) as String?;
|
||||
var popularManga = jsonDecode(response!) as List;
|
||||
|
||||
var popularMangaList =
|
||||
popularManga.map((e) => PopularMangaModelComick.fromJson(e)).toList();
|
||||
for (var popular in popularMangaList) {
|
||||
url.add("/comic/${popular.slug}");
|
||||
name.add(popular.title);
|
||||
image.add(popular.coverUrl);
|
||||
}
|
||||
popularManga = await Comick().getPopularManga(source: source, page: page);
|
||||
}
|
||||
|
||||
/***************/
|
||||
/*mangathemesia*/
|
||||
/**************/
|
||||
if (getWpMangTypeSource(source) == TypeSource.mangathemesia) {
|
||||
final dom = await httpGet(
|
||||
useUserAgent: true,
|
||||
url: '${getWpMangaUrl(source)}/manga/?title=&page=$page&order=popular',
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
if (dom!
|
||||
.querySelectorAll(
|
||||
'.utao .uta .imgu, .listupd .bs .bsx, .listo .bs .bsx')
|
||||
.isNotEmpty) {
|
||||
url = dom
|
||||
.querySelectorAll(
|
||||
'.utao .uta .imgu, .listupd .bs .bsx, .listo .bs .bsx')
|
||||
.map((e) {
|
||||
RegExp exp = RegExp(r'href="([^"]+)"');
|
||||
Iterable<Match> matches = exp.allMatches(e.innerHtml);
|
||||
String? firstMatch = matches.first.group(1);
|
||||
return firstMatch;
|
||||
}).toList();
|
||||
|
||||
image = dom
|
||||
.querySelectorAll(
|
||||
'.utao .uta .imgu, .listupd .bs .bsx, .listo .bs .bsx')
|
||||
.map((e) {
|
||||
RegExp exp = RegExp(r'src="([^"]+)"');
|
||||
Iterable<Match> matches = exp.allMatches(e.innerHtml);
|
||||
String? firstMatch = matches.first.group(1);
|
||||
return firstMatch;
|
||||
}).toList();
|
||||
|
||||
name = dom
|
||||
.querySelectorAll(
|
||||
'.utao .uta .imgu, .listupd .bs .bsx, .listo .bs .bsx ')
|
||||
.map((e) {
|
||||
RegExp exp = RegExp(r'title="([^"]+)"');
|
||||
Iterable<Match> matches = exp.allMatches(e.innerHtml);
|
||||
String? firstMatch = matches.first.group(1);
|
||||
return firstMatch;
|
||||
}).toList();
|
||||
}
|
||||
popularManga =
|
||||
await MangaThemeSia().getPopularManga(source: source, page: page);
|
||||
}
|
||||
|
||||
/***********/
|
||||
/*mangakawaii*/
|
||||
/***********/
|
||||
if (source == "mangakawaii") {
|
||||
final dom = await httpGet(
|
||||
url: 'https://www.mangakawaii.io/',
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
if (dom!.querySelectorAll('a.hot-manga__item').isNotEmpty) {
|
||||
url = dom
|
||||
.querySelectorAll('a.hot-manga__item ')
|
||||
.where((e) => e.attributes.containsKey('href'))
|
||||
.map((e) => e.attributes['href'])
|
||||
.toList();
|
||||
name = dom
|
||||
.querySelectorAll('a > div > div.hot-manga__item-name')
|
||||
.map((e) => e.innerHtml)
|
||||
.toList();
|
||||
for (var ia in name) {
|
||||
image.add("");
|
||||
}
|
||||
}
|
||||
popularManga =
|
||||
await MangaKawaii().getPopularManga(source: source, page: page);
|
||||
}
|
||||
|
||||
/***********/
|
||||
|
|
@ -173,93 +45,21 @@ Future<GetMangaModel> getPopularManga(GetPopularMangaRef ref,
|
|||
/***********/
|
||||
|
||||
else if (getWpMangTypeSource(source) == TypeSource.mmrcms) {
|
||||
final dom = await httpGet(
|
||||
url:
|
||||
'${getWpMangaUrl(source)}/filterList?page=$page&sortBy=views&asc=false',
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
final urlElement = dom!.getElementsByClassName('chart-title');
|
||||
for (var e in urlElement) {
|
||||
RegExp exp = RegExp(r'href="([^"]+)"');
|
||||
Iterable<Match> matches = exp.allMatches(e.outerHtml);
|
||||
String? firstMatch = matches.first.group(1);
|
||||
url.add(firstMatch);
|
||||
name.add(e.text);
|
||||
}
|
||||
final imgElement = dom.getElementsByTagName('img');
|
||||
for (var e in imgElement) {
|
||||
RegExp exp = RegExp(r'src="([^"]+)"');
|
||||
Iterable<Match> matches = exp.allMatches(e.outerHtml);
|
||||
String? firstMatch = matches.first.group(1);
|
||||
image.add(firstMatch);
|
||||
}
|
||||
popularManga = await Mmrcms().getPopularManga(source: source, page: page);
|
||||
}
|
||||
|
||||
/***********/
|
||||
/*mangahere*/
|
||||
/***********/
|
||||
else if (source == "mangahere") {
|
||||
final dom = await httpGet(
|
||||
url: 'https://www.mangahere.cc/ranking/',
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
if (dom!
|
||||
.querySelectorAll(
|
||||
'body > div.container.weekrank.ranking > div > div > ul > li > a')
|
||||
.isNotEmpty) {
|
||||
url = dom
|
||||
.querySelectorAll(
|
||||
'body > div.container.weekrank.ranking > div > div > ul > li > a ')
|
||||
.where((e) => e.attributes.containsKey('href'))
|
||||
.map((e) => e.attributes['href'])
|
||||
.toList();
|
||||
|
||||
image = dom
|
||||
.querySelectorAll(
|
||||
' body > div.container.weekrank.ranking > div > div > ul > li > a > img')
|
||||
.where((e) => e.attributes.containsKey('src'))
|
||||
.where((e) => e.attributes['src']!.contains("cover"))
|
||||
.map((e) => e.attributes['src'])
|
||||
.toList();
|
||||
|
||||
name = dom
|
||||
.querySelectorAll(
|
||||
'body > div.container.weekrank.ranking > div > div > ul > li > a ')
|
||||
.where((e) => e.attributes.containsKey('title'))
|
||||
.map((e) => e.attributes['title'])
|
||||
.toList();
|
||||
}
|
||||
popularManga =
|
||||
await Mangahere().getPopularManga(source: source, page: page);
|
||||
}
|
||||
/***********/
|
||||
/*japscan*/
|
||||
/***********/
|
||||
else if (source == "japscan") {
|
||||
final dom = await httpGet(
|
||||
url: "https://www.japscan.lol/",
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
if (dom!.querySelectorAll('#top_mangas_week > ul > li ').isNotEmpty) {
|
||||
final urls = dom
|
||||
.querySelectorAll('#top_mangas_week > ul > li > a')
|
||||
.where((e) => e.attributes['href'].toString().contains('manga'))
|
||||
.map((e) => e.attributes['href'])
|
||||
.toList();
|
||||
for (var ok in urls) {
|
||||
url.add("https://www.japscan.lol$ok");
|
||||
}
|
||||
name = dom
|
||||
.querySelectorAll(
|
||||
'#top_mangas_week > ul > li > a.text-dark.font-weight-bold')
|
||||
.map((e) => e.innerHtml)
|
||||
.toList();
|
||||
for (var ia in name) {
|
||||
image.add("");
|
||||
}
|
||||
}
|
||||
popularManga = await Japscan().getPopularManga(source: source, page: page);
|
||||
}
|
||||
return GetMangaModel(
|
||||
name: name,
|
||||
url: url,
|
||||
image: image,
|
||||
);
|
||||
return popularManga!;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'get_popular_manga.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$getPopularMangaHash() => r'cf3f1c29feafa93591a44549b5d81f25ff65bf4f';
|
||||
String _$getPopularMangaHash() => r'cec4ced8864aca6f08b29a8ef9405fd21b68927f';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,10 @@ import 'package:http/http.dart' as http;
|
|||
|
||||
Future<Document> httpResToDom(
|
||||
{required String url, required Map<String, String>? headers}) async {
|
||||
final response = await http.get(Uri.parse(url), headers: headers);
|
||||
return Document.html(response.body);
|
||||
try {
|
||||
final response = await http.get(Uri.parse(url), headers: headers);
|
||||
return Document.html(response.body);
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import 'package:html/dom.dart';
|
||||
import 'package:mangayomi/services/http_service/cloudflare/cloudflare_bypass.dart';
|
||||
import 'package:mangayomi/services/get_popular_manga.dart';
|
||||
import 'package:mangayomi/services/http_service/http_res_to_dom_html.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:mangayomi/sources/utils/utils.dart';
|
||||
import 'package:mangayomi/utils/headers.dart';
|
||||
|
||||
Future<dynamic> httpGet(
|
||||
|
|
@ -29,8 +29,13 @@ Future<dynamic> httpGet(
|
|||
useUserAgent: useUserAgent,
|
||||
);
|
||||
} else {
|
||||
final response = await http.get(Uri.parse(url), headers: headers(source));
|
||||
resHtml = response.body;
|
||||
try {
|
||||
final response =
|
||||
await http.get(Uri.parse(url), headers: headers(source));
|
||||
resHtml = response.body;
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
return resHtml;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,177 +1,68 @@
|
|||
import 'dart:convert';
|
||||
import 'package:html/dom.dart';
|
||||
import 'package:mangayomi/models/comick/search_manga_cimick.dart';
|
||||
import 'package:mangayomi/services/get_popular_manga.dart';
|
||||
import 'package:mangayomi/services/http_service/http_service.dart';
|
||||
import 'package:mangayomi/source/source_model.dart';
|
||||
import 'package:mangayomi/models/source_model.dart';
|
||||
import 'package:mangayomi/sources/service/service.dart';
|
||||
import 'package:mangayomi/sources/src/all/comick/src/comick.dart';
|
||||
import 'package:mangayomi/sources/src/en/mangahere/src/mangahere.dart';
|
||||
import 'package:mangayomi/sources/src/fr/japscan/src/japscan.dart';
|
||||
import 'package:mangayomi/sources/src/fr/mangakawaii/src/mangakawaii.dart';
|
||||
import 'package:mangayomi/sources/src/multi/mangathemesia/src/mangathemesia.dart';
|
||||
import 'package:mangayomi/sources/src/multi/mmrcms/src/mmrcms.dart';
|
||||
import 'package:mangayomi/sources/utils/utils.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
part 'search_manga.g.dart';
|
||||
|
||||
class SearchMangaModel {
|
||||
late List<String?> url;
|
||||
late List<String?> name;
|
||||
late List<String?> image;
|
||||
|
||||
SearchMangaModel({
|
||||
required this.name,
|
||||
required this.url,
|
||||
required this.image,
|
||||
});
|
||||
}
|
||||
|
||||
@riverpod
|
||||
Future<SearchMangaModel> searchManga(SearchMangaRef ref,
|
||||
Future<GetMangaModel> searchManga(SearchMangaRef ref,
|
||||
{required String source, required String query}) async {
|
||||
List<String?> url = [];
|
||||
List<String?> name = [];
|
||||
List<String?> image = [];
|
||||
GetMangaModel? manga;
|
||||
source = source.toLowerCase();
|
||||
|
||||
/********/
|
||||
/*comick*/
|
||||
/********/
|
||||
|
||||
if (getWpMangTypeSource(source) == TypeSource.comick) {
|
||||
final response = await httpGet(
|
||||
url:
|
||||
'https://api.comick.fun/search?q=${query.trim()}&tachiyomi=true&page=1',
|
||||
source: source,
|
||||
resDom: false) as String?;
|
||||
var popularManga = jsonDecode(response!) as List;
|
||||
var popularMangaList =
|
||||
popularManga.map((e) => MangaSearchModelComick.fromJson(e)).toList();
|
||||
for (var popular in popularMangaList) {
|
||||
url.add("/comic/${popular.slug}");
|
||||
name.add(popular.title);
|
||||
image.add(popular.coverUrl);
|
||||
}
|
||||
manga = await Comick().searchManga(source: source, query: query);
|
||||
}
|
||||
|
||||
/***************/
|
||||
/*mangathemesia*/
|
||||
/***************/
|
||||
|
||||
else if (getWpMangTypeSource(source) == TypeSource.mangathemesia) {
|
||||
final dom = await httpGet(
|
||||
url: '${getWpMangaUrl(source)}/?s=${query.trim()}',
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
if (dom!
|
||||
.querySelectorAll(
|
||||
'#content > div > div.postbody > div > div.listupd > div > div > a')
|
||||
.isNotEmpty) {
|
||||
url = dom
|
||||
.querySelectorAll(
|
||||
'#content > div > div.postbody > div > div.listupd > div > div > a ')
|
||||
.where((e) => e.attributes.containsKey('href'))
|
||||
.map((e) => e.attributes['href'])
|
||||
.toList();
|
||||
|
||||
image = dom
|
||||
.querySelectorAll(
|
||||
' #content > div > div.postbody > div > div.listupd > div > div > a > div > img')
|
||||
.where((e) => e.attributes.containsKey('src'))
|
||||
.map((e) => e.attributes['src'])
|
||||
.toList();
|
||||
|
||||
name = dom
|
||||
.querySelectorAll(
|
||||
'#content > div > div.postbody > div > div.listupd > div > div > a ')
|
||||
.where((e) => e.attributes.containsKey('title'))
|
||||
.map((e) => e.attributes['title'])
|
||||
.toList();
|
||||
}
|
||||
manga = await MangaThemeSia().searchManga(source: source, query: query);
|
||||
}
|
||||
|
||||
/***********/
|
||||
/*mangakawaii*/
|
||||
/***********/
|
||||
else if (source == "mangakawaii") {
|
||||
final dom = await httpGet(
|
||||
url:
|
||||
'https://www.mangakawaii.io/search?query=${query.trim()}&search_type=manga',
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
if (dom!
|
||||
.querySelectorAll(
|
||||
'#page-content > div > div > ul > li > div.section__list-group-right > div.section__list-group-header > div > h4 > a')
|
||||
.isNotEmpty) {
|
||||
final ur = dom
|
||||
.querySelectorAll(
|
||||
'#page-content > div > div > ul > li > div.section__list-group-right > div.section__list-group-header > div > h4 > a')
|
||||
.where((e) => e.attributes.containsKey('href'))
|
||||
.map((e) => e.attributes['href'])
|
||||
.toList();
|
||||
for (var a in ur) {
|
||||
url.add(a!);
|
||||
}
|
||||
|
||||
final nam = dom
|
||||
.querySelectorAll(
|
||||
'#page-content > div > div > ul > li > div.section__list-group-right > div.section__list-group-header > div > h4 > a')
|
||||
.map((e) => e.text)
|
||||
.toList();
|
||||
for (var a in nam) {
|
||||
name.add(a);
|
||||
image.add('');
|
||||
}
|
||||
}
|
||||
else if (source == "mangakawaii") {
|
||||
manga = await MangaKawaii().searchManga(source: source, query: query);
|
||||
}
|
||||
|
||||
/***********/
|
||||
/*mmrcms*/
|
||||
/***********/
|
||||
|
||||
else if (getWpMangTypeSource(source) == TypeSource.mmrcms) {
|
||||
final response = await httpGet(
|
||||
url: '${getWpMangaUrl(source)}/search?query=${query.trim()}',
|
||||
source: source,
|
||||
resDom: false) as String?;
|
||||
final rep = jsonDecode(response!);
|
||||
for (var ok in rep['suggestions']) {
|
||||
if (source == 'Read Comics Online') {
|
||||
url.add('${getWpMangaUrl(source)}/comic/${ok['data']}');
|
||||
} else if (source == 'Scan VF') {
|
||||
url.add('${getWpMangaUrl(source)}/${ok['data']}');
|
||||
} else {
|
||||
url.add('${getWpMangaUrl(source)}/manga/${ok['data']}');
|
||||
}
|
||||
name.add(ok["value"]);
|
||||
image.add('');
|
||||
}
|
||||
manga = await Mmrcms().searchManga(source: source, query: query);
|
||||
}
|
||||
|
||||
/***********/
|
||||
/*mangahere*/
|
||||
/***********/
|
||||
|
||||
else if (source == "mangahere") {
|
||||
final dom = await httpGet(
|
||||
url:
|
||||
'${getWpMangaUrl(source)}/search?title=${query.trim()}&genres=&nogenres=&sort=&stype=1&name=&type=0&author_method=cw&author=&artist_method=cw&artist=&rating_method=eq&rating=&released_method=eq&released=&st=0',
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
|
||||
if (dom!
|
||||
.querySelectorAll(
|
||||
'body > div.container > div > div > ul > li > p.manga-list-4-item-title > a')
|
||||
.isNotEmpty) {
|
||||
url = dom
|
||||
.querySelectorAll(
|
||||
'body > div.container > div > div > ul > li > p.manga-list-4-item-title > a')
|
||||
.where((e) => e.attributes.containsKey('href'))
|
||||
.map((e) => e.attributes['href'])
|
||||
.toList();
|
||||
|
||||
image = dom
|
||||
.querySelectorAll(
|
||||
'body > div.container > div > div > ul > li > a > img')
|
||||
.where((e) => e.attributes.containsKey('src'))
|
||||
.where((e) => e.attributes['src']!.contains("cover"))
|
||||
.map((e) => e.attributes['src'])
|
||||
.toList();
|
||||
|
||||
name = dom
|
||||
.querySelectorAll(
|
||||
'body > div.container > div > div > ul > li > p.manga-list-4-item-title > a')
|
||||
.where((e) => e.attributes.containsKey('title'))
|
||||
.map((e) => e.attributes['title'])
|
||||
.toList();
|
||||
}
|
||||
manga = await Mangahere().searchManga(source: source, query: query);
|
||||
}
|
||||
|
||||
return SearchMangaModel(name: name, url: url, image: image);
|
||||
/***********/
|
||||
/*japscan*/
|
||||
/***********/
|
||||
|
||||
else if (source == "japscan") {
|
||||
manga = await Japscan().searchManga(source: source, query: query);
|
||||
}
|
||||
|
||||
return manga!;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'search_manga.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$searchMangaHash() => r'8efe07dbe0f844d9d17ecf6962ac7f03ebcc9d57';
|
||||
String _$searchMangaHash() => r'1694578ec0cc207b533f4709427d3f68b691b1b7';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
@ -29,14 +29,14 @@ class _SystemHash {
|
|||
}
|
||||
}
|
||||
|
||||
typedef SearchMangaRef = AutoDisposeFutureProviderRef<SearchMangaModel>;
|
||||
typedef SearchMangaRef = AutoDisposeFutureProviderRef<GetMangaModel>;
|
||||
|
||||
/// See also [searchManga].
|
||||
@ProviderFor(searchManga)
|
||||
const searchMangaProvider = SearchMangaFamily();
|
||||
|
||||
/// See also [searchManga].
|
||||
class SearchMangaFamily extends Family<AsyncValue<SearchMangaModel>> {
|
||||
class SearchMangaFamily extends Family<AsyncValue<GetMangaModel>> {
|
||||
/// See also [searchManga].
|
||||
const SearchMangaFamily();
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ class SearchMangaFamily extends Family<AsyncValue<SearchMangaModel>> {
|
|||
}
|
||||
|
||||
/// See also [searchManga].
|
||||
class SearchMangaProvider extends AutoDisposeFutureProvider<SearchMangaModel> {
|
||||
class SearchMangaProvider extends AutoDisposeFutureProvider<GetMangaModel> {
|
||||
/// See also [searchManga].
|
||||
SearchMangaProvider({
|
||||
required this.source,
|
||||
|
|
|
|||
108
lib/sources/service/service.dart
Normal file
108
lib/sources/service/service.dart
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
import 'package:mangayomi/models/chapter.dart';
|
||||
|
||||
abstract class MangaYomiServices {
|
||||
List<String?> url = [];
|
||||
List<String?> name = [];
|
||||
List<String?> image = [];
|
||||
List<String> genre = [];
|
||||
String? author;
|
||||
String? status;
|
||||
List<String> chapterTitle = [];
|
||||
List<String> chapterUrl = [];
|
||||
List<String> chapterDate = [];
|
||||
String? description;
|
||||
List<Chapter> chapters = [];
|
||||
List<String> scanlators = [];
|
||||
List pageUrls = [];
|
||||
|
||||
GetMangaModel mangaRes() {
|
||||
return GetMangaModel(
|
||||
name: name,
|
||||
url: url,
|
||||
image: image,
|
||||
);
|
||||
}
|
||||
|
||||
GetMangaDetailModel mangadetailRes(
|
||||
{required String imageUrl,
|
||||
required String url,
|
||||
required String title,
|
||||
required String source}) {
|
||||
if (chapterDate.isNotEmpty &&
|
||||
chapterTitle.isNotEmpty &&
|
||||
chapterUrl.isNotEmpty) {
|
||||
for (var i = 0; i < chapterUrl.length; i++) {
|
||||
chapters.add(Chapter(
|
||||
name: chapterTitle[i],
|
||||
url: chapterUrl[i],
|
||||
dateUpload: chapterDate[i],
|
||||
isBookmarked: false,
|
||||
scanlator: scanlators.isEmpty ? "" : scanlators[i],
|
||||
isRead: false,
|
||||
lastPageRead: '',
|
||||
mangaId: null));
|
||||
}
|
||||
}
|
||||
return GetMangaDetailModel(
|
||||
status: status,
|
||||
genre: genre,
|
||||
author: author,
|
||||
description: description,
|
||||
name: title,
|
||||
url: url,
|
||||
source: source,
|
||||
imageUrl: imageUrl,
|
||||
chapters: chapters,
|
||||
);
|
||||
}
|
||||
|
||||
Future<GetMangaModel?> getPopularManga(
|
||||
{required String source, required int page});
|
||||
Future<GetMangaDetailModel?> getMangaDetail(
|
||||
{required String imageUrl,
|
||||
required String url,
|
||||
required String title,
|
||||
required String lang,
|
||||
required String source});
|
||||
Future<List<dynamic>?> getMangaChapterUrl({
|
||||
required Chapter chapter,
|
||||
});
|
||||
Future<GetMangaModel?> searchManga(
|
||||
{required String source, required String query});
|
||||
}
|
||||
|
||||
|
||||
|
||||
class GetMangaModel {
|
||||
late List<String?> url;
|
||||
late List<String?> name;
|
||||
late List<String?> image;
|
||||
GetMangaModel({
|
||||
required this.name,
|
||||
required this.url,
|
||||
required this.image,
|
||||
});
|
||||
}
|
||||
|
||||
class GetMangaDetailModel {
|
||||
List<String> genre = [];
|
||||
List<Chapter> chapters = [];
|
||||
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.chapters,
|
||||
required this.imageUrl,
|
||||
required this.description,
|
||||
required this.url,
|
||||
required this.name,
|
||||
required this.source,
|
||||
});
|
||||
}
|
||||
17
lib/sources/source_list.dart
Normal file
17
lib/sources/source_list.dart
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import 'package:mangayomi/models/source_model.dart';
|
||||
import 'package:mangayomi/sources/src/all/comick/comick_source_list.dart';
|
||||
import 'package:mangayomi/sources/src/en/mangahere/mangahere_source.dart';
|
||||
import 'package:mangayomi/sources/src/fr/japscan/japscan_source.dart';
|
||||
import 'package:mangayomi/sources/src/fr/mangakawaii/mangakawaii_source.dart';
|
||||
import 'package:mangayomi/sources/src/multi/mangathemesia/mangathemesia_source_list.dart';
|
||||
import 'package:mangayomi/sources/src/multi/mmrcms/mmrcms_source_list.dart';
|
||||
|
||||
List<SourceModel> get sourcesList => _sourcesList;
|
||||
List<SourceModel> _sourcesList = [
|
||||
mangahereSource,
|
||||
mangakawaiiSource,
|
||||
...mangathemesiaSourcesList,
|
||||
...comickSourcesList,
|
||||
...mmrcmsSourcesList,
|
||||
japscanSource
|
||||
];
|
||||
159
lib/sources/src/all/comick/comick_source_list.dart
Normal file
159
lib/sources/src/all/comick/comick_source_list.dart
Normal file
|
|
@ -0,0 +1,159 @@
|
|||
import 'package:mangayomi/models/source_model.dart';
|
||||
|
||||
String logoUrl =
|
||||
'https://comick.app/_next/image?url=%2Fstatic%2Ficons%2Funicorn-64.png&w=144&q=75';
|
||||
String apiUrl = 'https://api.comick.fun/';
|
||||
List<SourceModel> comickSourcesList = [
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: apiUrl,
|
||||
lang: 'en',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl: logoUrl,
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: apiUrl,
|
||||
lang: 'ar',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl: logoUrl,
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: apiUrl,
|
||||
lang: 'pt',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl: logoUrl,
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: apiUrl,
|
||||
lang: 'pt-br',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl: logoUrl,
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: apiUrl,
|
||||
lang: 'it',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl: logoUrl,
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: apiUrl,
|
||||
lang: 'ru',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl: logoUrl,
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: apiUrl,
|
||||
lang: 'es',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl: logoUrl,
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: apiUrl,
|
||||
lang: 'es-419',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl: logoUrl,
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: apiUrl,
|
||||
lang: 'id',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl: logoUrl,
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: apiUrl,
|
||||
lang: 'hi',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl: logoUrl,
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: apiUrl,
|
||||
lang: 'de',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl: logoUrl,
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: apiUrl,
|
||||
lang: 'ja',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl: logoUrl,
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: apiUrl,
|
||||
lang: 'tr',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl: logoUrl,
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: apiUrl,
|
||||
lang: 'pl',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl: logoUrl,
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: apiUrl,
|
||||
lang: 'zh',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl: logoUrl,
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: apiUrl,
|
||||
lang: 'zh-hk',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl: logoUrl,
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: apiUrl,
|
||||
lang: 'fr',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl: logoUrl,
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: "KomikLab",
|
||||
url: "https://komiklab.com",
|
||||
lang: "en",
|
||||
typeSource: TypeSource.mangathemesia,
|
||||
logoUrl: '',
|
||||
dateFormat: "MMMM dd, yyyy",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: "AnimatedGlitchedScans",
|
||||
url: "https://anigliscans.com",
|
||||
lang: "en",
|
||||
typeSource: TypeSource.mangathemesia,
|
||||
logoUrl: '',
|
||||
dateFormat: "MMMM dd, yyyy",
|
||||
dateFormatLocale: "en"),
|
||||
];
|
||||
127
lib/sources/src/all/comick/src/comick.dart
Normal file
127
lib/sources/src/all/comick/src/comick.dart
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/models/comick/chapter_page_comick.dart';
|
||||
import 'package:mangayomi/models/comick/manga_chapter_detail.dart';
|
||||
import 'package:mangayomi/models/comick/manga_detail_comick.dart';
|
||||
import 'package:mangayomi/models/comick/popular_manga_comick.dart';
|
||||
import 'package:mangayomi/models/comick/search_manga_cimick.dart';
|
||||
import 'package:mangayomi/services/http_service/http_service.dart';
|
||||
import 'package:mangayomi/sources/service/service.dart';
|
||||
import 'package:mangayomi/sources/src/all/comick/src/utils/utils.dart';
|
||||
import 'package:mangayomi/sources/utils/utils.dart';
|
||||
|
||||
class Comick extends MangaYomiServices {
|
||||
@override
|
||||
Future<GetMangaModel?> getPopularManga(
|
||||
{required String source, required int page}) async {
|
||||
source = source.toLowerCase();
|
||||
final response = await httpGet(
|
||||
url:
|
||||
'https://api.comick.fun/v1.0/search?sort=follow&page=$page&tachiyomi=true',
|
||||
source: source,
|
||||
resDom: false) as String?;
|
||||
var popularManga = jsonDecode(response!) as List;
|
||||
|
||||
var popularMangaList =
|
||||
popularManga.map((e) => PopularMangaModelComick.fromJson(e)).toList();
|
||||
for (var popular in popularMangaList) {
|
||||
url.add("/comic/${popular.slug}");
|
||||
name.add(popular.title);
|
||||
image.add(popular.coverUrl);
|
||||
}
|
||||
return mangaRes();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<GetMangaDetailModel?> getMangaDetail(
|
||||
{required String imageUrl,
|
||||
required String url,
|
||||
required String title,
|
||||
required String lang,
|
||||
required String source}) async {
|
||||
final response = await httpGet(
|
||||
url: 'https://api.comick.fun$url?tachiyomi=true',
|
||||
source: source,
|
||||
resDom: false) as String?;
|
||||
var mangaDetail = jsonDecode(response!) 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();
|
||||
|
||||
final responsee = await httpGet(
|
||||
url:
|
||||
'https://api.comick.fun/comic/$mangaId/chapters?lang=$lang&limit=$limit',
|
||||
source: source,
|
||||
resDom: false) as String?;
|
||||
var chapterDetail = jsonDecode(responsee!) as Map<String, dynamic>;
|
||||
var chapterDetailMap = MangaChapterModelComick.fromJson(chapterDetail);
|
||||
for (var chapter in chapterDetailMap.chapters!) {
|
||||
scanlators.add(chapter.groupName!.isNotEmpty
|
||||
? chapter.groupName!.first.toString() != 'null'
|
||||
? chapter.groupName!.first
|
||||
: ""
|
||||
: "");
|
||||
chapterUrl.add(
|
||||
"/comic/${mangaDetailLMap.comic!.slug}/${chapter.hid}-chapter-${chapter.chap}-en");
|
||||
chapterDate.add(parseDate(chapter.createdAt!, source));
|
||||
|
||||
chapterTitle.add(beautifyChapterName(
|
||||
chapter.vol ?? "", chapter.chap ?? "", chapter.title ?? "", lang));
|
||||
}
|
||||
|
||||
return mangadetailRes(
|
||||
imageUrl: imageUrl, url: url, title: title, source: source);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<GetMangaModel> searchManga(
|
||||
{required String source, required String query}) async {
|
||||
final response = await httpGet(
|
||||
url:
|
||||
'https://api.comick.fun/search?q=${query.trim()}&tachiyomi=true&page=1',
|
||||
source: source,
|
||||
resDom: false) as String?;
|
||||
var popularManga = jsonDecode(response!) as List;
|
||||
var popularMangaList =
|
||||
popularManga.map((e) => MangaSearchModelComick.fromJson(e)).toList();
|
||||
for (var popular in popularMangaList) {
|
||||
url.add("/comic/${popular.slug}");
|
||||
name.add(popular.title);
|
||||
image.add(popular.coverUrl);
|
||||
}
|
||||
return mangaRes();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<dynamic>> getMangaChapterUrl({required Chapter chapter}) async {
|
||||
String mangaId = chapter.url!.split('/').last.split('-').first;
|
||||
|
||||
final response = await httpGet(
|
||||
url: 'https://api.comick.fun/chapter/$mangaId?tachiyomi=true',
|
||||
source: 'comick',
|
||||
resDom: false) as String?;
|
||||
var data = jsonDecode(response!) as Map<String, dynamic>;
|
||||
var page = ChapterPageComick.fromJson(data);
|
||||
for (var url in page.chapter!.images!) {
|
||||
pageUrls.add(url.url);
|
||||
}
|
||||
return pageUrls;
|
||||
}
|
||||
}
|
||||
38
lib/sources/src/all/comick/src/utils/utils.dart
Normal file
38
lib/sources/src/all/comick/src/utils/utils.dart
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import 'package:intl/intl.dart';
|
||||
import 'package:mangayomi/sources/utils/utils.dart';
|
||||
import 'package:mangayomi/utils/headers.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
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 request = http.Request('GET',
|
||||
Uri.parse('https://api.comick.fun/tachiyomi/mapping?slugs=$oldSlug'));
|
||||
|
||||
request.headers.addAll(headers("comick"));
|
||||
|
||||
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" : ""}";
|
||||
}
|
||||
|
||||
12
lib/sources/src/en/mangahere/mangahere_source.dart
Normal file
12
lib/sources/src/en/mangahere/mangahere_source.dart
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import 'package:mangayomi/models/source_model.dart';
|
||||
|
||||
SourceModel mangahereSource = SourceModel(
|
||||
sourceName: "MangaHere",
|
||||
url: "http://www.mangahere.cc",
|
||||
lang: "en",
|
||||
typeSource: TypeSource.single,
|
||||
logoUrl: 'http://static.mangahere.cc/v20210106/mangahere/images/logo.png',
|
||||
isFullData: true,
|
||||
dateFormat: "MMM dd,yyyy",
|
||||
dateFormatLocale: "en",
|
||||
);
|
||||
295
lib/sources/src/en/mangahere/src/mangahere.dart
Normal file
295
lib/sources/src/en/mangahere/src/mangahere.dart
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
import 'package:flutter_js/flutter_js.dart';
|
||||
import 'package:html/dom.dart';
|
||||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/services/http_service/http_service.dart';
|
||||
import 'package:mangayomi/sources/service/service.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:html/dom.dart' as dom;
|
||||
import 'package:mangayomi/sources/utils/utils.dart';
|
||||
|
||||
class Mangahere extends MangaYomiServices {
|
||||
@override
|
||||
Future<GetMangaDetailModel?> getMangaDetail(
|
||||
{required String imageUrl,
|
||||
required String url,
|
||||
required String title,
|
||||
required String lang,
|
||||
required String source}) async {
|
||||
final dom = await httpGet(
|
||||
url: "http://www.mangahere.cc$url",
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
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(parseDate(ok, source));
|
||||
}
|
||||
}
|
||||
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 mangadetailRes(
|
||||
imageUrl: imageUrl, url: url, title: title, source: source);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<GetMangaModel?> getPopularManga(
|
||||
{required String source, required int page}) async {
|
||||
final dom = await httpGet(
|
||||
url: 'https://www.mangahere.cc/ranking/',
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
if (dom!
|
||||
.querySelectorAll(
|
||||
'body > div.container.weekrank.ranking > div > div > ul > li > a')
|
||||
.isNotEmpty) {
|
||||
url = dom
|
||||
.querySelectorAll(
|
||||
'body > div.container.weekrank.ranking > div > div > ul > li > a ')
|
||||
.where((e) => e.attributes.containsKey('href'))
|
||||
.map((e) => e.attributes['href'])
|
||||
.toList();
|
||||
|
||||
image = dom
|
||||
.querySelectorAll(
|
||||
' body > div.container.weekrank.ranking > div > div > ul > li > a > img')
|
||||
.where((e) => e.attributes.containsKey('src'))
|
||||
.where((e) => e.attributes['src']!.contains("cover"))
|
||||
.map((e) => e.attributes['src'])
|
||||
.toList();
|
||||
|
||||
name = dom
|
||||
.querySelectorAll(
|
||||
'body > div.container.weekrank.ranking > div > div > ul > li > a ')
|
||||
.where((e) => e.attributes.containsKey('title'))
|
||||
.map((e) => e.attributes['title'])
|
||||
.toList();
|
||||
}
|
||||
return mangaRes();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<GetMangaModel?> searchManga(
|
||||
{required String source, required String query}) async {
|
||||
final dom = await httpGet(
|
||||
url:
|
||||
'${getWpMangaUrl(source)}/search?title=${query.trim()}&genres=&nogenres=&sort=&stype=1&name=&type=0&author_method=cw&author=&artist_method=cw&artist=&rating_method=eq&rating=&released_method=eq&released=&st=0',
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
|
||||
if (dom!
|
||||
.querySelectorAll(
|
||||
'body > div.container > div > div > ul > li > p.manga-list-4-item-title > a')
|
||||
.isNotEmpty) {
|
||||
url = dom
|
||||
.querySelectorAll(
|
||||
'body > div.container > div > div > ul > li > p.manga-list-4-item-title > a')
|
||||
.where((e) => e.attributes.containsKey('href'))
|
||||
.map((e) => e.attributes['href'])
|
||||
.toList();
|
||||
|
||||
image = dom
|
||||
.querySelectorAll(
|
||||
'body > div.container > div > div > ul > li > a > img')
|
||||
.where((e) => e.attributes.containsKey('src'))
|
||||
.where((e) => e.attributes['src']!.contains("cover"))
|
||||
.map((e) => e.attributes['src'])
|
||||
.toList();
|
||||
|
||||
name = dom
|
||||
.querySelectorAll(
|
||||
'body > div.container > div > div > ul > li > p.manga-list-4-item-title > a')
|
||||
.where((e) => e.attributes.containsKey('title'))
|
||||
.map((e) => e.attributes['title'])
|
||||
.toList();
|
||||
}
|
||||
return mangaRes();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<dynamic>> getMangaChapterUrl({required Chapter chapter}) async {
|
||||
JavascriptRuntime? flutterJs;
|
||||
flutterJs = getJavascriptRuntime();
|
||||
extractSecretKey(String response, JavascriptRuntime? flutterJs) {
|
||||
var secretKeyScriptLocation =
|
||||
response.indexOf("eval(function(p,a,c,k,e,d)");
|
||||
var secretKeyScriptEndLocation =
|
||||
response.indexOf("</script>", secretKeyScriptLocation);
|
||||
var secretKeyScript = response
|
||||
.substring(secretKeyScriptLocation, secretKeyScriptEndLocation)
|
||||
.replaceAll("eval", "");
|
||||
var secretKeyDeobfuscatedScript =
|
||||
flutterJs!.evaluate(secretKeyScript).toString();
|
||||
var secretKeyStartLoc = secretKeyDeobfuscatedScript.indexOf("'");
|
||||
var secretKeyEndLoc = secretKeyDeobfuscatedScript.indexOf(";");
|
||||
|
||||
var secretKeyResultScript = secretKeyDeobfuscatedScript.substring(
|
||||
secretKeyStartLoc, secretKeyEndLoc);
|
||||
|
||||
return secretKeyResultScript;
|
||||
}
|
||||
|
||||
var link = "http://www.mangahere.cc${chapter.url!}";
|
||||
final response =
|
||||
await httpGet(url: link, source: "managhere", resDom: false) as String?;
|
||||
|
||||
dom.Document htmll = dom.Document.html(response!);
|
||||
int? pagesNumber = -1;
|
||||
if (htmll.querySelectorAll('body > div > div > span > a:').isNotEmpty) {
|
||||
final ta = htmll
|
||||
.querySelectorAll('body > div > div > span > a:')
|
||||
.map((e) => e.text.trim())
|
||||
.toList();
|
||||
ta.removeLast();
|
||||
pagesNumber = int.parse(ta.last);
|
||||
}
|
||||
if (pagesNumber == -1) {
|
||||
final script = htmll
|
||||
.getElementsByTagName("script")
|
||||
.firstWhere((e) => e.innerHtml.contains(
|
||||
"function(p,a,c,k,e,d)",
|
||||
))
|
||||
.innerHtml
|
||||
.replaceAll("eval", "");
|
||||
|
||||
String deobfuscatedScript = flutterJs.evaluate(script).toString();
|
||||
List<String> urlss = deobfuscatedScript
|
||||
.substring(
|
||||
deobfuscatedScript.indexOf("newImgs=['") + "newImgs=['".length,
|
||||
deobfuscatedScript.indexOf("'];"))
|
||||
.split("','");
|
||||
for (var tt in urlss) {
|
||||
pageUrls.add("https:$tt");
|
||||
}
|
||||
flutterJs.dispose();
|
||||
} else {
|
||||
var secretKey = extractSecretKey(response, flutterJs);
|
||||
|
||||
var chapterIdStartLoc = response.indexOf("chapterid");
|
||||
var chapterId = response
|
||||
.substring(
|
||||
chapterIdStartLoc + 11, response.indexOf(";", chapterIdStartLoc))
|
||||
.trim();
|
||||
|
||||
var pageBase = link.substring(0, link.lastIndexOf("/"));
|
||||
|
||||
for (int i = 1; i <= pagesNumber; i++) {
|
||||
var pageLink =
|
||||
"$pageBase/chapterfun.ashx?cid=$chapterId&page=$i&key=$secretKey";
|
||||
var responseText = "";
|
||||
|
||||
for (int tr = 1; tr <= 3; tr++) {
|
||||
var response = await http.get(Uri.parse(pageLink), headers: {
|
||||
"Referer": link,
|
||||
"Accept": "*/*",
|
||||
"Accept-Language": "en-US,en;q=0.9",
|
||||
"Connection": "keep-alive",
|
||||
"Host": "www.mangahere.cc",
|
||||
"X-Requested-With": "XMLHttpRequest"
|
||||
});
|
||||
responseText = response.body;
|
||||
if (responseText.isNotEmpty) {
|
||||
break;
|
||||
} else {
|
||||
secretKey = "";
|
||||
}
|
||||
}
|
||||
|
||||
var deobfuscatedScript =
|
||||
flutterJs.evaluate(responseText.replaceAll("eval", "")).toString();
|
||||
|
||||
var baseLinkStartPos = deobfuscatedScript.indexOf("pix=") + 5;
|
||||
var baseLinkEndPos =
|
||||
deobfuscatedScript.indexOf(";", baseLinkStartPos) - 1;
|
||||
var baseLink =
|
||||
deobfuscatedScript.substring(baseLinkStartPos, baseLinkEndPos);
|
||||
|
||||
var imageLinkStartPos = deobfuscatedScript.indexOf("pvalue=") + 9;
|
||||
var imageLinkEndPos =
|
||||
deobfuscatedScript.indexOf("\"", imageLinkStartPos);
|
||||
var imageLink =
|
||||
deobfuscatedScript.substring(imageLinkStartPos, imageLinkEndPos);
|
||||
pageUrls.add("https:$baseLink$imageLink");
|
||||
}
|
||||
|
||||
flutterJs.dispose();
|
||||
}
|
||||
return pageUrls;
|
||||
}
|
||||
}
|
||||
11
lib/sources/src/fr/japscan/japscan_source.dart
Normal file
11
lib/sources/src/fr/japscan/japscan_source.dart
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import 'package:mangayomi/models/source_model.dart';
|
||||
|
||||
SourceModel japscanSource = SourceModel(
|
||||
sourceName: "Japscan",
|
||||
url: "https://japscan.lol",
|
||||
lang: "fr",
|
||||
typeSource: TypeSource.single,
|
||||
logoUrl: '',
|
||||
isCloudflare: true,
|
||||
dateFormat: "d MMM yyyy",
|
||||
dateFormatLocale: "en_US");
|
||||
238
lib/sources/src/fr/japscan/src/japscan.dart
Normal file
238
lib/sources/src/fr/japscan/src/japscan.dart
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
// ignore_for_file: depend_on_referenced_packages
|
||||
|
||||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
import 'package:html/dom.dart' as dom;
|
||||
import 'package:html/dom.dart';
|
||||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/services/http_service/cloudflare/cloudflare_bypass.dart';
|
||||
import 'package:mangayomi/services/http_service/http_service.dart';
|
||||
import 'package:mangayomi/sources/service/service.dart';
|
||||
import 'package:mangayomi/sources/utils/utils.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
class Japscan extends MangaYomiServices {
|
||||
@override
|
||||
Future<GetMangaDetailModel?> getMangaDetail(
|
||||
{required String imageUrl,
|
||||
required String url,
|
||||
required String title,
|
||||
required String lang,
|
||||
required String source}) async {
|
||||
final dom =
|
||||
await httpGet(url: url, source: source, resDom: true) as Document?;
|
||||
if (dom!.querySelectorAll('.col-7 > p').isNotEmpty) {
|
||||
final images =
|
||||
dom.querySelectorAll('.col-5 ').map((e) => e.outerHtml).toList();
|
||||
RegExp exp = RegExp(r'src="([^"]+)"');
|
||||
|
||||
String? srcValue = exp.firstMatch(images[0])?.group(1);
|
||||
imageUrl = 'https://www.japscan.lol$srcValue';
|
||||
|
||||
if (dom.querySelectorAll('.col-7 > p').isNotEmpty) {
|
||||
final stat = dom
|
||||
.querySelectorAll('.col-7 > p')
|
||||
.where((element) => element.innerHtml.contains('Statut:'))
|
||||
.map((e) => e.text)
|
||||
.toList();
|
||||
if (stat.isNotEmpty) {
|
||||
status = stat[0].replaceAll('Statut:', '').trim();
|
||||
}
|
||||
|
||||
final auth = dom
|
||||
.querySelectorAll('.col-7 > p')
|
||||
.where((element) => element.innerHtml.contains('Auteur(s):'))
|
||||
.map((e) => e.text)
|
||||
.toList();
|
||||
if (auth.isNotEmpty) {
|
||||
author = auth[0].replaceAll('Auteur(s):', '').trim();
|
||||
}
|
||||
} else {
|
||||
author = "";
|
||||
status = "";
|
||||
}
|
||||
|
||||
final genres = dom
|
||||
.querySelectorAll('.col-7 > p')
|
||||
.where((element) => element.innerHtml.contains('Genre(s):'))
|
||||
.map((e) => e.text.replaceAll('Genre(s):', '').trim())
|
||||
.toList();
|
||||
if (genres.isNotEmpty) {
|
||||
for (var ok in genres[0].split(',')) {
|
||||
genre.add(ok);
|
||||
}
|
||||
}
|
||||
|
||||
final synop = dom
|
||||
.querySelectorAll('p.list-group-item ')
|
||||
.map((e) => e.text.trim())
|
||||
.toList();
|
||||
if (synop.isNotEmpty) {
|
||||
description = synop[0];
|
||||
}
|
||||
}
|
||||
|
||||
final urls =
|
||||
dom.querySelectorAll('.col-8 ').map((e) => e.outerHtml).toList();
|
||||
|
||||
for (var ok in urls) {
|
||||
RegExp exp = RegExp(r'href="([^"]+)"');
|
||||
|
||||
String? srcValue = exp.firstMatch(ok)?.group(1);
|
||||
chapterUrl.add('https://www.japscan.lol$srcValue');
|
||||
}
|
||||
|
||||
final chapterTitlee =
|
||||
dom.querySelectorAll('.col-8').map((e) => e.text.trim()).toList();
|
||||
|
||||
if (chapterTitlee.isNotEmpty) {
|
||||
for (var ok in chapterTitlee) {
|
||||
chapterTitle.add(ok);
|
||||
}
|
||||
}
|
||||
|
||||
final chapterDatee =
|
||||
dom.querySelectorAll('.col-4').map((e) => e.text.trim()).toList();
|
||||
if (chapterDatee.isNotEmpty) {
|
||||
for (var ok in chapterDatee) {
|
||||
chapterDate.add(parseDate(ok, source));
|
||||
}
|
||||
}
|
||||
return mangadetailRes(
|
||||
imageUrl: imageUrl, url: url, title: title, source: source);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<GetMangaModel?> getPopularManga(
|
||||
{required String source, required int page}) async {
|
||||
final dom = await httpGet(
|
||||
url: "https://www.japscan.lol/",
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
if (dom!.querySelectorAll('#top_mangas_week > ul > li ').isNotEmpty) {
|
||||
final urls = dom
|
||||
.querySelectorAll('#top_mangas_week > ul > li > a')
|
||||
.where((e) => e.attributes['href'].toString().contains('manga'))
|
||||
.map((e) => e.attributes['href'])
|
||||
.toList();
|
||||
for (var ok in urls) {
|
||||
url.add("https://www.japscan.lol$ok");
|
||||
}
|
||||
name = dom
|
||||
.querySelectorAll(
|
||||
'#top_mangas_week > ul > li > a.text-dark.font-weight-bold')
|
||||
.map((e) => e.innerHtml)
|
||||
.toList();
|
||||
for (var ia in name) {
|
||||
image.add("");
|
||||
}
|
||||
}
|
||||
return mangaRes();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<GetMangaModel?> searchManga(
|
||||
{required String source, required String query}) async {
|
||||
final dom = await httpGet(
|
||||
url: "https://www.google.com/search?q=${query.toLowerCase()}+japscan",
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
|
||||
if (dom!.querySelectorAll("div > div > div > div > div > a").isNotEmpty) {
|
||||
final urls = dom
|
||||
.querySelectorAll("div > div > div > div > div > a")
|
||||
.where((e) => e.attributes.containsKey('href'))
|
||||
.where((element) =>
|
||||
element.text.toLowerCase().contains("https://www.japscan."))
|
||||
.map((e) => e.attributes['href']
|
||||
.toString()
|
||||
.replaceAll('lecture-en-ligne', 'manga')
|
||||
.split("/"))
|
||||
.toList();
|
||||
List<String?> tt = [];
|
||||
List<String?> ta = [];
|
||||
for (var ok in urls) {
|
||||
tt.add("${ok[0]}//${ok[2]}/${ok[3]}/${ok[4]}/");
|
||||
ta.add(ok[4]
|
||||
.replaceAll('-', " ")
|
||||
.toString()
|
||||
.split(' ')
|
||||
.map((word) =>
|
||||
word.substring(0, 1).toUpperCase() + word.substring(1))
|
||||
.join(' '));
|
||||
}
|
||||
name = ta.toSet().toList();
|
||||
url = tt.toSet().toList();
|
||||
for (var a in url) {
|
||||
image.add("");
|
||||
}
|
||||
}
|
||||
return mangaRes();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<dynamic>> getMangaChapterUrl({required Chapter chapter}) async {
|
||||
final response = await httpGet(
|
||||
useUserAgent: true,
|
||||
url: chapter.url!,
|
||||
source: "japscan",
|
||||
resDom: false) as String?;
|
||||
RegExp regex = RegExp(r'<script src="/zjs/(.*?)"');
|
||||
Match? match = regex.firstMatch(response!);
|
||||
String zjsurl = match!.group(1)!;
|
||||
baseUrl = response;
|
||||
zjsUrl = "https://www.japscan.lol/zjs/$zjsurl";
|
||||
zjs();
|
||||
await Future.doWhile(() async {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
if (isOk == true) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return pageUrls;
|
||||
}
|
||||
|
||||
bool isOk = false;
|
||||
String? baseUrl;
|
||||
String? zjsUrl;
|
||||
zjs() async {
|
||||
final html = await cloudflareBypassHtml(
|
||||
url: zjsUrl!, source: "japscan", useUserAgent: true);
|
||||
dom.Document htmll = dom.Document.html(baseUrl!);
|
||||
final strings = html
|
||||
.replaceAll(RegExp(r'\\[(.*?)\\]'), '')
|
||||
.split(",")
|
||||
.map((s) => s.trim().replaceAll("'", "").split('').reversed.join());
|
||||
final stringLookupTables = strings
|
||||
.where((s) =>
|
||||
s.length == 62 &&
|
||||
s.split('').toSet().toList().sorted().join() ==
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
|
||||
.toList();
|
||||
|
||||
if (stringLookupTables.length != 2) {
|
||||
throw Exception("Expected only two lookup tables in ZJS");
|
||||
}
|
||||
|
||||
final scrambledData =
|
||||
htmll.getElementById("data")!.attributes['data-data']!;
|
||||
|
||||
for (var i = 0; i <= 1; i++) {
|
||||
final otherIndex = i == 0 ? 1 : 0;
|
||||
|
||||
final lookupTable = Map.fromIterables(stringLookupTables[i].split(''),
|
||||
stringLookupTables[otherIndex].split(''));
|
||||
try {
|
||||
final unscrambledData = scrambledData
|
||||
.split('')
|
||||
.map((char) => lookupTable[char] ?? char)
|
||||
.join();
|
||||
final decoded = utf8.decode(base64.decode(unscrambledData));
|
||||
final data = jsonDecode(decoded);
|
||||
pageUrls = data["imagesLink"].map((it) => it).toList();
|
||||
} catch (_) {}
|
||||
}
|
||||
isOk = true;
|
||||
}
|
||||
}
|
||||
10
lib/sources/src/fr/mangakawaii/mangakawaii_source.dart
Normal file
10
lib/sources/src/fr/mangakawaii/mangakawaii_source.dart
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
import 'package:mangayomi/models/source_model.dart';
|
||||
|
||||
SourceModel mangakawaiiSource = SourceModel(
|
||||
sourceName: "MangaKawaii",
|
||||
url: "https://www.mangakawaii.io",
|
||||
lang: "fr",
|
||||
typeSource: TypeSource.single,
|
||||
logoUrl: 'https://www.mangakawaii.io/assets/img/logo.png',
|
||||
dateFormat: "dd.MM.yyyy",
|
||||
dateFormatLocale: "en_US");
|
||||
206
lib/sources/src/fr/mangakawaii/src/mangakawaii.dart
Normal file
206
lib/sources/src/fr/mangakawaii/src/mangakawaii.dart
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
import 'package:html/dom.dart';
|
||||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/services/http_service/http_res_to_dom_html.dart';
|
||||
import 'package:mangayomi/services/http_service/http_service.dart';
|
||||
import 'package:mangayomi/sources/service/service.dart';
|
||||
import 'package:mangayomi/sources/src/all/comick/src/utils/utils.dart';
|
||||
import 'package:mangayomi/sources/utils/utils.dart';
|
||||
|
||||
class MangaKawaii extends MangaYomiServices {
|
||||
@override
|
||||
Future<GetMangaDetailModel?> getMangaDetail(
|
||||
{required String imageUrl,
|
||||
required String url,
|
||||
required String title,
|
||||
required String lang,
|
||||
required String source}) async {
|
||||
final dom = await httpGet(
|
||||
url: 'https://www.mangakawaii.io$url',
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
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(parseDate(
|
||||
"${DateTime.now().day}.${DateTime.now().month}.${DateTime.now().year}",
|
||||
source));
|
||||
}
|
||||
} else {
|
||||
for (var ok in url) {
|
||||
chapterDate.add(parseDate(
|
||||
ok.split(" ").first.toString().substring(0, 10), source));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return mangadetailRes(
|
||||
imageUrl: imageUrl, url: url, title: title, source: source);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<GetMangaModel?> getPopularManga(
|
||||
{required String source, required int page}) async {
|
||||
final dom = await httpGet(
|
||||
url: 'https://www.mangakawaii.io/',
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
if (dom!.querySelectorAll('a.hot-manga__item').isNotEmpty) {
|
||||
url = dom
|
||||
.querySelectorAll('a.hot-manga__item ')
|
||||
.where((e) => e.attributes.containsKey('href'))
|
||||
.map((e) => e.attributes['href'])
|
||||
.toList();
|
||||
name = dom
|
||||
.querySelectorAll('a > div > div.hot-manga__item-name')
|
||||
.map((e) => e.innerHtml)
|
||||
.toList();
|
||||
for (var ia in name) {
|
||||
image.add("");
|
||||
}
|
||||
}
|
||||
return mangaRes();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<GetMangaModel?> searchManga(
|
||||
{required String source, required String query}) async {
|
||||
final dom = await httpGet(
|
||||
url:
|
||||
'https://www.mangakawaii.io/search?query=${query.trim()}&search_type=manga',
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
if (dom!
|
||||
.querySelectorAll(
|
||||
'#page-content > div > div > ul > li > div.section__list-group-right > div.section__list-group-header > div > h4 > a')
|
||||
.isNotEmpty) {
|
||||
final ur = dom
|
||||
.querySelectorAll(
|
||||
'#page-content > div > div > ul > li > div.section__list-group-right > div.section__list-group-header > div > h4 > a')
|
||||
.where((e) => e.attributes.containsKey('href'))
|
||||
.map((e) => e.attributes['href'])
|
||||
.toList();
|
||||
for (var a in ur) {
|
||||
url.add(a!);
|
||||
}
|
||||
|
||||
final nam = dom
|
||||
.querySelectorAll(
|
||||
'#page-content > div > div > ul > li > div.section__list-group-right > div.section__list-group-header > div > h4 > a')
|
||||
.map((e) => e.text)
|
||||
.toList();
|
||||
for (var a in nam) {
|
||||
name.add(a);
|
||||
image.add('');
|
||||
}
|
||||
}
|
||||
return mangaRes();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<dynamic>> getMangaChapterUrl({required Chapter chapter}) async {
|
||||
final response =
|
||||
await httpGet(url: chapter.url!, source: "mangakawaii", resDom: false)
|
||||
as String?;
|
||||
var chapterSlug = RegExp("""var chapter_slug = "([^"]*)";""")
|
||||
.allMatches(response!)
|
||||
.last
|
||||
.group(1);
|
||||
var mangaSlug = RegExp("""var oeuvre_slug = "([^"]*)";""")
|
||||
.allMatches(response)
|
||||
.last
|
||||
.group(1);
|
||||
var pages = RegExp('''"page_image":"([^"]*)"''')
|
||||
.allMatches(response)
|
||||
.map((e) => e.group(1));
|
||||
|
||||
for (var tt in pages) {
|
||||
pageUrls.add(
|
||||
'https://cdn.mangakawaii.pics/uploads/manga/$mangaSlug/chapters_fr/$chapterSlug/$tt');
|
||||
}
|
||||
return pageUrls;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,191 +1,13 @@
|
|||
import 'package:mangayomi/source/source_model.dart';
|
||||
List<SourceModel> sourcesList = [
|
||||
SourceModel(
|
||||
sourceName: "MangaHere",
|
||||
url: "http://www.mangahere.cc",
|
||||
lang: "en",
|
||||
typeSource: TypeSource.single,
|
||||
logoUrl: 'http://static.mangahere.cc/v20210106/mangahere/images/logo.png',
|
||||
isFullData: true,
|
||||
dateFormat: "MMM dd,yyyy",
|
||||
dateFormatLocale: "en",
|
||||
),
|
||||
// SourceModel(
|
||||
// sourceName: "MangaSee",
|
||||
// url: "https://mangasee123.com",
|
||||
// lang: "en",
|
||||
// typeSource: TypeSource.single,
|
||||
// logoUrl: 'https://mangasee123.com/media/navbar.brand.png',
|
||||
// dateFormat: "MMM dd,yyyy",
|
||||
// dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: "MangaKawaii",
|
||||
url: "https://www.mangakawaii.io",
|
||||
lang: "fr",
|
||||
typeSource: TypeSource.single,
|
||||
logoUrl: 'https://www.mangakawaii.io/assets/img/logo.png',
|
||||
dateFormat: "dd.MM.yyyy",
|
||||
dateFormatLocale: "en_US"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: 'https://api.comick.fun/',
|
||||
lang: 'en',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl:
|
||||
'https://comick.app/_next/image?url=%2Fstatic%2Ficons%2Funicorn-64.png&w=144&q=75',
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: 'https://api.comick.fun/',
|
||||
lang: 'ar',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl:
|
||||
'https://comick.app/_next/image?url=%2Fstatic%2Ficons%2Funicorn-64.png&w=144&q=75',
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: 'https://api.comick.fun/',
|
||||
lang: 'pt',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl:
|
||||
'https://comick.app/_next/image?url=%2Fstatic%2Ficons%2Funicorn-64.png&w=144&q=75',
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: 'https://api.comick.fun/',
|
||||
lang: 'pt-br',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl:
|
||||
'https://comick.app/_next/image?url=%2Fstatic%2Ficons%2Funicorn-64.png&w=144&q=75',
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: 'https://api.comick.fun/',
|
||||
lang: 'it',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl:
|
||||
'https://comick.app/_next/image?url=%2Fstatic%2Ficons%2Funicorn-64.png&w=144&q=75',
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: 'https://api.comick.fun/',
|
||||
lang: 'ru',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl:
|
||||
'https://comick.app/_next/image?url=%2Fstatic%2Ficons%2Funicorn-64.png&w=144&q=75',
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: 'https://api.comick.fun/',
|
||||
lang: 'es',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl:
|
||||
'https://comick.app/_next/image?url=%2Fstatic%2Ficons%2Funicorn-64.png&w=144&q=75',
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: 'https://api.comick.fun/',
|
||||
lang: 'es-419',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl:
|
||||
'https://comick.app/_next/image?url=%2Fstatic%2Ficons%2Funicorn-64.png&w=144&q=75',
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: 'https://api.comick.fun/',
|
||||
lang: 'id',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl:
|
||||
'https://comick.app/_next/image?url=%2Fstatic%2Ficons%2Funicorn-64.png&w=144&q=75',
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: 'https://api.comick.fun/',
|
||||
lang: 'hi',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl:
|
||||
'https://comick.app/_next/image?url=%2Fstatic%2Ficons%2Funicorn-64.png&w=144&q=75',
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: 'https://api.comick.fun/',
|
||||
lang: 'de',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl:
|
||||
'https://comick.app/_next/image?url=%2Fstatic%2Ficons%2Funicorn-64.png&w=144&q=75',
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: 'https://api.comick.fun/',
|
||||
lang: 'ja',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl:
|
||||
'https://comick.app/_next/image?url=%2Fstatic%2Ficons%2Funicorn-64.png&w=144&q=75',
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: 'https://api.comick.fun/',
|
||||
lang: 'tr',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl:
|
||||
'https://comick.app/_next/image?url=%2Fstatic%2Ficons%2Funicorn-64.png&w=144&q=75',
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: 'https://api.comick.fun/',
|
||||
lang: 'pl',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl:
|
||||
'https://comick.app/_next/image?url=%2Fstatic%2Ficons%2Funicorn-64.png&w=144&q=75',
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: 'https://api.comick.fun/',
|
||||
lang: 'zh',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl:
|
||||
'https://comick.app/_next/image?url=%2Fstatic%2Ficons%2Funicorn-64.png&w=144&q=75',
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: 'https://api.comick.fun/',
|
||||
lang: 'zh-hk',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl:
|
||||
'https://comick.app/_next/image?url=%2Fstatic%2Ficons%2Funicorn-64.png&w=144&q=75',
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: 'Comick',
|
||||
url: 'https://api.comick.fun/',
|
||||
lang: 'fr',
|
||||
typeSource: TypeSource.comick,
|
||||
logoUrl:
|
||||
'https://comick.app/_next/image?url=%2Fstatic%2Ficons%2Funicorn-64.png&w=144&q=75',
|
||||
dateFormat: "yyyy-MM-dd'T'HH:mm:ss'Z'",
|
||||
dateFormatLocale: "en"),
|
||||
import 'package:mangayomi/models/source_model.dart';
|
||||
|
||||
List<SourceModel> mangathemesiaSourcesList = [
|
||||
SourceModel(
|
||||
sourceName: "KomikLab",
|
||||
url: "https://komiklab.com",
|
||||
lang: "en",
|
||||
typeSource: TypeSource.mangathemesia,
|
||||
logoUrl: '',
|
||||
dateFormat: "MMMM dd, yyyy",
|
||||
dateFormat: "MMMM dd, yyyy",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: "AnimatedGlitchedScans",
|
||||
|
|
@ -193,7 +15,7 @@ List<SourceModel> sourcesList = [
|
|||
lang: "en",
|
||||
typeSource: TypeSource.mangathemesia,
|
||||
logoUrl: '',
|
||||
dateFormat: "MMMM dd, yyyy",
|
||||
dateFormat: "MMMM dd, yyyy",
|
||||
dateFormatLocale: "en"),
|
||||
// SourceModel(
|
||||
// sourceName: "ArenaScans",
|
||||
|
|
@ -234,7 +56,7 @@ List<SourceModel> sourcesList = [
|
|||
lang: "en",
|
||||
typeSource: TypeSource.mangathemesia,
|
||||
logoUrl: '',
|
||||
dateFormat: "MMMM dd, yyyy",
|
||||
dateFormat: "MMMM dd, yyyy",
|
||||
dateFormatLocale: "en"),
|
||||
SourceModel(
|
||||
sourceName: "DiskusScan",
|
||||
|
|
@ -272,7 +94,7 @@ List<SourceModel> sourcesList = [
|
|||
typeSource: TypeSource.mangathemesia,
|
||||
logoUrl: '',
|
||||
isCloudflare: true,
|
||||
dateFormat: "MMMM dd, yyyy",
|
||||
dateFormat: "MMMM dd, yyyy",
|
||||
dateFormatLocale: "en"),
|
||||
|
||||
// SourceModel(
|
||||
|
|
@ -487,70 +309,4 @@ List<SourceModel> sourcesList = [
|
|||
'https://xcalibrscans.com/wp-content/uploads/2021/06/xcalibr-dark-v3.png',
|
||||
dateFormat: "MMMM dd, yyyy",
|
||||
dateFormatLocale: "en"),
|
||||
|
||||
// SourceModel(
|
||||
// sourceName: "Fallen Angels",
|
||||
// url: "https://manga.fascans.com",
|
||||
// lang: "en",
|
||||
// typeSource: TypeSource.mmrcms,
|
||||
// logoUrl: '',
|
||||
// dateFormat: "d MMM. yyyy",
|
||||
// dateFormatLocale: "en_US"),
|
||||
SourceModel(
|
||||
sourceName: "Scan FR",
|
||||
url: "https://www.scan-fr.org",
|
||||
lang: "fr",
|
||||
typeSource: TypeSource.mmrcms,
|
||||
logoUrl: '',
|
||||
dateFormat: "d MMM. yyyy",
|
||||
dateFormatLocale: "en_US"),
|
||||
SourceModel(
|
||||
sourceName: "Scan VF",
|
||||
url: "https://www.scan-vf.net",
|
||||
lang: "fr",
|
||||
typeSource: TypeSource.mmrcms,
|
||||
logoUrl: '',
|
||||
dateFormat: "d MMM. yyyy",
|
||||
dateFormatLocale: "en_US"), //
|
||||
SourceModel(
|
||||
sourceName: "Komikid",
|
||||
url: "https://www.komikid.com",
|
||||
lang: "id",
|
||||
typeSource: TypeSource.mmrcms,
|
||||
logoUrl: '',
|
||||
dateFormat: "d MMM. yyyy",
|
||||
dateFormatLocale: "en_US"),
|
||||
// SourceModel(
|
||||
// sourceName: "MangaHanta",
|
||||
// url: "http://mangahanta.com",
|
||||
// lang: "tr",
|
||||
// typeSource: TypeSource.mmrcms,
|
||||
// logoUrl: '',
|
||||
// dateFormat: "d MMM. yyyy",
|
||||
// dateFormatLocale: "en_US"),
|
||||
SourceModel(
|
||||
sourceName: "MangaID",
|
||||
url: "https://mangaid.click",
|
||||
lang: "id",
|
||||
typeSource: TypeSource.mmrcms,
|
||||
logoUrl: '',
|
||||
dateFormat: "d MMM. yyyy",
|
||||
dateFormatLocale: "en_US"),
|
||||
SourceModel(
|
||||
sourceName: "Jpmangas",
|
||||
url: "https://jpmangas.cc",
|
||||
lang: "fr",
|
||||
typeSource: TypeSource.mmrcms,
|
||||
logoUrl: '',
|
||||
dateFormat: "d MMM. yyyy",
|
||||
dateFormatLocale: "en_US"),
|
||||
SourceModel(
|
||||
sourceName: "Japscan",
|
||||
url: "https://japscan.lol",
|
||||
lang: "fr",
|
||||
typeSource: TypeSource.single,
|
||||
logoUrl: '',
|
||||
isCloudflare: true,
|
||||
dateFormat: "d MMM. yyyy",
|
||||
dateFormatLocale: "en_US"),
|
||||
];
|
||||
];
|
||||
272
lib/sources/src/multi/mangathemesia/src/mangathemesia.dart
Normal file
272
lib/sources/src/multi/mangathemesia/src/mangathemesia.dart
Normal file
|
|
@ -0,0 +1,272 @@
|
|||
import 'package:html/dom.dart';
|
||||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/services/http_service/http_service.dart';
|
||||
import 'package:mangayomi/sources/service/service.dart';
|
||||
import 'package:mangayomi/sources/utils/utils.dart';
|
||||
|
||||
class MangaThemeSia extends MangaYomiServices {
|
||||
@override
|
||||
Future<GetMangaDetailModel?> getMangaDetail(
|
||||
{required String imageUrl,
|
||||
required String url,
|
||||
required String title,
|
||||
required String lang,
|
||||
required String source}) async {
|
||||
final dom = await httpGet(
|
||||
url: url,
|
||||
source: source,
|
||||
resDom: true,
|
||||
useUserAgent: true) as Document?;
|
||||
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(parseDate(ok, source));
|
||||
}
|
||||
}
|
||||
}
|
||||
return mangadetailRes(
|
||||
imageUrl: imageUrl, url: url, title: title, source: source);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<GetMangaModel?> getPopularManga(
|
||||
{required String source, required int page}) async {
|
||||
source = source.toLowerCase();
|
||||
final dom = await httpGet(
|
||||
useUserAgent: true,
|
||||
url: '${getWpMangaUrl(source)}/manga/?title=&page=$page&order=popular',
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
if (dom!
|
||||
.querySelectorAll(
|
||||
'.utao .uta .imgu, .listupd .bs .bsx, .listo .bs .bsx')
|
||||
.isNotEmpty) {
|
||||
url = dom
|
||||
.querySelectorAll(
|
||||
'.utao .uta .imgu, .listupd .bs .bsx, .listo .bs .bsx')
|
||||
.map((e) {
|
||||
RegExp exp = RegExp(r'href="([^"]+)"');
|
||||
Iterable<Match> matches = exp.allMatches(e.innerHtml);
|
||||
String? firstMatch = matches.first.group(1);
|
||||
return firstMatch;
|
||||
}).toList();
|
||||
|
||||
image = dom
|
||||
.querySelectorAll(
|
||||
'.utao .uta .imgu, .listupd .bs .bsx, .listo .bs .bsx')
|
||||
.map((e) {
|
||||
RegExp exp = RegExp(r'src="([^"]+)"');
|
||||
Iterable<Match> matches = exp.allMatches(e.innerHtml);
|
||||
String? firstMatch = matches.first.group(1);
|
||||
return firstMatch;
|
||||
}).toList();
|
||||
|
||||
name = dom
|
||||
.querySelectorAll(
|
||||
'.utao .uta .imgu, .listupd .bs .bsx, .listo .bs .bsx ')
|
||||
.map((e) {
|
||||
RegExp exp = RegExp(r'title="([^"]+)"');
|
||||
Iterable<Match> matches = exp.allMatches(e.innerHtml);
|
||||
String? firstMatch = matches.first.group(1);
|
||||
return firstMatch;
|
||||
}).toList();
|
||||
}
|
||||
return mangaRes();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<GetMangaModel?> searchManga(
|
||||
{required String source, required String query}) async {
|
||||
final dom = await httpGet(
|
||||
url: '${getWpMangaUrl(source)}/?s=${query.trim()}',
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
if (dom!
|
||||
.querySelectorAll(
|
||||
'#content > div > div.postbody > div > div.listupd > div > div > a')
|
||||
.isNotEmpty) {
|
||||
url = dom
|
||||
.querySelectorAll(
|
||||
'#content > div > div.postbody > div > div.listupd > div > div > a ')
|
||||
.where((e) => e.attributes.containsKey('href'))
|
||||
.map((e) => e.attributes['href'])
|
||||
.toList();
|
||||
|
||||
image = dom
|
||||
.querySelectorAll(
|
||||
' #content > div > div.postbody > div > div.listupd > div > div > a > div > img')
|
||||
.where((e) => e.attributes.containsKey('src'))
|
||||
.map((e) => e.attributes['src'])
|
||||
.toList();
|
||||
|
||||
name = dom
|
||||
.querySelectorAll(
|
||||
'#content > div > div.postbody > div > div.listupd > div > div > a ')
|
||||
.where((e) => e.attributes.containsKey('title'))
|
||||
.map((e) => e.attributes['title'])
|
||||
.toList();
|
||||
}
|
||||
return mangaRes();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<dynamic>> getMangaChapterUrl({required Chapter chapter}) async {
|
||||
final dom = await httpGet(
|
||||
useUserAgent: true,
|
||||
url: chapter.url!,
|
||||
source: "mangathemesia",
|
||||
resDom: true) as Document?;
|
||||
if (dom!.querySelectorAll('#readerarea').isNotEmpty) {
|
||||
final ta =
|
||||
dom.querySelectorAll('#readerarea').map((e) => e.outerHtml).toList();
|
||||
final RegExp regex = RegExp(r'<img[^>]+src="([^"]+)"');
|
||||
final Iterable<Match> matches = regex.allMatches(ta.first);
|
||||
|
||||
final List<String?> urls = matches.map((m) => m.group(1)).toList();
|
||||
Iterable<Match> matchess = [];
|
||||
if (dom.querySelectorAll(' #select-paged ').isNotEmpty) {
|
||||
final ee = dom
|
||||
.querySelectorAll(' #select-paged ')
|
||||
.map((e) => e.outerHtml)
|
||||
.toList();
|
||||
final RegExp regexx = RegExp(r'value="([^"]+)"');
|
||||
matchess = regexx.allMatches(ee.first);
|
||||
}
|
||||
|
||||
final List<String?> urlss = matchess.map((m) => m.group(1)).toList();
|
||||
if (urls.length == 1 && urls.isNotEmpty) {
|
||||
for (var i = 0; i < urlss.length; i++) {
|
||||
if (urlss[i]!.length == 1) {
|
||||
pageUrls.add(
|
||||
urls.first!.replaceAll("001", '00${int.parse(urlss[i]!) + 1}'));
|
||||
} else if (urlss[i]!.length == 2) {
|
||||
pageUrls.add(
|
||||
urls.first!.replaceAll("001", '0${int.parse(urlss[i]!) + 1}'));
|
||||
} else if (urlss[i]!.length == 3) {
|
||||
pageUrls.add(
|
||||
urls.first!.replaceAll("001", '${int.parse(urlss[i]!) + 1}'));
|
||||
}
|
||||
}
|
||||
} else if (urls.length > 1 && urls.isNotEmpty) {
|
||||
for (var tt in urls) {
|
||||
pageUrls.add(tt);
|
||||
}
|
||||
}
|
||||
}
|
||||
return pageUrls;
|
||||
}
|
||||
}
|
||||
62
lib/sources/src/multi/mmrcms/mmrcms_source_list.dart
Normal file
62
lib/sources/src/multi/mmrcms/mmrcms_source_list.dart
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
import 'package:mangayomi/models/source_model.dart';
|
||||
|
||||
List<SourceModel> mmrcmsSourcesList = [
|
||||
|
||||
|
||||
// SourceModel(
|
||||
// sourceName: "Fallen Angels",
|
||||
// url: "https://manga.fascans.com",
|
||||
// lang: "en",
|
||||
// typeSource: TypeSource.mmrcms,
|
||||
// logoUrl: '',
|
||||
// dateFormat: "d MMM. yyyy",
|
||||
// dateFormatLocale: "en_US"),
|
||||
SourceModel(
|
||||
sourceName: "Scan FR",
|
||||
url: "https://www.scan-fr.org",
|
||||
lang: "fr",
|
||||
typeSource: TypeSource.mmrcms,
|
||||
logoUrl: '',
|
||||
dateFormat: "d MMM. yyyy",
|
||||
dateFormatLocale: "en_US"),
|
||||
SourceModel(
|
||||
sourceName: "Scan VF",
|
||||
url: "https://www.scan-vf.net",
|
||||
lang: "fr",
|
||||
typeSource: TypeSource.mmrcms,
|
||||
logoUrl: '',
|
||||
dateFormat: "d MMM. yyyy",
|
||||
dateFormatLocale: "en_US"), //
|
||||
SourceModel(
|
||||
sourceName: "Komikid",
|
||||
url: "https://www.komikid.com",
|
||||
lang: "id",
|
||||
typeSource: TypeSource.mmrcms,
|
||||
logoUrl: '',
|
||||
dateFormat: "d MMM. yyyy",
|
||||
dateFormatLocale: "en_US"),
|
||||
// SourceModel(
|
||||
// sourceName: "MangaHanta",
|
||||
// url: "http://mangahanta.com",
|
||||
// lang: "tr",
|
||||
// typeSource: TypeSource.mmrcms,
|
||||
// logoUrl: '',
|
||||
// dateFormat: "d MMM. yyyy",
|
||||
// dateFormatLocale: "en_US"),
|
||||
SourceModel(
|
||||
sourceName: "MangaID",
|
||||
url: "https://mangaid.click",
|
||||
lang: "id",
|
||||
typeSource: TypeSource.mmrcms,
|
||||
logoUrl: '',
|
||||
dateFormat: "d MMM. yyyy",
|
||||
dateFormatLocale: "en_US"),
|
||||
SourceModel(
|
||||
sourceName: "Jpmangas",
|
||||
url: "https://jpmangas.cc",
|
||||
lang: "fr",
|
||||
typeSource: TypeSource.mmrcms,
|
||||
logoUrl: '',
|
||||
dateFormat: "d MMM. yyyy",
|
||||
dateFormatLocale: "en_US"),
|
||||
];
|
||||
183
lib/sources/src/multi/mmrcms/src/mmrcms.dart
Normal file
183
lib/sources/src/multi/mmrcms/src/mmrcms.dart
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:html/dom.dart';
|
||||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/services/http_service/http_service.dart';
|
||||
import 'package:mangayomi/sources/service/service.dart';
|
||||
import 'package:mangayomi/sources/utils/utils.dart';
|
||||
import 'package:mangayomi/utils/reg_exp_matcher.dart';
|
||||
|
||||
class Mmrcms extends MangaYomiServices {
|
||||
@override
|
||||
Future<GetMangaDetailModel?> getMangaDetail(
|
||||
{required String imageUrl,
|
||||
required String url,
|
||||
required String title,
|
||||
required String lang,
|
||||
required String source}) async {
|
||||
final dom =
|
||||
await httpGet(url: url, source: source, resDom: true) as Document?;
|
||||
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(parseDate(da, source));
|
||||
}
|
||||
}
|
||||
return mangadetailRes(
|
||||
imageUrl: imageUrl, url: url, title: title, source: source);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<GetMangaModel?> getPopularManga(
|
||||
{required String source, required int page}) async {
|
||||
final dom = await httpGet(
|
||||
url:
|
||||
'${getWpMangaUrl(source)}/filterList?page=$page&sortBy=views&asc=false',
|
||||
source: source,
|
||||
resDom: true) as Document?;
|
||||
final urlElement = dom!.getElementsByClassName('chart-title');
|
||||
for (var e in urlElement) {
|
||||
RegExp exp = RegExp(r'href="([^"]+)"');
|
||||
Iterable<Match> matches = exp.allMatches(e.outerHtml);
|
||||
String? firstMatch = matches.first.group(1);
|
||||
url.add(firstMatch);
|
||||
name.add(e.text);
|
||||
}
|
||||
final imgElement = dom.getElementsByTagName('img');
|
||||
for (var e in imgElement) {
|
||||
RegExp exp = RegExp(r'src="([^"]+)"');
|
||||
Iterable<Match> matches = exp.allMatches(e.outerHtml);
|
||||
String? firstMatch = matches.first.group(1);
|
||||
image.add(firstMatch);
|
||||
}
|
||||
return mangaRes();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<GetMangaModel?> searchManga(
|
||||
{required String source, required String query}) async {
|
||||
final response = await httpGet(
|
||||
url: '${getWpMangaUrl(source)}/search?query=${query.trim()}',
|
||||
source: source,
|
||||
resDom: false) as String?;
|
||||
final rep = jsonDecode(response!);
|
||||
for (var ok in rep['suggestions']) {
|
||||
if (source == 'Read Comics Online') {
|
||||
url.add('${getWpMangaUrl(source)}/comic/${ok['data']}');
|
||||
} else if (source == 'Scan VF') {
|
||||
url.add('${getWpMangaUrl(source)}/${ok['data']}');
|
||||
} else {
|
||||
url.add('${getWpMangaUrl(source)}/manga/${ok['data']}');
|
||||
}
|
||||
name.add(ok["value"]);
|
||||
image.add('');
|
||||
}
|
||||
return mangaRes();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<dynamic>> getMangaChapterUrl({required Chapter chapter}) async {
|
||||
final dom = await httpGet(
|
||||
useUserAgent: true,
|
||||
url: chapter.url!,
|
||||
source: chapter.manga.value!.source!.toLowerCase(),
|
||||
resDom: true) as Document?;
|
||||
if (dom!.querySelectorAll('#all > .img-responsive').isNotEmpty) {
|
||||
pageUrls = dom.querySelectorAll('#all > .img-responsive').map((e) {
|
||||
final RegExp regexx = RegExp(r'data-src="([^"]+)"');
|
||||
if (chapter.manga.value!.source!.toLowerCase() == 'fr scan') {
|
||||
return regexx
|
||||
.allMatches(e.outerHtml)
|
||||
.first
|
||||
.group(1)!
|
||||
.replaceAll('//', 'https://')
|
||||
.replaceAll(RegExp(r"\s+\b|\b\s"), "");
|
||||
}
|
||||
return regexx
|
||||
.allMatches(e.outerHtml)
|
||||
.first
|
||||
.group(1)!
|
||||
.replaceAll(RegExp(r"\s+\b|\b\s"), "");
|
||||
}).toList();
|
||||
}
|
||||
return pageUrls;
|
||||
}
|
||||
}
|
||||
65
lib/sources/utils/utils.dart
Normal file
65
lib/sources/utils/utils.dart
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
import 'package:intl/intl.dart';
|
||||
import 'package:mangayomi/models/source_model.dart';
|
||||
import 'package:mangayomi/sources/source_list.dart';
|
||||
|
||||
String getWpMangaUrl(String source) {
|
||||
String url = "";
|
||||
for (var i = 0; i < sourcesList.length; i++) {
|
||||
if (sourcesList[i].sourceName.toLowerCase() == source.toLowerCase()) {
|
||||
url = sourcesList[i].url;
|
||||
}
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
TypeSource getWpMangTypeSource(String source) {
|
||||
TypeSource? typeSource;
|
||||
for (var i = 0; i < sourcesList.length; i++) {
|
||||
if (sourcesList[i].sourceName.toLowerCase() == source.toLowerCase()) {
|
||||
typeSource = sourcesList[i].typeSource;
|
||||
}
|
||||
}
|
||||
return typeSource!;
|
||||
}
|
||||
|
||||
String getFormatDate(String source) {
|
||||
String? dateFormat;
|
||||
for (var i = 0; i < sourcesList.length; i++) {
|
||||
if (sourcesList[i].sourceName.toLowerCase() == source.toLowerCase()) {
|
||||
dateFormat = sourcesList[i].dateFormat;
|
||||
}
|
||||
}
|
||||
return dateFormat!;
|
||||
}
|
||||
|
||||
String getFormatDateLocale(String source) {
|
||||
String? dateFormatLocale;
|
||||
for (var i = 0; i < sourcesList.length; i++) {
|
||||
if (sourcesList[i].sourceName.toLowerCase() == source.toLowerCase()) {
|
||||
dateFormatLocale = sourcesList[i].dateFormatLocale;
|
||||
}
|
||||
}
|
||||
return dateFormatLocale!;
|
||||
}
|
||||
|
||||
bool isCloudflare(String source) {
|
||||
bool? isCloudflare;
|
||||
for (var i = 0; i < sourcesList.length; i++) {
|
||||
if (sourcesList[i].sourceName.toLowerCase() == source.toLowerCase()) {
|
||||
isCloudflare = sourcesList[i].isCloudflare;
|
||||
}
|
||||
}
|
||||
return isCloudflare!;
|
||||
}
|
||||
|
||||
String utilDate(String data) {
|
||||
DateTime date = DateTime.parse(data);
|
||||
return date.millisecondsSinceEpoch.toString();
|
||||
}
|
||||
|
||||
parseDate(String data, String source) {
|
||||
source = source.toLowerCase();
|
||||
DateTime date = DateFormat(getFormatDate(source), getFormatDateLocale(source))
|
||||
.parse(data);
|
||||
return date.millisecondsSinceEpoch.toString();
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:mangayomi/providers/storage_provider.dart';
|
||||
import 'package:mangayomi/source/source_model.dart';
|
||||
import 'package:mangayomi/models/source_model.dart';
|
||||
import 'package:mangayomi/views/browse/extension/extension_screen.dart';
|
||||
import 'package:mangayomi/views/browse/migrate_screen.dart';
|
||||
import 'package:mangayomi/views/browse/sources_screen.dart';
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:mangayomi/providers/hive_provider.dart';
|
||||
import 'package:mangayomi/source/source_list.dart';
|
||||
import 'package:mangayomi/source/source_model.dart';
|
||||
import 'package:mangayomi/models/source_model.dart';
|
||||
import 'package:mangayomi/sources/source_list.dart';
|
||||
import 'package:mangayomi/utils/lang.dart';
|
||||
import 'package:mangayomi/views/browse/extension/widgets/extension_lang_list_tile_widget.dart';
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||
import 'package:grouped_list/grouped_list.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:mangayomi/providers/hive_provider.dart';
|
||||
import 'package:mangayomi/source/source_model.dart';
|
||||
import 'package:mangayomi/models/source_model.dart';
|
||||
import 'package:mangayomi/utils/lang.dart';
|
||||
import 'package:mangayomi/views/browse/extension/refresh_filter_data.dart';
|
||||
import 'package:mangayomi/views/browse/extension/widgets/extension_list_tile_widget.dart';
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:mangayomi/providers/hive_provider.dart';
|
||||
import 'package:mangayomi/source/source_list.dart';
|
||||
import 'package:mangayomi/source/source_model.dart';
|
||||
import 'package:mangayomi/models/source_model.dart';
|
||||
import 'package:mangayomi/sources/source_list.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
part 'refresh_filter_data.g.dart';
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import 'package:mangayomi/models/manga.dart';
|
|||
import 'package:mangayomi/providers/hive_provider.dart';
|
||||
import 'package:mangayomi/services/get_manga_detail.dart';
|
||||
import 'package:mangayomi/services/search_manga.dart';
|
||||
import 'package:mangayomi/source/source_model.dart';
|
||||
import 'package:mangayomi/models/source_model.dart';
|
||||
import 'package:mangayomi/utils/cached_network.dart';
|
||||
import 'package:mangayomi/utils/headers.dart';
|
||||
import 'package:mangayomi/utils/lang.dart';
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import 'package:grouped_list/grouped_list.dart';
|
|||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:mangayomi/models/manga_type.dart';
|
||||
import 'package:mangayomi/providers/hive_provider.dart';
|
||||
import 'package:mangayomi/source/source_model.dart';
|
||||
import 'package:mangayomi/models/source_model.dart';
|
||||
import 'package:mangayomi/utils/headers.dart';
|
||||
import 'package:mangayomi/utils/lang.dart';
|
||||
import 'package:mangayomi/views/browse/extension/refresh_filter_data.dart';
|
||||
|
|
|
|||
|
|
@ -866,7 +866,7 @@ class ChapterSetDownloadStateProvider
|
|||
}
|
||||
|
||||
String _$chaptersListttStateHash() =>
|
||||
r'2f81698d88c8087360e33c19884bfbb018604269';
|
||||
r'5f1b0d2be32fcb904c12c5735f1340c8b33400a9';
|
||||
|
||||
/// See also [ChaptersListttState].
|
||||
@ProviderFor(ChaptersListttState)
|
||||
|
|
|
|||
|
|
@ -1,12 +1,8 @@
|
|||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/utils/date.dart';
|
||||
import 'package:mangayomi/views/manga/reader/providers/push_router.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/utils/colors.dart';
|
||||
import 'package:mangayomi/utils/utils.dart';
|
||||
import 'package:mangayomi/views/manga/detail/providers/state_providers.dart';
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ Future<List<dynamic>> downloadChapter(
|
|||
DownloadChapterRef ref, {
|
||||
required Chapter chapter,
|
||||
}) async {
|
||||
List urll = [];
|
||||
List pageUrls = [];
|
||||
List<DownloadTask> tasks = [];
|
||||
final StorageProvider storageProvider = StorageProvider();
|
||||
await storageProvider.requestPermission();
|
||||
|
|
@ -39,8 +39,8 @@ Future<List<dynamic>> downloadChapter(
|
|||
chapter: chapter,
|
||||
).future)
|
||||
.then((value) {
|
||||
if (value.urll.isNotEmpty) {
|
||||
urll = value.urll;
|
||||
if (value.pageUrls.isNotEmpty) {
|
||||
pageUrls = value.pageUrls;
|
||||
isOk = true;
|
||||
}
|
||||
});
|
||||
|
|
@ -52,8 +52,8 @@ Future<List<dynamic>> downloadChapter(
|
|||
return true;
|
||||
});
|
||||
|
||||
if (urll.isNotEmpty) {
|
||||
for (var index = 0; index < urll.length; index++) {
|
||||
if (pageUrls.isNotEmpty) {
|
||||
for (var index = 0; index < pageUrls.length; index++) {
|
||||
final path2 = Directory("${path1.path}downloads/");
|
||||
final path4 = Directory(
|
||||
"${path2.path}${manga.source} (${manga.lang!.toUpperCase()})/");
|
||||
|
|
@ -83,9 +83,9 @@ Future<List<dynamic>> downloadChapter(
|
|||
if (await File("${path.path}" "${padIndex(index + 1)}.jpg").exists()) {
|
||||
} else {
|
||||
tasks.add(DownloadTask(
|
||||
taskId: urll[index],
|
||||
taskId: pageUrls[index],
|
||||
headers: headers(manga.source!),
|
||||
url: urll[index],
|
||||
url: pageUrls[index],
|
||||
filename: "${padIndex(index + 1)}.jpg",
|
||||
baseDirectory:
|
||||
Platform.isWindows || Platform.isMacOS || Platform.isLinux
|
||||
|
|
@ -104,9 +104,9 @@ Future<List<dynamic>> downloadChapter(
|
|||
if (await File("${path.path}" "${padIndex(index + 1)}.jpg").exists()) {
|
||||
} else {
|
||||
tasks.add(DownloadTask(
|
||||
taskId: urll[index],
|
||||
taskId: pageUrls[index],
|
||||
headers: headers(manga.source!),
|
||||
url: urll[index],
|
||||
url: pageUrls[index],
|
||||
filename: "${padIndex(index + 1)}.jpg",
|
||||
baseDirectory:
|
||||
Platform.isWindows || Platform.isMacOS || Platform.isLinux
|
||||
|
|
@ -122,7 +122,7 @@ Future<List<dynamic>> downloadChapter(
|
|||
}
|
||||
}
|
||||
}
|
||||
if (tasks.isEmpty && urll.isNotEmpty) {
|
||||
if (tasks.isEmpty && pageUrls.isNotEmpty) {
|
||||
final model = DownloadModel(
|
||||
chapterId: chapter.id,
|
||||
mangaName: manga.name,
|
||||
|
|
@ -133,7 +133,7 @@ Future<List<dynamic>> downloadChapter(
|
|||
total: 0,
|
||||
isDownload: true,
|
||||
mangaId: manga.id!,
|
||||
taskIds: urll,
|
||||
taskIds: pageUrls,
|
||||
isStartDownload: false);
|
||||
|
||||
ref
|
||||
|
|
@ -150,7 +150,7 @@ Future<List<dynamic>> downloadChapter(
|
|||
chapterId: chapter.id,
|
||||
total: tasks.length,
|
||||
isDownload: (succeeded == tasks.length) ? true : false,
|
||||
taskIds: urll,
|
||||
taskIds: pageUrls,
|
||||
isStartDownload: true,
|
||||
chapterName: chapter.name!,
|
||||
mangaSource: manga.source,
|
||||
|
|
@ -182,5 +182,5 @@ Future<List<dynamic>> downloadChapter(
|
|||
);
|
||||
}
|
||||
}
|
||||
return urll;
|
||||
return pageUrls;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'download_provider.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$downloadChapterHash() => r'240d09a7cf3726a4b75c2a45ef12a50de20d5a0e';
|
||||
String _$downloadChapterHash() => r'd750be212254a2aefbbb7825b98235dafe41ace5';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import 'package:go_router/go_router.dart';
|
|||
import 'package:mangayomi/models/manga_type.dart';
|
||||
import 'package:mangayomi/services/get_manga_detail.dart';
|
||||
import 'package:mangayomi/services/get_popular_manga.dart';
|
||||
import 'package:mangayomi/sources/utils/utils.dart';
|
||||
import 'package:mangayomi/utils/colors.dart';
|
||||
import 'package:mangayomi/views/manga/home/manga_search_screen.dart';
|
||||
import 'package:mangayomi/views/widgets/bottom_text_widget.dart';
|
||||
|
|
|
|||
|
|
@ -40,12 +40,12 @@ class MangaReaderView extends ConsumerWidget {
|
|||
ref.read(readerControllerProvider(chapter: chapter).notifier);
|
||||
return chapterData.when(
|
||||
data: (data) {
|
||||
if (data.urll.isEmpty) {
|
||||
if (data.pageUrls.isEmpty) {
|
||||
Navigator.pop(context);
|
||||
}
|
||||
return MangaChapterPageGallery(
|
||||
path: data.path!,
|
||||
url: data.urll,
|
||||
url: data.pageUrls,
|
||||
readerController: readerController,
|
||||
isLocaleList: data.isLocaleList,
|
||||
chapter: chapter,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:mangayomi/providers/hive_provider.dart';
|
||||
import 'package:mangayomi/utils/colors.dart';
|
||||
import 'package:mangayomi/views/more/settings/appearance/providers/flex_scheme_color_state_provider.dart';
|
||||
import 'package:mangayomi/views/more/settings/appearance/providers/theme_mode_state_provider.dart';
|
||||
// import 'package:rive/rive.dart';
|
||||
|
||||
|
|
@ -17,13 +19,23 @@ class _DarkModeButtonState extends ConsumerState<DarkModeButton> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
bool isLight = ref.watch(themeModeStateProvider);
|
||||
|
||||
return ListTile(
|
||||
onTap: () {
|
||||
int flexColorIndex = ref
|
||||
.watch(hiveBoxSettingsProvider)
|
||||
.get('FlexColorIndex', defaultValue: 7);
|
||||
if (!isLight == true) {
|
||||
ref.read(themeModeStateProvider.notifier).setLightTheme();
|
||||
} else {
|
||||
ref.read(themeModeStateProvider.notifier).setDarkTheme();
|
||||
}
|
||||
|
||||
!isLight
|
||||
? ref.read(flexSchemeColorStateProvider.notifier).setTheme(
|
||||
ThemeAA.schemes[flexColorIndex].light, flexColorIndex)
|
||||
: ref.read(flexSchemeColorStateProvider.notifier).setTheme(
|
||||
ThemeAA.schemes[flexColorIndex].dark, flexColorIndex);
|
||||
},
|
||||
title: const Text("Dark mode"),
|
||||
subtitle: Text(
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import 'package:mangayomi/main.dart';
|
|||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/services/get_manga_detail.dart';
|
||||
import 'package:mangayomi/sources/service/service.dart';
|
||||
import 'package:mangayomi/utils/cached_network.dart';
|
||||
import 'package:mangayomi/utils/headers.dart';
|
||||
import 'package:mangayomi/views/widgets/bottom_text_widget.dart';
|
||||
|
|
|
|||
Loading…
Reference in a new issue