mirror of
https://github.com/kodjodevf/mangayomi.git
synced 2026-04-21 16:01:58 +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
|
// ignore_for_file: depend_on_referenced_packages
|
||||||
import 'dart:developer';
|
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:fast_cached_network_image/fast_cached_network_image.dart';
|
import 'package:fast_cached_network_image/fast_cached_network_image.dart';
|
||||||
import 'package:flex_color_scheme/flex_color_scheme.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/utils/constant.dart';
|
||||||
import 'package:mangayomi/models/manga.dart';
|
import 'package:mangayomi/models/manga.dart';
|
||||||
import 'package:mangayomi/router/router.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/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/blend_level_state_provider.dart';
|
||||||
import 'package:mangayomi/views/more/settings/appearance/providers/flex_scheme_color_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:hive_flutter/hive_flutter.dart';
|
||||||
import 'package:mangayomi/models/download_model.dart';
|
import 'package:mangayomi/models/download_model.dart';
|
||||||
import 'package:mangayomi/utils/constant.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:mangayomi/views/manga/reader/providers/reader_controller_provider.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.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:async';
|
||||||
import 'dart:convert';
|
|
||||||
import 'dart:io';
|
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/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/hive_provider.dart';
|
||||||
import 'package:mangayomi/providers/storage_provider.dart';
|
import 'package:mangayomi/providers/storage_provider.dart';
|
||||||
import 'package:mangayomi/services/http_service/cloudflare/cloudflare_bypass.dart';
|
import 'package:mangayomi/sources/src/all/comick/src/comick.dart';
|
||||||
import 'package:mangayomi/services/get_popular_manga.dart';
|
import 'package:mangayomi/sources/src/en/mangahere/src/mangahere.dart';
|
||||||
import 'package:mangayomi/services/http_service/http_service.dart';
|
import 'package:mangayomi/sources/src/fr/japscan/src/japscan.dart';
|
||||||
import 'package:mangayomi/source/source_model.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/utils/reg_exp_matcher.dart';
|
||||||
import 'package:mangayomi/views/more/settings/providers/incognito_mode_state_provider.dart';
|
import 'package:mangayomi/views/more/settings/providers/incognito_mode_state_provider.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.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';
|
part 'get_manga_chapter_url.g.dart';
|
||||||
|
|
||||||
class GetMangaChapterUrlModel {
|
class GetMangaChapterUrlModel {
|
||||||
Directory? path;
|
Directory? path;
|
||||||
List urll = [];
|
List pageUrls = [];
|
||||||
List<bool> isLocaleList = [];
|
List<bool> isLocaleList = [];
|
||||||
GetMangaChapterUrlModel(
|
GetMangaChapterUrlModel(
|
||||||
{required this.path, required this.urll, required this.isLocaleList});
|
{required this.path, required this.pageUrls, required this.isLocaleList});
|
||||||
}
|
}
|
||||||
|
|
||||||
@riverpod
|
@riverpod
|
||||||
|
|
@ -33,127 +30,35 @@ Future<GetMangaChapterUrlModel> getMangaChapterUrl(
|
||||||
GetMangaChapterUrlRef ref, {
|
GetMangaChapterUrlRef ref, {
|
||||||
required Chapter chapter,
|
required Chapter chapter,
|
||||||
}) async {
|
}) async {
|
||||||
bool isOk = false;
|
|
||||||
Directory? path;
|
Directory? path;
|
||||||
List urll = [];
|
List pageUrls = [];
|
||||||
String? baseUrl;
|
|
||||||
String? zjsUrl;
|
|
||||||
final manga = chapter.manga.value!;
|
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 = [];
|
List<bool> isLocaleList = [];
|
||||||
String source = manga.source!.toLowerCase();
|
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",
|
"${manga.lang}-${manga.source}/${manga.name}/${chapter.name}-pageurl",
|
||||||
defaultValue: []);
|
defaultValue: []);
|
||||||
final incognitoMode = ref.watch(incognitoModeStateProvider);
|
final incognitoMode = ref.watch(incognitoModeStateProvider);
|
||||||
path = await StorageProvider().getMangaChapterDirectory(chapter);
|
path = await StorageProvider().getMangaChapterDirectory(chapter);
|
||||||
|
|
||||||
if (pagesUrl.isNotEmpty) {
|
if (hivePagesUrls.isNotEmpty) {
|
||||||
urll = pagesUrl;
|
pageUrls = hivePagesUrls;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********/
|
/*********/
|
||||||
/*comick*/
|
/*comick*/
|
||||||
/********/
|
/********/
|
||||||
else if (getWpMangTypeSource(source) == TypeSource.comick) {
|
|
||||||
String mangaId = chapter.url!.split('/').last.split('-').first;
|
|
||||||
|
|
||||||
final response = await httpGet(
|
else if (getWpMangTypeSource(source) == TypeSource.comick) {
|
||||||
url: 'https://api.comick.fun/chapter/$mangaId?tachiyomi=true',
|
pageUrls = await Comick().getMangaChapterUrl(chapter: chapter);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*************/
|
/*************/
|
||||||
/*mangathemesia*/
|
/*mangathemesia*/
|
||||||
/**************/
|
/**************/
|
||||||
|
|
||||||
else if (getWpMangTypeSource(source) == TypeSource.mangathemesia) {
|
else if (getWpMangTypeSource(source) == TypeSource.mangathemesia) {
|
||||||
final dom = await httpGet(
|
pageUrls = await MangaThemeSia().getMangaChapterUrl(chapter: chapter);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********/
|
/***********/
|
||||||
|
|
@ -161,25 +66,7 @@ Future<GetMangaChapterUrlModel> getMangaChapterUrl(
|
||||||
/***********/
|
/***********/
|
||||||
|
|
||||||
else if (source == 'mangakawaii') {
|
else if (source == 'mangakawaii') {
|
||||||
final response =
|
pageUrls = await MangaKawaii().getMangaChapterUrl(chapter: chapter);
|
||||||
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');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********/
|
/***********/
|
||||||
|
|
@ -187,168 +74,32 @@ Future<GetMangaChapterUrlModel> getMangaChapterUrl(
|
||||||
/***********/
|
/***********/
|
||||||
|
|
||||||
else if (getWpMangTypeSource(source) == TypeSource.mmrcms) {
|
else if (getWpMangTypeSource(source) == TypeSource.mmrcms) {
|
||||||
final dom = await httpGet(
|
pageUrls = await Mmrcms().getMangaChapterUrl(chapter: chapter);
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********/
|
/***********/
|
||||||
/*mangahere*/
|
/*mangahere*/
|
||||||
/***********/
|
/***********/
|
||||||
|
|
||||||
else if (source == 'mangahere') {
|
else if (source == 'mangahere') {
|
||||||
JavascriptRuntime? flutterJs;
|
pageUrls = await Mangahere().getMangaChapterUrl(chapter: chapter);
|
||||||
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;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if (urll.isNotEmpty) {
|
|
||||||
|
/***********/
|
||||||
|
/*japscan*/
|
||||||
|
/***********/
|
||||||
|
|
||||||
|
else if (source == 'japscan') {
|
||||||
|
pageUrls = await Japscan().getMangaChapterUrl(chapter: chapter);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pageUrls.isNotEmpty) {
|
||||||
if (!incognitoMode) {
|
if (!incognitoMode) {
|
||||||
ref.watch(hiveBoxMangaProvider).put(
|
ref.watch(hiveBoxMangaProvider).put(
|
||||||
"${manga.lang}-${manga.source}/${manga.name}/${chapter.name}-pageurl",
|
"${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()) {
|
if (await File("${path!.path}" "${padIndex(i + 1)}.jpg").exists()) {
|
||||||
isLocaleList.add(true);
|
isLocaleList.add(true);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -358,5 +109,5 @@ Future<GetMangaChapterUrlModel> getMangaChapterUrl(
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetMangaChapterUrlModel(
|
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() =>
|
String _$getMangaChapterUrlHash() =>
|
||||||
r'bb23f4789336a4970dddaaf61707998a9c79bcb5';
|
r'4daf1dc296255c64ca0ee2cf963dd98b3595d93c';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
|
|
|
||||||
|
|
@ -1,89 +1,16 @@
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'package:mangayomi/models/source_model.dart';
|
||||||
import 'dart:developer';
|
import 'package:mangayomi/sources/service/service.dart';
|
||||||
import 'package:html/dom.dart';
|
import 'package:mangayomi/sources/src/all/comick/src/comick.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:mangayomi/sources/src/en/mangahere/src/mangahere.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:mangayomi/sources/src/fr/japscan/src/japscan.dart';
|
||||||
import 'package:mangayomi/models/chapter.dart';
|
import 'package:mangayomi/sources/src/fr/mangakawaii/src/mangakawaii.dart';
|
||||||
import 'package:mangayomi/models/comick/manga_chapter_detail.dart';
|
import 'package:mangayomi/sources/src/multi/mangathemesia/src/mangathemesia.dart';
|
||||||
import 'package:mangayomi/models/comick/manga_detail_comick.dart';
|
import 'package:mangayomi/sources/src/multi/mmrcms/src/mmrcms.dart';
|
||||||
import 'package:mangayomi/services/get_popular_manga.dart';
|
import 'package:mangayomi/sources/utils/utils.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:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
part 'get_manga_detail.g.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
|
@riverpod
|
||||||
Future<GetMangaDetailModel> getMangaDetail(GetMangaDetailRef ref,
|
Future<GetMangaDetailModel> getMangaDetail(GetMangaDetailRef ref,
|
||||||
{required String imageUrl,
|
{required String imageUrl,
|
||||||
|
|
@ -91,305 +18,30 @@ Future<GetMangaDetailModel> getMangaDetail(GetMangaDetailRef ref,
|
||||||
required String title,
|
required String title,
|
||||||
required String lang,
|
required String lang,
|
||||||
required String source}) async {
|
required String source}) async {
|
||||||
List<String> genre = [];
|
GetMangaDetailModel? mangadetail;
|
||||||
String? author;
|
|
||||||
String? status;
|
|
||||||
List<String> chapterTitle = [];
|
|
||||||
List<String> chapterUrl = [];
|
|
||||||
List<String> chapterDate = [];
|
|
||||||
String? description;
|
|
||||||
List<Chapter> chapters = [];
|
|
||||||
List<String> scanlators = [];
|
|
||||||
|
|
||||||
/********/
|
/********/
|
||||||
/*comick*/
|
/*comick*/
|
||||||
/********/
|
/********/
|
||||||
|
|
||||||
if (getWpMangTypeSource(source.toLowerCase()) == TypeSource.comick) {
|
if (getWpMangTypeSource(source.toLowerCase()) == TypeSource.comick) {
|
||||||
final response = await httpGet(
|
mangadetail = await Comick().getMangaDetail(
|
||||||
url: 'https://api.comick.fun$url?tachiyomi=true',
|
imageUrl: imageUrl, url: url, title: title, lang: lang, source: source);
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/*************/
|
/*************/
|
||||||
/*mangathemesia*/
|
/*mangathemesia*/
|
||||||
/**************/
|
/**************/
|
||||||
|
|
||||||
if (getWpMangTypeSource(source.toLowerCase()) == TypeSource.mangathemesia) {
|
if (getWpMangTypeSource(source.toLowerCase()) == TypeSource.mangathemesia) {
|
||||||
final dom = await httpGet(
|
mangadetail = await MangaThemeSia().getMangaDetail(
|
||||||
url: url,
|
imageUrl: imageUrl, url: url, title: title, lang: lang, source: source);
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/***********/
|
/***********/
|
||||||
/*mangakawaii*/
|
/*mangakawaii*/
|
||||||
/***********/
|
/***********/
|
||||||
else if (source.toLowerCase() == "mangakawaii") {
|
else if (source.toLowerCase() == "mangakawaii") {
|
||||||
final dom = await httpGet(
|
mangadetail = await MangaKawaii().getMangaDetail(
|
||||||
url: 'https://www.mangakawaii.io$url',
|
imageUrl: imageUrl, url: url, title: title, lang: lang, source: source);
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********/
|
/***********/
|
||||||
|
|
@ -397,293 +49,25 @@ Future<GetMangaDetailModel> getMangaDetail(GetMangaDetailRef ref,
|
||||||
/***********/
|
/***********/
|
||||||
|
|
||||||
else if (getWpMangTypeSource(source.toLowerCase()) == TypeSource.mmrcms) {
|
else if (getWpMangTypeSource(source.toLowerCase()) == TypeSource.mmrcms) {
|
||||||
final dom =
|
mangadetail = await Mmrcms().getMangaDetail(
|
||||||
await httpGet(url: url, source: source, resDom: true) as Document?;
|
imageUrl: imageUrl, url: url, title: title, lang: lang, source: source);
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********/
|
/***********/
|
||||||
/*mangahere*/
|
/*mangahere*/
|
||||||
/***********/
|
/***********/
|
||||||
else if (source.toLowerCase() == "mangahere") {
|
else if (source.toLowerCase() == "mangahere") {
|
||||||
final dom = await httpGet(
|
mangadetail = await Mangahere().getMangaDetail(
|
||||||
url: "http://www.mangahere.cc$url",
|
imageUrl: imageUrl, url: url, title: title, lang: lang, source: source);
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetMangaDetailModel(
|
/***********/
|
||||||
status: status,
|
/*japscan*/
|
||||||
genre: genre,
|
/***********/
|
||||||
author: author,
|
|
||||||
description: description,
|
else if (source.toLowerCase() == "japscan") {
|
||||||
name: title,
|
mangadetail = await Japscan().getMangaDetail(
|
||||||
url: url,
|
imageUrl: imageUrl, url: url, title: title, lang: lang, source: source);
|
||||||
source: source,
|
}
|
||||||
imageUrl: imageUrl,
|
return mangadetail!;
|
||||||
chapters: chapters,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ part of 'get_manga_detail.dart';
|
||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$getMangaDetailHash() => r'42e2ad9fac5c3a0db0a6aefe8f77f2c97eaaf235';
|
String _$getMangaDetailHash() => r'989fdfaf80bf546d1f9910b0715afc9a0e64f33a';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
|
|
|
||||||
|
|
@ -1,171 +1,43 @@
|
||||||
// ignore_for_file: unused_local_variable
|
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:convert';
|
import 'package:mangayomi/models/source_model.dart';
|
||||||
import 'package:html/dom.dart';
|
import 'package:mangayomi/sources/service/service.dart';
|
||||||
import 'package:mangayomi/models/comick/popular_manga_comick.dart';
|
import 'package:mangayomi/sources/src/all/comick/src/comick.dart';
|
||||||
import 'package:mangayomi/services/http_service/http_service.dart';
|
import 'package:mangayomi/sources/src/en/mangahere/src/mangahere.dart';
|
||||||
import 'package:mangayomi/source/source_list.dart';
|
import 'package:mangayomi/sources/src/fr/japscan/src/japscan.dart';
|
||||||
import 'package:mangayomi/source/source_model.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';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
part 'get_popular_manga.g.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
|
@riverpod
|
||||||
Future<GetMangaModel> getPopularManga(GetPopularMangaRef ref,
|
Future<GetMangaModel> getPopularManga(GetPopularMangaRef ref,
|
||||||
{required String source, required int page}) async {
|
{required String source, required int page}) async {
|
||||||
List<String?> url = [];
|
GetMangaModel? popularManga;
|
||||||
List<String?> name = [];
|
|
||||||
List<String?> image = [];
|
|
||||||
source = source.toLowerCase();
|
source = source.toLowerCase();
|
||||||
|
|
||||||
/*********/
|
/*********/
|
||||||
/*comick*/
|
/*comick*/
|
||||||
/*******/
|
/*******/
|
||||||
if (getWpMangTypeSource(source) == TypeSource.comick) {
|
if (getWpMangTypeSource(source) == TypeSource.comick) {
|
||||||
final response = await httpGet(
|
popularManga = await Comick().getPopularManga(source: source, page: page);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************/
|
/***************/
|
||||||
/*mangathemesia*/
|
/*mangathemesia*/
|
||||||
/**************/
|
/**************/
|
||||||
if (getWpMangTypeSource(source) == TypeSource.mangathemesia) {
|
if (getWpMangTypeSource(source) == TypeSource.mangathemesia) {
|
||||||
final dom = await httpGet(
|
popularManga =
|
||||||
useUserAgent: true,
|
await MangaThemeSia().getPopularManga(source: source, page: page);
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********/
|
/***********/
|
||||||
/*mangakawaii*/
|
/*mangakawaii*/
|
||||||
/***********/
|
/***********/
|
||||||
if (source == "mangakawaii") {
|
if (source == "mangakawaii") {
|
||||||
final dom = await httpGet(
|
popularManga =
|
||||||
url: 'https://www.mangakawaii.io/',
|
await MangaKawaii().getPopularManga(source: source, page: page);
|
||||||
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("");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********/
|
/***********/
|
||||||
|
|
@ -173,93 +45,21 @@ Future<GetMangaModel> getPopularManga(GetPopularMangaRef ref,
|
||||||
/***********/
|
/***********/
|
||||||
|
|
||||||
else if (getWpMangTypeSource(source) == TypeSource.mmrcms) {
|
else if (getWpMangTypeSource(source) == TypeSource.mmrcms) {
|
||||||
final dom = await httpGet(
|
popularManga = await Mmrcms().getPopularManga(source: source, page: page);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********/
|
/***********/
|
||||||
/*mangahere*/
|
/*mangahere*/
|
||||||
/***********/
|
/***********/
|
||||||
else if (source == "mangahere") {
|
else if (source == "mangahere") {
|
||||||
final dom = await httpGet(
|
popularManga =
|
||||||
url: 'https://www.mangahere.cc/ranking/',
|
await Mangahere().getPopularManga(source: source, page: page);
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/***********/
|
/***********/
|
||||||
/*japscan*/
|
/*japscan*/
|
||||||
/***********/
|
/***********/
|
||||||
else if (source == "japscan") {
|
else if (source == "japscan") {
|
||||||
final dom = await httpGet(
|
popularManga = await Japscan().getPopularManga(source: source, page: page);
|
||||||
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 GetMangaModel(
|
return popularManga!;
|
||||||
name: name,
|
|
||||||
url: url,
|
|
||||||
image: image,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ part of 'get_popular_manga.dart';
|
||||||
// RiverpodGenerator
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$getPopularMangaHash() => r'cf3f1c29feafa93591a44549b5d81f25ff65bf4f';
|
String _$getPopularMangaHash() => r'cec4ced8864aca6f08b29a8ef9405fd21b68927f';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,10 @@ import 'package:http/http.dart' as http;
|
||||||
|
|
||||||
Future<Document> httpResToDom(
|
Future<Document> httpResToDom(
|
||||||
{required String url, required Map<String, String>? headers}) async {
|
{required String url, required Map<String, String>? headers}) async {
|
||||||
final response = await http.get(Uri.parse(url), headers: headers);
|
try {
|
||||||
return Document.html(response.body);
|
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:html/dom.dart';
|
||||||
import 'package:mangayomi/services/http_service/cloudflare/cloudflare_bypass.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:mangayomi/services/http_service/http_res_to_dom_html.dart';
|
||||||
import 'package:http/http.dart' as http;
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:mangayomi/sources/utils/utils.dart';
|
||||||
import 'package:mangayomi/utils/headers.dart';
|
import 'package:mangayomi/utils/headers.dart';
|
||||||
|
|
||||||
Future<dynamic> httpGet(
|
Future<dynamic> httpGet(
|
||||||
|
|
@ -29,8 +29,13 @@ Future<dynamic> httpGet(
|
||||||
useUserAgent: useUserAgent,
|
useUserAgent: useUserAgent,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
final response = await http.get(Uri.parse(url), headers: headers(source));
|
try {
|
||||||
resHtml = response.body;
|
final response =
|
||||||
|
await http.get(Uri.parse(url), headers: headers(source));
|
||||||
|
resHtml = response.body;
|
||||||
|
} catch (e) {
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return resHtml;
|
return resHtml;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,177 +1,68 @@
|
||||||
import 'dart:convert';
|
import 'package:mangayomi/models/source_model.dart';
|
||||||
import 'package:html/dom.dart';
|
import 'package:mangayomi/sources/service/service.dart';
|
||||||
import 'package:mangayomi/models/comick/search_manga_cimick.dart';
|
import 'package:mangayomi/sources/src/all/comick/src/comick.dart';
|
||||||
import 'package:mangayomi/services/get_popular_manga.dart';
|
import 'package:mangayomi/sources/src/en/mangahere/src/mangahere.dart';
|
||||||
import 'package:mangayomi/services/http_service/http_service.dart';
|
import 'package:mangayomi/sources/src/fr/japscan/src/japscan.dart';
|
||||||
import 'package:mangayomi/source/source_model.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';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
part 'search_manga.g.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
|
@riverpod
|
||||||
Future<SearchMangaModel> searchManga(SearchMangaRef ref,
|
Future<GetMangaModel> searchManga(SearchMangaRef ref,
|
||||||
{required String source, required String query}) async {
|
{required String source, required String query}) async {
|
||||||
List<String?> url = [];
|
GetMangaModel? manga;
|
||||||
List<String?> name = [];
|
|
||||||
List<String?> image = [];
|
|
||||||
source = source.toLowerCase();
|
source = source.toLowerCase();
|
||||||
|
|
||||||
/********/
|
/********/
|
||||||
/*comick*/
|
/*comick*/
|
||||||
/********/
|
/********/
|
||||||
|
|
||||||
if (getWpMangTypeSource(source) == TypeSource.comick) {
|
if (getWpMangTypeSource(source) == TypeSource.comick) {
|
||||||
final response = await httpGet(
|
manga = await Comick().searchManga(source: source, query: query);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***************/
|
/***************/
|
||||||
/*mangathemesia*/
|
/*mangathemesia*/
|
||||||
/***************/
|
/***************/
|
||||||
|
|
||||||
else if (getWpMangTypeSource(source) == TypeSource.mangathemesia) {
|
else if (getWpMangTypeSource(source) == TypeSource.mangathemesia) {
|
||||||
final dom = await httpGet(
|
manga = await MangaThemeSia().searchManga(source: source, query: query);
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********/
|
/***********/
|
||||||
/*mangakawaii*/
|
/*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
|
else if (source == "mangakawaii") {
|
||||||
.querySelectorAll(
|
manga = await MangaKawaii().searchManga(source: source, query: query);
|
||||||
'#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('');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********/
|
/***********/
|
||||||
/*mmrcms*/
|
/*mmrcms*/
|
||||||
/***********/
|
/***********/
|
||||||
|
|
||||||
else if (getWpMangTypeSource(source) == TypeSource.mmrcms) {
|
else if (getWpMangTypeSource(source) == TypeSource.mmrcms) {
|
||||||
final response = await httpGet(
|
manga = await Mmrcms().searchManga(source: source, query: query);
|
||||||
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('');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***********/
|
/***********/
|
||||||
/*mangahere*/
|
/*mangahere*/
|
||||||
/***********/
|
/***********/
|
||||||
|
|
||||||
else if (source == "mangahere") {
|
else if (source == "mangahere") {
|
||||||
final dom = await httpGet(
|
manga = await Mangahere().searchManga(source: source, query: query);
|
||||||
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 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
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$searchMangaHash() => r'8efe07dbe0f844d9d17ecf6962ac7f03ebcc9d57';
|
String _$searchMangaHash() => r'1694578ec0cc207b533f4709427d3f68b691b1b7';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
|
|
@ -29,14 +29,14 @@ class _SystemHash {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef SearchMangaRef = AutoDisposeFutureProviderRef<SearchMangaModel>;
|
typedef SearchMangaRef = AutoDisposeFutureProviderRef<GetMangaModel>;
|
||||||
|
|
||||||
/// See also [searchManga].
|
/// See also [searchManga].
|
||||||
@ProviderFor(searchManga)
|
@ProviderFor(searchManga)
|
||||||
const searchMangaProvider = SearchMangaFamily();
|
const searchMangaProvider = SearchMangaFamily();
|
||||||
|
|
||||||
/// See also [searchManga].
|
/// See also [searchManga].
|
||||||
class SearchMangaFamily extends Family<AsyncValue<SearchMangaModel>> {
|
class SearchMangaFamily extends Family<AsyncValue<GetMangaModel>> {
|
||||||
/// See also [searchManga].
|
/// See also [searchManga].
|
||||||
const SearchMangaFamily();
|
const SearchMangaFamily();
|
||||||
|
|
||||||
|
|
@ -77,7 +77,7 @@ class SearchMangaFamily extends Family<AsyncValue<SearchMangaModel>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// See also [searchManga].
|
/// See also [searchManga].
|
||||||
class SearchMangaProvider extends AutoDisposeFutureProvider<SearchMangaModel> {
|
class SearchMangaProvider extends AutoDisposeFutureProvider<GetMangaModel> {
|
||||||
/// See also [searchManga].
|
/// See also [searchManga].
|
||||||
SearchMangaProvider({
|
SearchMangaProvider({
|
||||||
required this.source,
|
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';
|
import 'package:mangayomi/models/source_model.dart';
|
||||||
List<SourceModel> sourcesList = [
|
|
||||||
SourceModel(
|
List<SourceModel> mangathemesiaSourcesList = [
|
||||||
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"),
|
|
||||||
SourceModel(
|
SourceModel(
|
||||||
sourceName: "KomikLab",
|
sourceName: "KomikLab",
|
||||||
url: "https://komiklab.com",
|
url: "https://komiklab.com",
|
||||||
lang: "en",
|
lang: "en",
|
||||||
typeSource: TypeSource.mangathemesia,
|
typeSource: TypeSource.mangathemesia,
|
||||||
logoUrl: '',
|
logoUrl: '',
|
||||||
dateFormat: "MMMM dd, yyyy",
|
dateFormat: "MMMM dd, yyyy",
|
||||||
dateFormatLocale: "en"),
|
dateFormatLocale: "en"),
|
||||||
SourceModel(
|
SourceModel(
|
||||||
sourceName: "AnimatedGlitchedScans",
|
sourceName: "AnimatedGlitchedScans",
|
||||||
|
|
@ -193,7 +15,7 @@ List<SourceModel> sourcesList = [
|
||||||
lang: "en",
|
lang: "en",
|
||||||
typeSource: TypeSource.mangathemesia,
|
typeSource: TypeSource.mangathemesia,
|
||||||
logoUrl: '',
|
logoUrl: '',
|
||||||
dateFormat: "MMMM dd, yyyy",
|
dateFormat: "MMMM dd, yyyy",
|
||||||
dateFormatLocale: "en"),
|
dateFormatLocale: "en"),
|
||||||
// SourceModel(
|
// SourceModel(
|
||||||
// sourceName: "ArenaScans",
|
// sourceName: "ArenaScans",
|
||||||
|
|
@ -234,7 +56,7 @@ List<SourceModel> sourcesList = [
|
||||||
lang: "en",
|
lang: "en",
|
||||||
typeSource: TypeSource.mangathemesia,
|
typeSource: TypeSource.mangathemesia,
|
||||||
logoUrl: '',
|
logoUrl: '',
|
||||||
dateFormat: "MMMM dd, yyyy",
|
dateFormat: "MMMM dd, yyyy",
|
||||||
dateFormatLocale: "en"),
|
dateFormatLocale: "en"),
|
||||||
SourceModel(
|
SourceModel(
|
||||||
sourceName: "DiskusScan",
|
sourceName: "DiskusScan",
|
||||||
|
|
@ -272,7 +94,7 @@ List<SourceModel> sourcesList = [
|
||||||
typeSource: TypeSource.mangathemesia,
|
typeSource: TypeSource.mangathemesia,
|
||||||
logoUrl: '',
|
logoUrl: '',
|
||||||
isCloudflare: true,
|
isCloudflare: true,
|
||||||
dateFormat: "MMMM dd, yyyy",
|
dateFormat: "MMMM dd, yyyy",
|
||||||
dateFormatLocale: "en"),
|
dateFormatLocale: "en"),
|
||||||
|
|
||||||
// SourceModel(
|
// SourceModel(
|
||||||
|
|
@ -487,70 +309,4 @@ List<SourceModel> sourcesList = [
|
||||||
'https://xcalibrscans.com/wp-content/uploads/2021/06/xcalibr-dark-v3.png',
|
'https://xcalibrscans.com/wp-content/uploads/2021/06/xcalibr-dark-v3.png',
|
||||||
dateFormat: "MMMM dd, yyyy",
|
dateFormat: "MMMM dd, yyyy",
|
||||||
dateFormatLocale: "en"),
|
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:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:mangayomi/providers/storage_provider.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/extension/extension_screen.dart';
|
||||||
import 'package:mangayomi/views/browse/migrate_screen.dart';
|
import 'package:mangayomi/views/browse/migrate_screen.dart';
|
||||||
import 'package:mangayomi/views/browse/sources_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:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:hive_flutter/hive_flutter.dart';
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
import 'package:mangayomi/providers/hive_provider.dart';
|
import 'package:mangayomi/providers/hive_provider.dart';
|
||||||
import 'package:mangayomi/source/source_list.dart';
|
import 'package:mangayomi/models/source_model.dart';
|
||||||
import 'package:mangayomi/source/source_model.dart';
|
import 'package:mangayomi/sources/source_list.dart';
|
||||||
import 'package:mangayomi/utils/lang.dart';
|
import 'package:mangayomi/utils/lang.dart';
|
||||||
import 'package:mangayomi/views/browse/extension/widgets/extension_lang_list_tile_widget.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:grouped_list/grouped_list.dart';
|
||||||
import 'package:hive_flutter/hive_flutter.dart';
|
import 'package:hive_flutter/hive_flutter.dart';
|
||||||
import 'package:mangayomi/providers/hive_provider.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/utils/lang.dart';
|
||||||
import 'package:mangayomi/views/browse/extension/refresh_filter_data.dart';
|
import 'package:mangayomi/views/browse/extension/refresh_filter_data.dart';
|
||||||
import 'package:mangayomi/views/browse/extension/widgets/extension_list_tile_widget.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/providers/hive_provider.dart';
|
||||||
import 'package:mangayomi/source/source_list.dart';
|
import 'package:mangayomi/models/source_model.dart';
|
||||||
import 'package:mangayomi/source/source_model.dart';
|
import 'package:mangayomi/sources/source_list.dart';
|
||||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||||
part 'refresh_filter_data.g.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/providers/hive_provider.dart';
|
||||||
import 'package:mangayomi/services/get_manga_detail.dart';
|
import 'package:mangayomi/services/get_manga_detail.dart';
|
||||||
import 'package:mangayomi/services/search_manga.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/cached_network.dart';
|
||||||
import 'package:mangayomi/utils/headers.dart';
|
import 'package:mangayomi/utils/headers.dart';
|
||||||
import 'package:mangayomi/utils/lang.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:hive_flutter/hive_flutter.dart';
|
||||||
import 'package:mangayomi/models/manga_type.dart';
|
import 'package:mangayomi/models/manga_type.dart';
|
||||||
import 'package:mangayomi/providers/hive_provider.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/headers.dart';
|
||||||
import 'package:mangayomi/utils/lang.dart';
|
import 'package:mangayomi/utils/lang.dart';
|
||||||
import 'package:mangayomi/views/browse/extension/refresh_filter_data.dart';
|
import 'package:mangayomi/views/browse/extension/refresh_filter_data.dart';
|
||||||
|
|
|
||||||
|
|
@ -866,7 +866,7 @@ class ChapterSetDownloadStateProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
String _$chaptersListttStateHash() =>
|
String _$chaptersListttStateHash() =>
|
||||||
r'2f81698d88c8087360e33c19884bfbb018604269';
|
r'5f1b0d2be32fcb904c12c5735f1340c8b33400a9';
|
||||||
|
|
||||||
/// See also [ChaptersListttState].
|
/// See also [ChaptersListttState].
|
||||||
@ProviderFor(ChaptersListttState)
|
@ProviderFor(ChaptersListttState)
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,8 @@
|
||||||
import 'dart:developer';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:intl/intl.dart';
|
|
||||||
import 'package:mangayomi/models/chapter.dart';
|
import 'package:mangayomi/models/chapter.dart';
|
||||||
import 'package:mangayomi/utils/date.dart';
|
import 'package:mangayomi/utils/date.dart';
|
||||||
import 'package:mangayomi/views/manga/reader/providers/push_router.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/colors.dart';
|
||||||
import 'package:mangayomi/utils/utils.dart';
|
import 'package:mangayomi/utils/utils.dart';
|
||||||
import 'package:mangayomi/views/manga/detail/providers/state_providers.dart';
|
import 'package:mangayomi/views/manga/detail/providers/state_providers.dart';
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ Future<List<dynamic>> downloadChapter(
|
||||||
DownloadChapterRef ref, {
|
DownloadChapterRef ref, {
|
||||||
required Chapter chapter,
|
required Chapter chapter,
|
||||||
}) async {
|
}) async {
|
||||||
List urll = [];
|
List pageUrls = [];
|
||||||
List<DownloadTask> tasks = [];
|
List<DownloadTask> tasks = [];
|
||||||
final StorageProvider storageProvider = StorageProvider();
|
final StorageProvider storageProvider = StorageProvider();
|
||||||
await storageProvider.requestPermission();
|
await storageProvider.requestPermission();
|
||||||
|
|
@ -39,8 +39,8 @@ Future<List<dynamic>> downloadChapter(
|
||||||
chapter: chapter,
|
chapter: chapter,
|
||||||
).future)
|
).future)
|
||||||
.then((value) {
|
.then((value) {
|
||||||
if (value.urll.isNotEmpty) {
|
if (value.pageUrls.isNotEmpty) {
|
||||||
urll = value.urll;
|
pageUrls = value.pageUrls;
|
||||||
isOk = true;
|
isOk = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -52,8 +52,8 @@ Future<List<dynamic>> downloadChapter(
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (urll.isNotEmpty) {
|
if (pageUrls.isNotEmpty) {
|
||||||
for (var index = 0; index < urll.length; index++) {
|
for (var index = 0; index < pageUrls.length; index++) {
|
||||||
final path2 = Directory("${path1.path}downloads/");
|
final path2 = Directory("${path1.path}downloads/");
|
||||||
final path4 = Directory(
|
final path4 = Directory(
|
||||||
"${path2.path}${manga.source} (${manga.lang!.toUpperCase()})/");
|
"${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()) {
|
if (await File("${path.path}" "${padIndex(index + 1)}.jpg").exists()) {
|
||||||
} else {
|
} else {
|
||||||
tasks.add(DownloadTask(
|
tasks.add(DownloadTask(
|
||||||
taskId: urll[index],
|
taskId: pageUrls[index],
|
||||||
headers: headers(manga.source!),
|
headers: headers(manga.source!),
|
||||||
url: urll[index],
|
url: pageUrls[index],
|
||||||
filename: "${padIndex(index + 1)}.jpg",
|
filename: "${padIndex(index + 1)}.jpg",
|
||||||
baseDirectory:
|
baseDirectory:
|
||||||
Platform.isWindows || Platform.isMacOS || Platform.isLinux
|
Platform.isWindows || Platform.isMacOS || Platform.isLinux
|
||||||
|
|
@ -104,9 +104,9 @@ Future<List<dynamic>> downloadChapter(
|
||||||
if (await File("${path.path}" "${padIndex(index + 1)}.jpg").exists()) {
|
if (await File("${path.path}" "${padIndex(index + 1)}.jpg").exists()) {
|
||||||
} else {
|
} else {
|
||||||
tasks.add(DownloadTask(
|
tasks.add(DownloadTask(
|
||||||
taskId: urll[index],
|
taskId: pageUrls[index],
|
||||||
headers: headers(manga.source!),
|
headers: headers(manga.source!),
|
||||||
url: urll[index],
|
url: pageUrls[index],
|
||||||
filename: "${padIndex(index + 1)}.jpg",
|
filename: "${padIndex(index + 1)}.jpg",
|
||||||
baseDirectory:
|
baseDirectory:
|
||||||
Platform.isWindows || Platform.isMacOS || Platform.isLinux
|
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(
|
final model = DownloadModel(
|
||||||
chapterId: chapter.id,
|
chapterId: chapter.id,
|
||||||
mangaName: manga.name,
|
mangaName: manga.name,
|
||||||
|
|
@ -133,7 +133,7 @@ Future<List<dynamic>> downloadChapter(
|
||||||
total: 0,
|
total: 0,
|
||||||
isDownload: true,
|
isDownload: true,
|
||||||
mangaId: manga.id!,
|
mangaId: manga.id!,
|
||||||
taskIds: urll,
|
taskIds: pageUrls,
|
||||||
isStartDownload: false);
|
isStartDownload: false);
|
||||||
|
|
||||||
ref
|
ref
|
||||||
|
|
@ -150,7 +150,7 @@ Future<List<dynamic>> downloadChapter(
|
||||||
chapterId: chapter.id,
|
chapterId: chapter.id,
|
||||||
total: tasks.length,
|
total: tasks.length,
|
||||||
isDownload: (succeeded == tasks.length) ? true : false,
|
isDownload: (succeeded == tasks.length) ? true : false,
|
||||||
taskIds: urll,
|
taskIds: pageUrls,
|
||||||
isStartDownload: true,
|
isStartDownload: true,
|
||||||
chapterName: chapter.name!,
|
chapterName: chapter.name!,
|
||||||
mangaSource: manga.source,
|
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
|
// RiverpodGenerator
|
||||||
// **************************************************************************
|
// **************************************************************************
|
||||||
|
|
||||||
String _$downloadChapterHash() => r'240d09a7cf3726a4b75c2a45ef12a50de20d5a0e';
|
String _$downloadChapterHash() => r'd750be212254a2aefbbb7825b98235dafe41ace5';
|
||||||
|
|
||||||
/// Copied from Dart SDK
|
/// Copied from Dart SDK
|
||||||
class _SystemHash {
|
class _SystemHash {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import 'package:go_router/go_router.dart';
|
||||||
import 'package:mangayomi/models/manga_type.dart';
|
import 'package:mangayomi/models/manga_type.dart';
|
||||||
import 'package:mangayomi/services/get_manga_detail.dart';
|
import 'package:mangayomi/services/get_manga_detail.dart';
|
||||||
import 'package:mangayomi/services/get_popular_manga.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/utils/colors.dart';
|
||||||
import 'package:mangayomi/views/manga/home/manga_search_screen.dart';
|
import 'package:mangayomi/views/manga/home/manga_search_screen.dart';
|
||||||
import 'package:mangayomi/views/widgets/bottom_text_widget.dart';
|
import 'package:mangayomi/views/widgets/bottom_text_widget.dart';
|
||||||
|
|
|
||||||
|
|
@ -40,12 +40,12 @@ class MangaReaderView extends ConsumerWidget {
|
||||||
ref.read(readerControllerProvider(chapter: chapter).notifier);
|
ref.read(readerControllerProvider(chapter: chapter).notifier);
|
||||||
return chapterData.when(
|
return chapterData.when(
|
||||||
data: (data) {
|
data: (data) {
|
||||||
if (data.urll.isEmpty) {
|
if (data.pageUrls.isEmpty) {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
}
|
}
|
||||||
return MangaChapterPageGallery(
|
return MangaChapterPageGallery(
|
||||||
path: data.path!,
|
path: data.path!,
|
||||||
url: data.urll,
|
url: data.pageUrls,
|
||||||
readerController: readerController,
|
readerController: readerController,
|
||||||
isLocaleList: data.isLocaleList,
|
isLocaleList: data.isLocaleList,
|
||||||
chapter: chapter,
|
chapter: chapter,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:mangayomi/providers/hive_provider.dart';
|
||||||
import 'package:mangayomi/utils/colors.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:mangayomi/views/more/settings/appearance/providers/theme_mode_state_provider.dart';
|
||||||
// import 'package:rive/rive.dart';
|
// import 'package:rive/rive.dart';
|
||||||
|
|
||||||
|
|
@ -17,13 +19,23 @@ class _DarkModeButtonState extends ConsumerState<DarkModeButton> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
bool isLight = ref.watch(themeModeStateProvider);
|
bool isLight = ref.watch(themeModeStateProvider);
|
||||||
|
|
||||||
return ListTile(
|
return ListTile(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
|
int flexColorIndex = ref
|
||||||
|
.watch(hiveBoxSettingsProvider)
|
||||||
|
.get('FlexColorIndex', defaultValue: 7);
|
||||||
if (!isLight == true) {
|
if (!isLight == true) {
|
||||||
ref.read(themeModeStateProvider.notifier).setLightTheme();
|
ref.read(themeModeStateProvider.notifier).setLightTheme();
|
||||||
} else {
|
} else {
|
||||||
ref.read(themeModeStateProvider.notifier).setDarkTheme();
|
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"),
|
title: const Text("Dark mode"),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import 'package:mangayomi/main.dart';
|
||||||
import 'package:mangayomi/models/chapter.dart';
|
import 'package:mangayomi/models/chapter.dart';
|
||||||
import 'package:mangayomi/models/manga.dart';
|
import 'package:mangayomi/models/manga.dart';
|
||||||
import 'package:mangayomi/services/get_manga_detail.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/cached_network.dart';
|
||||||
import 'package:mangayomi/utils/headers.dart';
|
import 'package:mangayomi/utils/headers.dart';
|
||||||
import 'package:mangayomi/views/widgets/bottom_text_widget.dart';
|
import 'package:mangayomi/views/widgets/bottom_text_widget.dart';
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue