diff --git a/lib/modules/browse/extension/widgets/extension_list_tile_widget.dart b/lib/modules/browse/extension/widgets/extension_list_tile_widget.dart index 8b102e14..41760c49 100644 --- a/lib/modules/browse/extension/widgets/extension_list_tile_widget.dart +++ b/lib/modules/browse/extension/widgets/extension_list_tile_widget.dart @@ -1,4 +1,3 @@ -import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:mangayomi/utils/lang.dart'; diff --git a/lib/modules/browse/sources/sources_screen.dart b/lib/modules/browse/sources/sources_screen.dart index 5d01ea30..e14ba33a 100644 --- a/lib/modules/browse/sources/sources_screen.dart +++ b/lib/modules/browse/sources/sources_screen.dart @@ -1,4 +1,3 @@ -import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; @@ -7,7 +6,6 @@ import 'package:isar/isar.dart'; import 'package:mangayomi/main.dart'; import 'package:mangayomi/models/manga_type.dart'; import 'package:mangayomi/models/source.dart'; -import 'package:mangayomi/utils/headers.dart'; import 'package:mangayomi/utils/lang.dart'; import 'package:mangayomi/modules/more/settings/browse/providers/browse_state_provider.dart'; diff --git a/lib/modules/manga/home/manga_home_screen.dart b/lib/modules/manga/home/manga_home_screen.dart index 977c8b6d..b49719a8 100644 --- a/lib/modules/manga/home/manga_home_screen.dart +++ b/lib/modules/manga/home/manga_home_screen.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import 'package:mangayomi/models/manga_type.dart'; +import 'package:mangayomi/services/get_latest_updates_manga.dart'; import 'package:mangayomi/services/get_manga_detail.dart'; import 'package:mangayomi/services/get_popular_manga.dart'; import 'package:mangayomi/services/search_manga.dart'; @@ -54,7 +55,10 @@ class _MangaHomeScreenState extends ConsumerState { if (_selectedIndex == 2 && _isSearch && _query.isNotEmpty) { _getManga = ref.watch( searchMangaProvider(source: widget.mangaType.source!, query: _query)); - } else { + } else if (_selectedIndex == 1 && !_isSearch && _query.isEmpty) { + _getManga = ref.watch( + getLatestUpdatesMangaProvider(source: widget.mangaType.source!, page: 1)); + } else if (_selectedIndex == 0 && !_isSearch && _query.isEmpty) { _getManga = ref.watch( getPopularMangaProvider(source: widget.mangaType.source!, page: 1)); } diff --git a/lib/services/get_latest_updates_manga.dart b/lib/services/get_latest_updates_manga.dart new file mode 100644 index 00000000..80c4e511 --- /dev/null +++ b/lib/services/get_latest_updates_manga.dart @@ -0,0 +1,85 @@ +import 'dart:async'; +import 'package:mangayomi/models/source.dart'; +import 'package:mangayomi/sources/multisrc/heancms/heancms.dart'; +import 'package:mangayomi/sources/multisrc/madara/src/madara.dart'; +import 'package:mangayomi/sources/service.dart'; +import 'package:mangayomi/sources/src/all/comick/src/comick.dart'; +import 'package:mangayomi/sources/src/en/mangahere/src/mangahere.dart'; +import 'package:mangayomi/sources/src/fr/japscan/src/japscan.dart'; +import 'package:mangayomi/sources/src/fr/mangakawaii/src/mangakawaii.dart'; +import 'package:mangayomi/sources/multisrc/mangathemesia/src/mangathemesia.dart'; +import 'package:mangayomi/sources/multisrc/mmrcms/src/mmrcms.dart'; +import 'package:mangayomi/sources/utils/utils.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; +part 'get_latest_updates_manga.g.dart'; + +@riverpod +Future> getLatestUpdatesManga(GetLatestUpdatesMangaRef ref, + {required String source, required int page}) async { + List? latestUpdatesManga; + source = source.toLowerCase(); + + /*********/ + /*comick*/ + /*******/ + if (getMangaTypeSource(source) == TypeSource.comick) { + latestUpdatesManga = + await Comick().getLatestUpdatesManga(source: source, page: page, ref: ref); + } + + /***************/ + /*mangathemesia*/ + /**************/ + if (getMangaTypeSource(source) == TypeSource.mangathemesia) { + latestUpdatesManga = await MangaThemeSia() + .getLatestUpdatesManga(source: source, page: page, ref: ref); + } + + /***********/ + /*mangakawaii*/ + /***********/ + if (source == "mangakawaii") { + latestUpdatesManga = await MangaKawaii() + .getLatestUpdatesManga(source: source, page: page, ref: ref); + } + + /***********/ + /*mmrcms*/ + /***********/ + + else if (getMangaTypeSource(source) == TypeSource.mmrcms) { + latestUpdatesManga = + await Mmrcms().getLatestUpdatesManga(source: source, page: page, ref: ref); + } + + /***********/ + /*mangahere*/ + /***********/ + else if (source == "mangahere") { + latestUpdatesManga = + await Mangahere().getLatestUpdatesManga(source: source, page: page, ref: ref); + } + /***********/ + /*japscan*/ + /***********/ + else if (source == "japscan") { + latestUpdatesManga = + await Japscan().getLatestUpdatesManga(source: source, page: page, ref: ref); + } + + /***********/ + /*heancms*/ + /***********/ + else if (getMangaTypeSource(source) == TypeSource.heancms) { + latestUpdatesManga = + await HeanCms().getLatestUpdatesManga(source: source, page: page, ref: ref); + } + /***********/ + /*madara*/ + /***********/ + else if (getMangaTypeSource(source) == TypeSource.madara) { + latestUpdatesManga = + await Madara().getLatestUpdatesManga(source: source, page: page, ref: ref); + } + return latestUpdatesManga!; +} diff --git a/lib/services/get_latest_updates_manga.g.dart b/lib/services/get_latest_updates_manga.g.dart new file mode 100644 index 00000000..ec79a712 --- /dev/null +++ b/lib/services/get_latest_updates_manga.g.dart @@ -0,0 +1,124 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'get_latest_updates_manga.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$getLatestUpdatesMangaHash() => + r'2f6c7714feca588ada6c6dd98ad62849042e9bae'; + +/// Copied from Dart SDK +class _SystemHash { + _SystemHash._(); + + static int combine(int hash, int value) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + value); + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); + return hash ^ (hash >> 6); + } + + static int finish(int hash) { + // ignore: parameter_assignments + hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); + // ignore: parameter_assignments + hash = hash ^ (hash >> 11); + return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); + } +} + +typedef GetLatestUpdatesMangaRef + = AutoDisposeFutureProviderRef>; + +/// See also [getLatestUpdatesManga]. +@ProviderFor(getLatestUpdatesManga) +const getLatestUpdatesMangaProvider = GetLatestUpdatesMangaFamily(); + +/// See also [getLatestUpdatesManga]. +class GetLatestUpdatesMangaFamily extends Family>> { + /// See also [getLatestUpdatesManga]. + const GetLatestUpdatesMangaFamily(); + + /// See also [getLatestUpdatesManga]. + GetLatestUpdatesMangaProvider call({ + required String source, + required int page, + }) { + return GetLatestUpdatesMangaProvider( + source: source, + page: page, + ); + } + + @override + GetLatestUpdatesMangaProvider getProviderOverride( + covariant GetLatestUpdatesMangaProvider provider, + ) { + return call( + source: provider.source, + page: provider.page, + ); + } + + static const Iterable? _dependencies = null; + + @override + Iterable? get dependencies => _dependencies; + + static const Iterable? _allTransitiveDependencies = null; + + @override + Iterable? get allTransitiveDependencies => + _allTransitiveDependencies; + + @override + String? get name => r'getLatestUpdatesMangaProvider'; +} + +/// See also [getLatestUpdatesManga]. +class GetLatestUpdatesMangaProvider + extends AutoDisposeFutureProvider> { + /// See also [getLatestUpdatesManga]. + GetLatestUpdatesMangaProvider({ + required this.source, + required this.page, + }) : super.internal( + (ref) => getLatestUpdatesManga( + ref, + source: source, + page: page, + ), + from: getLatestUpdatesMangaProvider, + name: r'getLatestUpdatesMangaProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$getLatestUpdatesMangaHash, + dependencies: GetLatestUpdatesMangaFamily._dependencies, + allTransitiveDependencies: + GetLatestUpdatesMangaFamily._allTransitiveDependencies, + ); + + final String source; + final int page; + + @override + bool operator ==(Object other) { + return other is GetLatestUpdatesMangaProvider && + other.source == source && + other.page == page; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, source.hashCode); + hash = _SystemHash.combine(hash, page.hashCode); + + return _SystemHash.finish(hash); + } +} +// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions diff --git a/lib/sources/multisrc/heancms/heancms.dart b/lib/sources/multisrc/heancms/heancms.dart index e8f238e3..a63bce78 100644 --- a/lib/sources/multisrc/heancms/heancms.dart +++ b/lib/sources/multisrc/heancms/heancms.dart @@ -182,4 +182,52 @@ class HeanCms extends MangaYomiServices { } return mangaRes(); } + + @override + Future> getLatestUpdatesManga( + {required String source, + required int page, + required AutoDisposeFutureProviderRef ref}) async { + var request = http.Request( + 'POST', Uri.parse('${getMangaAPIUrl(source)}series/querysearch')); + request.body = json.encode({ + "page": page, + "order": "desc", + "order_by": "latest", + "series_status": "Ongoing", + "series_type": "Comic" + }); + request.headers.addAll(_headers(source)); + + http.StreamedResponse response = await request.send(); + final res = await response.stream.bytesToString(); + List? data; + if (res.startsWith("{")) { + var popularManga = jsonDecode(res) as Map; + var popularMangaList = HeanCmsSearchModel.fromJson(popularManga); + data = popularMangaList.data!; + } else { + var popularManga = jsonDecode(res) as List; + data = popularManga.map((e) => Data.fromJson(e)).toList(); + } + + for (var a in data) { + final status = (switch (a.status) { + "Ongoing" => Status.ongoing, + "Hiatus" => Status.onHiatus, + "Dropped" => Status.canceled, + "Completed" => Status.completed, + "Finished" => Status.completed, + _ => Status.unknown, + }); + statusList.add(status); + image.add(a.thumbnail!.startsWith("https://") + ? a.thumbnail + : "${getMangaAPIUrl(source)}cover/${a.thumbnail}"); + name.add(a.title); + url.add("/series/${a.seriesSlug!.replaceAll(timeStampRegex, '')}"); + } + + return mangaRes(); + } } diff --git a/lib/sources/multisrc/madara/src/madara.dart b/lib/sources/multisrc/madara/src/madara.dart index 44bae466..04c257b2 100644 --- a/lib/sources/multisrc/madara/src/madara.dart +++ b/lib/sources/multisrc/madara/src/madara.dart @@ -179,7 +179,6 @@ class Madara extends MangaYomiServices { .attrs) { chapterUrl.add(url!); } - log(chapterUrl.toString()); for (var title in xpath .query("//*[@id='manga-chapters-holder']/div[2]/div/ul/li/a/text()") .attrs) { @@ -239,12 +238,8 @@ class Madara extends MangaYomiServices { } final xpath = xpathSelector(html!); name = xpath.query('//*[@id^="manga-item"]/a/@title').attrs; - // log(name.toString()); url = xpath.query('//*[@class^="post-title"]/h3/a/@href').attrs; - // log(url.toString()); - image = xpath.query('//*[@id^="manga-item"]/a/img/@data-src=').attrs; - // log(image.toString()); return mangaRes(); } @@ -259,14 +254,29 @@ class Madara extends MangaYomiServices { source: source, resDom: false) .future) as String?; - log(html!); - final xpath = xpathSelector(html); + final xpath = xpathSelector(html!); name = xpath.query('//*[@class^="post-title"]/h3/a/text()').attrs; - log(name.toString()); url = xpath.query('//*[@class^="post-title"]/h3/a/@href').attrs; - log(url.toString()); image = name; + return mangaRes(); + } + @override + Future> getLatestUpdatesManga( + {required String source, + required int page, + required AutoDisposeFutureProviderRef ref}) async { + String? html; + html = await ref.watch(httpGetProvider( + url: + '${getMangaBaseUrl(source)}/manga/page/$page/?m_orderby=latest', + source: source, + resDom: false) + .future) as String?; + final xpath = xpathSelector(html!); + name = xpath.query('//*[@id^="manga-item"]/a/@title').attrs; + url = xpath.query('//*[@class^="post-title"]/h3/a/@href').attrs; + image = xpath.query('//*[@id^="manga-item"]/a/img/@data-src=').attrs; return mangaRes(); } } diff --git a/lib/sources/multisrc/madara/src/t.dart b/lib/sources/multisrc/madara/src/t.dart deleted file mode 100644 index 0e063f5d..00000000 --- a/lib/sources/multisrc/madara/src/t.dart +++ /dev/null @@ -1,295 +0,0 @@ -// import 'dart:developer'; -// import 'dart:io'; -// import 'package:desktop_webview_window/desktop_webview_window.dart'; -// import 'package:flutter/material.dart'; -// import 'package:flutter_inappwebview/flutter_inappwebview.dart'; -// import 'package:flutter_riverpod/flutter_riverpod.dart'; -// import 'package:html/dom.dart'; -// import 'package:html/parser.dart'; -// import 'package:mangayomi/models/chapter.dart'; -// import 'package:mangayomi/modules/webview/webview.dart'; -// import 'package:mangayomi/services/http_service/http_service.dart'; -// import 'package:mangayomi/sources/service.dart'; -// import 'package:mangayomi/sources/utils/utils.dart'; -// import 'package:mangayomi/utils/constant.dart'; -// import 'package:mangayomi/utils/reg_exp_matcher.dart'; -// // import 'package:mangayomi/utils/xpath_selector.dart'; - -// class Madara extends MangaYomiServices { -// @override -// Future> getChapterUrl( -// {required Chapter chapter, -// required AutoDisposeFutureProviderRef ref}) async { -// final dom = await await ref.watch(httpGetProvider( -// useUserAgent: true, -// url: chapter.url!, -// source: chapter.manga.value!.source!.toLowerCase(), -// resDom: true) -// .future) as Document?; -// final res = dom!.querySelector( -// "div.page-break, li.blocks-gallery-item, .reading-content, .text-left img"); -// final imgs = res! -// .querySelectorAll('img') -// .map((i) => regSrcMatcher(i.outerHtml).trim().trimLeft().trimRight()) -// .toList(); -// if (imgs.isNotEmpty && imgs.length == 1) { -// final pagesNumber = dom -// .querySelector("#single-pager")! -// .querySelectorAll("option") -// .map((e) => e.outerHtml) -// .toList(); -// for (var i = 0; i < pagesNumber.length; i++) { -// if (i.toString().length == 1) { -// pageUrls.add( -// imgs.first.replaceAll("01", '0${int.parse(i.toString()) + 1}')); -// } else if (i.toString().length == 2) { -// pageUrls.add( -// imgs.first.replaceAll("01", '${int.parse(i.toString()) + 1}')); -// } else if (i.toString().length == 3) { -// pageUrls.add( -// imgs.first.replaceAll("01", '${int.parse(i.toString()) + 1}')); -// } -// } -// } else { -// pageUrls = imgs; -// } -// log(pageUrls.toString()); - -// return pageUrls; -// } - -// @override -// Future getMangaDetail( -// {required GetManga manga, -// required String lang, -// required String source, -// required AutoDisposeFutureProviderRef ref}) async { -// final dom = await ref.watch( -// httpGetProvider(url: manga.url!, source: source, resDom: true) -// .future) as Document?; -// author = dom! -// .querySelectorAll("div.author-content > a") -// .map((e) => e.text) -// .toList() -// .join(', '); -// description = dom -// .querySelectorAll( -// "div.description-summary div.summary__content, div.summary_content div.post-content_item > h5 + div, div.summary_content div.manga-excerpt, div.sinopsis div.contenedor") -// .map((e) => e.text) -// .toList() -// .first; -// status = dom -// .querySelectorAll("div.summary-content") -// .map((e) => e.text.trim().trimLeft().trimRight()) -// .toList() -// .last; - -// manga.imageUrl = dom -// .querySelectorAll("div.summary_image img") -// .map((e) => regSrcMatcher(e.outerHtml)) -// .toList() -// .first; -// genre = dom -// .querySelectorAll("div.genres-content a") -// .map((e) => e.text) -// .toList(); -// bool isOk = false; -// String? html; -// if (Platform.isWindows || Platform.isLinux) { -// final webview = await WebviewWindow.create( -// configuration: CreateConfiguration( -// windowHeight: 500, -// windowWidth: 500, -// userDataFolderWindows: await getWebViewPath(), -// ), -// ); -// webview -// ..setBrightness(Brightness.dark) -// ..setApplicationNameForUserAgent(defaultUserAgent) -// ..launch(manga.url!); - -// await Future.doWhile(() async { -// await Future.delayed(const Duration(seconds: 10)); -// html = await decodeHtml(webview); -// if (parse(html!) -// .querySelector("div[id^=manga-chapters-holder]")! -// .querySelectorAll("li.wp-manga-chapter") -// .isEmpty) { -// html = await decodeHtml(webview); -// return true; -// } -// return false; -// }); -// html = await decodeHtml(webview); -// isOk = true; -// await Future.doWhile(() async { -// await Future.delayed(const Duration(seconds: 1)); -// if (isOk == true) { -// return false; -// } -// return true; -// }); -// html = await decodeHtml(webview); -// webview.close(); -// } else { -// HeadlessInAppWebView? headlessWebViewJapScan; -// headlessWebViewJapScan = HeadlessInAppWebView( -// onLoadStop: (controller, u) async { -// html = await controller.evaluateJavascript( -// source: -// "window.document.getElementsByTagName('html')[0].outerHTML;"); -// await Future.doWhile(() async { -// html = await controller.evaluateJavascript( -// source: -// "window.document.getElementsByTagName('html')[0].outerHTML;"); -// if (parse(html!) -// .querySelector("div[id^=manga-chapters-holder]")! -// .querySelectorAll("li.wp-manga-chapter") -// .isEmpty) { -// html = await controller.evaluateJavascript( -// source: -// "window.document.getElementsByTagName('html')[0].outerHTML;"); -// return true; -// } -// return false; -// }); -// html = await controller.evaluateJavascript( -// source: -// "window.document.getElementsByTagName('html')[0].outerHTML;"); -// isOk = true; -// headlessWebViewJapScan!.dispose(); -// }, -// initialUrlRequest: URLRequest( -// url: WebUri.uri(Uri.parse(manga.url!)), -// ), -// ); -// headlessWebViewJapScan.run(); -// await Future.doWhile(() async { -// await Future.delayed(const Duration(seconds: 1)); -// if (isOk == true) { -// return false; -// } -// return true; -// }); -// } -// // final xpath = xpathSelector(html!); -// // // log(parse(html!) -// // // .querySelector("div[id^=manga-chapters-holder]")! -// // // .querySelectorAll("li.wp-manga-chapter") -// // // .map((e) => e.text) -// // // .toList() -// // // .toString()); -// // for (var url in xpath -// // .query("//*[@id='manga-chapters-holder']/div[2]/div/ul/li/a/@href") -// // .attrs) { -// // chapterUrl.add(url!); -// // } -// chapterUrl = parse(html!) -// .querySelector("div[id^=manga-chapters-holder]")! -// .querySelectorAll("li.wp-manga-chapter") -// .map((e) => regHrefMatcher(e.outerHtml)) -// .toList(); -// // for (var title in xpath -// // .query("//*[@id='manga-chapters-holder']/div[2]/div/ul/li/a/text()") -// // .attrs) { -// // chapterTitle.add(title!.trim().trimLeft().trimRight()); -// // } -// // log(chapterUrl.toString()); -// chapterTitle = parse(html!) -// .querySelector("div[id^=manga-chapters-holder]")! -// .querySelectorAll("li.wp-manga-chapter a") -// .map((e) => e.text.trim().trimLeft().trimRight()) -// .toList(); -// // log(chapterTitle.toString()); -// final dateF = parse(html!) -// .querySelector("div[id^=manga-chapters-holder]")! -// .querySelectorAll("li.wp-manga-chapter span") -// .map((e) => e.text.trim().trimLeft().trimRight()) -// .toList(); -// log(dateF.toString()); -// // xpath -// // .query( -// // "//*[@id='manga-chapters-holder']/div[2]/div/ul/li/span/i/text()") -// // .attrs; - -// if (dateF.length == chapterUrl.length) { -// for (var date in dateF) { -// chapterDate.add(parseDate(date, source)); -// } -// } else if (dateF.length < chapterUrl.length) { -// final length = chapterUrl.length - dateF.length; -// for (var i = 0; i < length; i++) { -// chapterDate.add(DateTime.now().millisecondsSinceEpoch.toString()); -// } -// for (var date in dateF) { -// chapterDate.add(parseDate(date!, source)); -// } -// } - -// return mangadetailRes(manga: manga, source: source); -// } - -// @override -// Future> getPopularManga( -// {required String source, -// required int page, -// required AutoDisposeFutureProviderRef ref}) async { -// String? html; -// html = await ref.watch(httpGetProvider( -// url: '${getMangaBaseUrl(source)}/manga/page/$page/?m_orderby=views', -// source: source, -// resDom: false) -// .future) as String?; -// if (parse(html!) -// .querySelectorAll('div.post-title a') -// .map((e) => e.text) -// .toList() -// .isEmpty) { -// html = await ref.watch(httpGetProvider( -// url: -// '${getMangaBaseUrl(source)}/manga/page/$page/?m_orderby=trending', -// source: source, -// resDom: false) -// .future) as String?; -// if (parse(html!) -// .querySelectorAll('div.post-title a') -// .map((e) => e.text) -// .toList() -// .isEmpty) { -// html = await ref.watch(httpGetProvider( -// url: getMangaBaseUrl(source), source: source, resDom: false) -// .future) as String?; -// } -// } -// final dom = parse(html!); -// name = dom.querySelectorAll('div.post-title a').map((e) => e.text).toList(); -// image = name; -// url = dom -// .querySelectorAll('div.post-title a') -// .map((e) => regHrefMatcher(e.outerHtml)) -// .toList(); - -// return mangaRes(); -// } - -// @override -// Future> searchManga( -// {required String source, -// required String query, -// required AutoDisposeFutureProviderRef ref}) async { -// final html = await ref.watch(httpGetProvider( -// url: '${getMangaBaseUrl(source)}/?s=$query&post_type=wp-manga', -// source: source, -// resDom: false) -// .future) as String?; -// final dom = parse(html!); -// name = dom.querySelectorAll('div.post-title a').map((e) => e.text).toList(); -// image = name; -// url = dom -// .querySelectorAll('div.post-title a') -// .map((e) => regHrefMatcher(e.outerHtml)) -// .toList(); - -// return mangaRes(); -// } -// } diff --git a/lib/sources/multisrc/mangathemesia/src/mangathemesia.dart b/lib/sources/multisrc/mangathemesia/src/mangathemesia.dart index 0f666dc5..3f608be2 100644 --- a/lib/sources/multisrc/mangathemesia/src/mangathemesia.dart +++ b/lib/sources/multisrc/mangathemesia/src/mangathemesia.dart @@ -277,6 +277,56 @@ class MangaThemeSia extends MangaYomiServices { } return pageUrls; } + + @override + Future> getLatestUpdatesManga( + {required String source, + required int page, + required AutoDisposeFutureProviderRef ref}) async { + source = source.toLowerCase(); + final dom = await ref.watch(httpGetProvider( + useUserAgent: true, + url: + '${getMangaBaseUrl(source)}/manga/?title=&page=$page&order=update', + source: source, + resDom: true) + .future) 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 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 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 matches = exp.allMatches(e.innerHtml); + String? firstMatch = matches.first.group(1); + return firstMatch; + }).toList(); + } + return mangaRes(); + } } mangathemesiaStatusParser(String status) { diff --git a/lib/sources/multisrc/mmrcms/src/mmrcms.dart b/lib/sources/multisrc/mmrcms/src/mmrcms.dart index 1e611214..43775eab 100644 --- a/lib/sources/multisrc/mmrcms/src/mmrcms.dart +++ b/lib/sources/multisrc/mmrcms/src/mmrcms.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:developer'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:html/dom.dart'; @@ -193,4 +194,28 @@ class Mmrcms extends MangaYomiServices { } return pageUrls; } + + @override + Future> getLatestUpdatesManga( + {required String source, + required int page, + required AutoDisposeFutureProviderRef ref}) async { + final dom = await ref.watch(httpGetProvider( + url: '${getMangaBaseUrl(source)}/latest-release?page=$page', + source: source, + resDom: true) + .future) as Document?; + final urlElement = dom!.querySelectorAll("div.mangalist div.manga-item"); + + for (var e in urlElement) { + RegExp exp = RegExp(r'href="([^"]+)"'); + Iterable matches = exp.allMatches(e.querySelector("a")!.outerHtml); + String? firstMatch = matches.first.group(1); + url.add(firstMatch); + name.add(e.querySelector("a")!.text); + image.add( + "${getMangaBaseUrl(source)}/uploads/manga/${firstMatch!.split('/').last}/cover/cover_250x350.jpg"); + } + return mangaRes(); + } } diff --git a/lib/sources/service.dart b/lib/sources/service.dart index 74486f82..2354b124 100644 --- a/lib/sources/service.dart +++ b/lib/sources/service.dart @@ -67,6 +67,10 @@ abstract class MangaYomiServices { {required String source, required int page, required AutoDisposeFutureProviderRef ref}); + Future> getLatestUpdatesManga( + {required String source, + required int page, + required AutoDisposeFutureProviderRef ref}); Future getMangaDetail( {required GetManga manga, required String lang, diff --git a/lib/sources/source_list.dart b/lib/sources/source_list.dart index e42a0e39..824194ff 100644 --- a/lib/sources/source_list.dart +++ b/lib/sources/source_list.dart @@ -3,14 +3,13 @@ import 'package:mangayomi/sources/multisrc/heancms/heancms_source_list.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/multisrc/mangathemesia/mangathemesia_source_list.dart'; import 'package:mangayomi/sources/multisrc/mmrcms/mmrcms_source_list.dart'; import 'package:mangayomi/sources/multisrc/madara/madara_source_list.dart'; List get sourcesList => _sourcesList; List _sourcesList = [ mangahereSource, - mangakawaiiSource, + // mangakawaiiSource, ...mangathemesiaSourcesList, ...comickSourcesList, ...mmrcmsSourcesList, diff --git a/lib/sources/src/all/comick/src/comick.dart b/lib/sources/src/all/comick/src/comick.dart index f3c6ca22..8198d76d 100644 --- a/lib/sources/src/all/comick/src/comick.dart +++ b/lib/sources/src/all/comick/src/comick.dart @@ -1,7 +1,6 @@ import 'dart:convert'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:mangayomi/models/chapter.dart'; -import 'package:mangayomi/models/manga.dart'; import 'package:mangayomi/sources/src/all/comick/src/model/chapter_page_comick.dart'; import 'package:mangayomi/sources/src/all/comick/src/model/manga_chapter_detail.dart'; import 'package:mangayomi/sources/src/all/comick/src/model/manga_detail_comick.dart'; @@ -11,8 +10,6 @@ import 'package:mangayomi/services/http_service/http_service.dart'; import 'package:mangayomi/sources/service.dart'; import 'package:mangayomi/sources/src/all/comick/src/utils/utils.dart'; import 'package:mangayomi/sources/utils/utils.dart'; -import 'package:http/http.dart' as http; -import 'package:mangayomi/utils/headers.dart'; class Comick extends MangaYomiServices { @override @@ -146,12 +143,37 @@ class Comick extends MangaYomiServices { Future paginatedChapterListRequest(AutoDisposeFutureProviderRef ref, String mangaUrl, int page, String source, String lang) async { - final url = Uri.parse( - "${getMangaAPIUrl(source)}$mangaUrl/chapters?${lang != "all" ? 'lang=$lang' : ''}&tachiyomi=true&page=$page"); - var request = http.Request('GET', url); - request.headers.addAll(ref.watch(headersProvider(source: source))); - http.StreamedResponse response = await request.send(); + final response = await ref.watch(httpGetProvider( + url: + "${getMangaAPIUrl(source)}$mangaUrl/chapters?${lang != "all" ? 'lang=$lang' : ''}&tachiyomi=true&page=$page", + source: source, + resDom: false) + .future) as String?; + return response!; + } - return response.stream.bytesToString(); + @override + Future> getLatestUpdatesManga( + {required String source, + required int page, + required AutoDisposeFutureProviderRef ref}) async { + source = source.toLowerCase(); + final response = await ref.watch(httpGetProvider( + url: + '${getMangaAPIUrl(source)}/v1.0/search?sort=uploaded&page=$page&tachiyomi=true', + source: source, + resDom: false) + .future) 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.hid}#"); + name.add(popular.title); + image.add(popular.coverUrl); + } + + return mangaRes(); } } diff --git a/lib/sources/src/en/mangahere/mangahere_source.dart b/lib/sources/src/en/mangahere/mangahere_source.dart index ae6cf67d..a5f5cc0e 100644 --- a/lib/sources/src/en/mangahere/mangahere_source.dart +++ b/lib/sources/src/en/mangahere/mangahere_source.dart @@ -8,7 +8,6 @@ Source _mangahereSource = Source( lang: "en", typeSource: TypeSource.single, logoUrl: 'http://static.mangahere.cc/v20210106/mangahere/images/logo.png', - isFullData: true, dateFormat: "MMM dd,yyyy", dateFormatLocale: "en", ); diff --git a/lib/sources/src/en/mangahere/src/mangahere.dart b/lib/sources/src/en/mangahere/src/mangahere.dart index 241d6884..2720e661 100644 --- a/lib/sources/src/en/mangahere/src/mangahere.dart +++ b/lib/sources/src/en/mangahere/src/mangahere.dart @@ -18,7 +18,7 @@ class Mangahere extends MangaYomiServices { required String source, required AutoDisposeFutureProviderRef ref}) async { final dom = await ref.watch(httpGetProvider( - url: "http://www.mangahere.cc${manga.url}", + url: "${getMangaBaseUrl(source)}/${manga.url}", source: source, resDom: true) .future) as Document?; @@ -120,32 +120,26 @@ class Mangahere extends MangaYomiServices { required int page, required AutoDisposeFutureProviderRef ref}) async { final dom = await ref.watch(httpGetProvider( - url: 'https://www.mangahere.cc/ranking/', + url: '${getMangaBaseUrl(source)}/directory/$page.htm', source: source, resDom: true) .future) as Document?; - if (dom! - .querySelectorAll( - 'body > div.container.weekrank.ranking > div > div > ul > li > a') - .isNotEmpty) { + if (dom!.querySelectorAll('.manga-list-1-list li').isNotEmpty) { url = dom - .querySelectorAll( - 'body > div.container.weekrank.ranking > div > div > ul > li > a ') + .querySelectorAll('.manga-list-1-list 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') + .querySelectorAll('.manga-list-1-list 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 ') + .querySelectorAll('.manga-list-1-list li > a ') .where((e) => e.attributes.containsKey('title')) .map((e) => e.attributes['title']) .toList(); @@ -219,7 +213,8 @@ class Mangahere extends MangaYomiServices { return secretKeyResultScript; } - var link = "http://www.mangahere.cc${chapter.url!}"; + var link = + "${getMangaBaseUrl(chapter.manga.value!.source!)}${chapter.url!}"; final response = await ref.watch( httpGetProvider(url: link, source: "mangahere", resDom: false) .future) as String?; @@ -307,6 +302,39 @@ class Mangahere extends MangaYomiServices { } return pageUrls; } + + @override + Future> getLatestUpdatesManga( + {required String source, + required int page, + required AutoDisposeFutureProviderRef ref}) async { + final dom = await ref.watch(httpGetProvider( + url: '${getMangaBaseUrl(source)}/directory/$page.htm?latest', + source: source, + resDom: true) + .future) as Document?; + if (dom!.querySelectorAll('.manga-list-1-list li').isNotEmpty) { + url = dom + .querySelectorAll('.manga-list-1-list li > a ') + .where((e) => e.attributes.containsKey('href')) + .map((e) => e.attributes['href']) + .toList(); + + image = dom + .querySelectorAll('.manga-list-1-list 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('.manga-list-1-list li > a ') + .where((e) => e.attributes.containsKey('title')) + .map((e) => e.attributes['title']) + .toList(); + } + return mangaRes(); + } } int parseMangaHereChapterDate(String date, String source) { diff --git a/lib/sources/src/fr/japscan/src/japscan.dart b/lib/sources/src/fr/japscan/src/japscan.dart index 4e788b1d..22e5b1e3 100644 --- a/lib/sources/src/fr/japscan/src/japscan.dart +++ b/lib/sources/src/fr/japscan/src/japscan.dart @@ -19,16 +19,18 @@ class Japscan extends MangaYomiServices { required String lang, required String source, required AutoDisposeFutureProviderRef ref}) async { - final dom = await ref.watch( - httpGetProvider(url: manga.url!, source: source, resDom: true) - .future) as Document?; + final dom = await ref.watch(httpGetProvider( + url: manga.url!, + source: source, + resDom: true, + ).future) 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); - manga.imageUrl = 'https://www.japscan.lol$srcValue'; + manga.imageUrl = '${getMangaBaseUrl(source)}l$srcValue'; if (dom.querySelectorAll('.col-7 > p').isNotEmpty) { final stat = dom @@ -36,13 +38,16 @@ class Japscan extends MangaYomiServices { .where((element) => element.innerHtml.contains('Statut:')) .map((e) => e.text) .toList(); - String sta = stat[0].replaceAll('Statut:', '').trim(); + if (stat.isNotEmpty) { + String sta = stat[0].replaceAll('Statut:', '').trim(); status = (switch (sta) { "En Cours" => Status.ongoing, "Terminé" => Status.completed, _ => Status.unknown, }); + } else { + status = Status.unknown; } final auth = dom @@ -85,7 +90,7 @@ class Japscan extends MangaYomiServices { RegExp exp = RegExp(r'href="([^"]+)"'); String? srcValue = exp.firstMatch(ok)?.group(1); - chapterUrl.add('https://www.japscan.lol$srcValue'); + chapterUrl.add('${getMangaBaseUrl(source)}l$srcValue'); } final chapterTitlee = @@ -113,7 +118,7 @@ class Japscan extends MangaYomiServices { required int page, required AutoDisposeFutureProviderRef ref}) async { final dom = await ref.watch(httpGetProvider( - url: "https://www.japscan.lol/", source: source, resDom: true) + url: "${getMangaBaseUrl(source)}l/", source: source, resDom: true) .future) as Document?; if (dom!.querySelectorAll('#top_mangas_week > ul > li ').isNotEmpty) { final urls = dom @@ -122,7 +127,7 @@ class Japscan extends MangaYomiServices { .map((e) => e.attributes['href']) .toList(); for (var ok in urls) { - url.add("https://www.japscan.lol$ok"); + url.add("${getMangaBaseUrl(source)}l$ok"); } name = dom .querySelectorAll( @@ -194,7 +199,7 @@ class Japscan extends MangaYomiServices { Match? match = regex.firstMatch(response!); String zjsurl = match!.group(1)!; baseUrl = response; - zjsUrl = "https://www.japscan.lol/zjs/$zjsurl"; + zjsUrl = "${getMangaBaseUrl(chapter.manga.value!.source!)}l/zjs/$zjsurl"; zjs(ref); await Future.doWhile(() async { await Future.delayed(const Duration(seconds: 1)); @@ -252,4 +257,38 @@ class Japscan extends MangaYomiServices { } isOk = true; } + + @override + Future> getLatestUpdatesManga( + {required String source, + required int page, + required AutoDisposeFutureProviderRef ref}) async { + final dom = await ref.watch(httpGetProvider( + url: "${getMangaBaseUrl(source)}l/", source: source, resDom: true) + .future) as Document?; + if (dom! + .querySelectorAll( + '#chapters h3.text-truncate, #chapters_list h3.text-truncate') + .isNotEmpty) { + final urls = dom + .querySelectorAll( + '#chapters h3.text-truncate, #chapters_list h3.text-truncate > a') + .where((e) => e.attributes['href'].toString().contains('manga')) + .map((e) => e.attributes['href']) + .toList(); + for (var ok in urls) { + url.add("${getMangaBaseUrl(source)}l$ok"); + } + + name = dom + .querySelectorAll( + '#chapters h3.text-truncate, #chapters_list h3.text-truncate > a.text-dark.font-weight-bold') + .map((e) => e.innerHtml) + .toList(); + for (var i = 0; i < name.length; i++) { + image.add(""); + } + } + return mangaRes(); + } } diff --git a/lib/sources/src/fr/mangakawaii/src/mangakawaii.dart b/lib/sources/src/fr/mangakawaii/src/mangakawaii.dart index 030ff55b..686793fd 100644 --- a/lib/sources/src/fr/mangakawaii/src/mangakawaii.dart +++ b/lib/sources/src/fr/mangakawaii/src/mangakawaii.dart @@ -212,4 +212,10 @@ class MangaKawaii extends MangaYomiServices { } return pageUrls; } + + @override + Future> getLatestUpdatesManga({required String source, required int page, required AutoDisposeFutureProviderRef ref}) { + // TODO: implement getLatestUpdatesManga + throw UnimplementedError(); + } }