diff --git a/lib/eval/bridge_class/video_model.dart b/lib/eval/bridge_class/video_model.dart index 312110c2..0a8f2b53 100644 --- a/lib/eval/bridge_class/video_model.dart +++ b/lib/eval/bridge_class/video_model.dart @@ -41,6 +41,11 @@ class $VideoModel implements VideoModel, $Instance { BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, [BridgeTypeRef.type(RuntimeTypes.dynamicType)])), false), + BridgeParameter( + 'audios', + BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list, + [BridgeTypeRef.type(RuntimeTypes.dynamicType)])), + false), ])) }, // Specify class fields diff --git a/lib/eval/m_bridge.dart b/lib/eval/m_bridge.dart index 278ea48b..8f4cd9a9 100644 --- a/lib/eval/m_bridge.dart +++ b/lib/eval/m_bridge.dart @@ -36,6 +36,7 @@ import 'package:mangayomi/services/anime_extractors/your_upload_extractor.dart'; import 'package:mangayomi/services/http_service/cloudflare/cloudflare_bypass.dart'; import 'package:mangayomi/utils/constant.dart'; import 'package:mangayomi/utils/cryptoaes/crypto_aes.dart'; +import 'package:mangayomi/utils/cryptoaes/deobfuscator.dart'; import 'package:mangayomi/utils/extensions.dart'; import 'package:mangayomi/utils/reg_exp_matcher.dart'; import 'package:mangayomi/utils/xpath_selector.dart'; @@ -110,7 +111,7 @@ class MBridge { .trimLeft() .trimRight(); } catch (e) { - _botToast(e.toString()); + botToast(e.toString()); throw Exception(e); } } @@ -198,7 +199,7 @@ class MBridge { //return last element of the resRegExp list return resRegExp.last.trim().trimLeft().trimRight(); } catch (e) { - _botToast(e.toString()); + botToast(e.toString()); throw Exception(e); } } @@ -225,7 +226,7 @@ class MBridge { return attr; } } catch (e) { - // _botToast(e.toString()); + // botToast(e.toString()); return ""; } } @@ -296,9 +297,11 @@ class MBridge { ..launch(url); await Future.doWhile(() async { - await Future.delayed(const Duration(seconds: 10)); - html = await decodeHtml(webview); - if (xpathSelector(html!).query(rule).attrs.isEmpty) { + await Future.delayed(const Duration(seconds: 1)); + html = await decodeHtml( + webview, + ); + if (html == null || xpathSelector(html!).query(rule).attrs.isEmpty) { html = await decodeHtml(webview); return true; } @@ -374,7 +377,7 @@ class MBridge { final jsPacker = JSPacker(code); return jsPacker.unpack() ?? ""; } catch (e) { - _botToast(e.toString()); + botToast(e.toString()); throw Exception(e); } } @@ -423,7 +426,7 @@ class MBridge { }).toList(); } } catch (e) { - _botToast(e.toString()); + botToast(e.toString()); throw Exception(e); } } @@ -484,7 +487,7 @@ class MBridge { } return listRg.first; } catch (e) { - _botToast(e.toString()); + botToast(e.toString()); throw Exception(e); } } @@ -608,7 +611,7 @@ class MBridge { return result; } catch (e) { - _botToast(e.toString()); + botToast(e.toString()); return ""; } } @@ -682,7 +685,7 @@ class MBridge { return result; } catch (e) { - _botToast(e.toString()); + botToast(e.toString()); return ""; } } @@ -778,7 +781,7 @@ class MBridge { ["menit", "dakika", "min", "minute", "minuto", "นาที", "دقائق"]) .anyWordIn(date)) { return cal.subtract(Duration(minutes: number)).millisecondsSinceEpoch; - } else if (WordSet(["detik", "segundo", "second", "วินาที"]) + } else if (WordSet(["detik", "segundo", "second", "วินาที", "sec"]) .anyWordIn(date)) { return cal.subtract(Duration(seconds: number)).millisecondsSinceEpoch; } else if (WordSet(["week", "semana"]).anyWordIn(date)) { @@ -872,11 +875,15 @@ class MBridge { } catch (_) {} } } - _botToast(e.toString()); + botToast(e.toString()); throw Exception(e); } } + static String deobfuscateJsPassword(String inputString) { + return Deobfuscator.deobfuscateJsPassword(inputString); + } + static Future> sibnetExtractor(String url) async { return await SibnetExtractor().videosFromUrl( url, @@ -1097,6 +1104,19 @@ class $MBridge extends MBridge with $Bridge { ], namedParams: []), isStatic: true), + 'deobfuscateJsPassword': BridgeMethodDef( + BridgeFunctionDef( + returns: BridgeTypeAnnotation( + BridgeTypeRef.type(RuntimeTypes.stringType)), + params: [ + BridgeParameter( + 'inputString', + BridgeTypeAnnotation( + BridgeTypeRef.type(RuntimeTypes.stringType)), + false), + ], + namedParams: []), + isStatic: true), 'sibnetExtractor': BridgeMethodDef( BridgeFunctionDef( returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future, @@ -2033,6 +2053,10 @@ class $MBridge extends MBridge with $Bridge { $String(MBridge.parseChapterDate( args[0]!.$value, args[1]!.$value, args[2]!.$value)); + static $String $deobfuscateJsPassword( + Runtime runtime, $Value? target, List<$Value?> args) => + $String(MBridge.deobfuscateJsPassword(args[0]!.$value)); + static $String $querySelectorAll( Runtime runtime, $Value? target, List<$Value?> args) => $String(MBridge.querySelectorAll( @@ -2160,7 +2184,7 @@ class $MBridge extends MBridge with $Bridge { void $bridgeSet(String identifier, $Value value) {} } -void _botToast(String title) { +void botToast(String title) { BotToast.showSimpleNotification( onlyOne: true, dismissDirections: [DismissDirection.horizontal, DismissDirection.down], diff --git a/lib/eval/runtime/runtime.dart b/lib/eval/runtime/runtime.dart index 1104a387..581784fb 100644 --- a/lib/eval/runtime/runtime.dart +++ b/lib/eval/runtime/runtime.dart @@ -99,6 +99,8 @@ Runtime runtimeEval(Uint8List bytecode) { 'package:bridge_lib/bridge_lib.dart', 'MBridge.xpath', $MBridge.$xpath); runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart', 'MBridge.querySelector', $MBridge.$querySelector); + runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart', + 'MBridge.deobfuscateJsPassword', $MBridge.$deobfuscateJsPassword); runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart', 'MBridge.querySelectorAll', $MBridge.$querySelectorAll); runtime.setup(); diff --git a/lib/modules/browse/extension/extension_detail.dart b/lib/modules/browse/extension/extension_detail.dart index 2f7894bc..ba3f9509 100644 --- a/lib/modules/browse/extension/extension_detail.dart +++ b/lib/modules/browse/extension/extension_detail.dart @@ -3,17 +3,24 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:mangayomi/main.dart'; import 'package:mangayomi/models/source.dart'; +import 'package:mangayomi/modules/browse/extension/providers/extension_preferences_providers.dart'; import 'package:mangayomi/providers/l10n_providers.dart'; import 'package:mangayomi/utils/colors.dart'; import 'package:mangayomi/utils/language.dart'; import 'package:mangayomi/utils/media_query.dart'; -class ExtensionDetail extends ConsumerWidget { +class ExtensionDetail extends ConsumerStatefulWidget { final Source source; const ExtensionDetail({super.key, required this.source}); @override - Widget build(BuildContext context, WidgetRef ref) { + ConsumerState createState() => _ExtensionDetailState(); +} + +class _ExtensionDetailState extends ConsumerState { + late Source source = widget.source; + @override + Widget build(BuildContext context) { final l10n = l10nLocalizations(context)!; return Scaffold( appBar: AppBar( @@ -28,10 +35,10 @@ class ExtensionDetail extends ConsumerWidget { color: Theme.of(context).secondaryHeaderColor.withOpacity(0.5), borderRadius: BorderRadius.circular(10)), - child: source.iconUrl!.isEmpty + child: widget.source.iconUrl!.isEmpty ? const Icon(Icons.source_outlined, size: 140) : CachedNetworkImage( - imageUrl: source.iconUrl!, + imageUrl: widget.source.iconUrl!, fit: BoxFit.contain, width: 140, height: 140, @@ -50,7 +57,7 @@ class ExtensionDetail extends ConsumerWidget { Padding( padding: const EdgeInsets.all(12), child: Text( - source.name!, + widget.source.name!, style: const TextStyle(fontSize: 23, fontWeight: FontWeight.bold), textAlign: TextAlign.center, ), @@ -69,7 +76,7 @@ class ExtensionDetail extends ConsumerWidget { Column( children: [ Text( - source.version!, + widget.source.version!, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold), ), @@ -79,7 +86,7 @@ class ExtensionDetail extends ConsumerWidget { ), ], ), - if (source.isNsfw!) + if (widget.source.isNsfw!) Container( decoration: BoxDecoration( color: Colors.red.withOpacity(0.7), @@ -96,7 +103,7 @@ class ExtensionDetail extends ConsumerWidget { Column( children: [ Text( - completeLanguageName(source.lang!), + completeLanguageName(widget.source.lang!), style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold), ), @@ -131,10 +138,10 @@ class ExtensionDetail extends ConsumerWidget { builder: (ctx) { return AlertDialog( title: Text( - source.name!, + widget.source.name!, ), - content: - Text(l10n.uninstall_extension(source.name!)), + content: Text( + l10n.uninstall_extension(widget.source.name!)), actions: [ Row( mainAxisAlignment: MainAxisAlignment.end, @@ -149,8 +156,8 @@ class ExtensionDetail extends ConsumerWidget { ), TextButton( onPressed: () { - isar.writeTxnSync( - () => isar.sources.putSync(source + isar.writeTxnSync(() => + isar.sources.putSync(widget.source ..sourceCode = "" ..isAdded = false ..isPinned = false)); @@ -170,7 +177,86 @@ class ExtensionDetail extends ConsumerWidget { fontSize: 20, fontWeight: FontWeight.bold), )), ), - ) + ), + ref.watch(getMirrorPrefProvider(widget.source.sourceCode!)).when( + data: (data) => data != null + ? ListTile( + onTap: () { + showDialog( + context: context, + builder: (context) { + return AlertDialog( + title: Text( + l10n.relative_timestamp, + ), + content: SizedBox( + width: mediaWidth(context, 0.8), + child: ListView.builder( + shrinkWrap: true, + itemCount: data.entries.length, + itemBuilder: (context, index) { + return RadioListTile( + dense: true, + contentPadding: + const EdgeInsets.all(0), + value: data.entries + .toList()[index] + .value, + groupValue: widget.source.baseUrl!, + onChanged: (value) { + isar.writeTxnSync(() => isar + .sources + .putSync(widget.source + ..baseUrl = data.entries + .toList()[index] + .value)); + setState(() { + source = isar.sources + .getSync(source.id!)!; + }); + + Navigator.pop(context); + }, + title: Row( + children: [ + Text(data.entries + .toList()[index] + .key) + ], + ), + ); + }, + )), + actions: [ + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + TextButton( + onPressed: () async { + Navigator.pop(context); + }, + child: Text( + l10n.cancel, + style: TextStyle( + color: primaryColor(context)), + )), + ], + ) + ], + ); + }); + }, + title: Text(l10n.relative_timestamp), + subtitle: Text( + widget.source.baseUrl!, + style: TextStyle( + fontSize: 11, color: secondaryColor(context)), + ), + ) + : Container(), + error: (error, stackTrace) => Text(error.toString()), + loading: () => Container(), + ) ], ), ); diff --git a/lib/modules/browse/extension/providers/extension_preferences_providers.dart b/lib/modules/browse/extension/providers/extension_preferences_providers.dart new file mode 100644 index 00000000..eadf4183 --- /dev/null +++ b/lib/modules/browse/extension/providers/extension_preferences_providers.dart @@ -0,0 +1,26 @@ +import 'package:dart_eval/stdlib/core.dart'; +import 'package:mangayomi/eval/compiler/compiler.dart'; +import 'package:mangayomi/eval/runtime/runtime.dart'; +import 'package:riverpod_annotation/riverpod_annotation.dart'; +part 'extension_preferences_providers.g.dart'; + +@riverpod +Future?> getMirrorPref( + GetMirrorPrefRef ref, String codeSource) async { + try { + final bytecode = compilerEval(codeSource); + final runtime = runtimeEval(bytecode); + var res = await runtime.executeLib( + 'package:mangayomi/source_code.dart', + 'getMirrorPref', + ); + Map headers = {}; + if (res is $Map) { + headers = res.$reified + .map((key, value) => MapEntry(key.toString(), value.toString())); + } + return headers; + } catch (_) { + return null; + } +} diff --git a/lib/modules/browse/extension/providers/extension_preferences_providers.g.dart b/lib/modules/browse/extension/providers/extension_preferences_providers.g.dart new file mode 100644 index 00000000..5ddd393d --- /dev/null +++ b/lib/modules/browse/extension/providers/extension_preferences_providers.g.dart @@ -0,0 +1,114 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'extension_preferences_providers.dart'; + +// ************************************************************************** +// RiverpodGenerator +// ************************************************************************** + +String _$getMirrorPrefHash() => r'87d8329eabbe702d2e612a04cfe6fc719519194c'; + +/// 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 GetMirrorPrefRef = AutoDisposeFutureProviderRef?>; + +/// See also [getMirrorPref]. +@ProviderFor(getMirrorPref) +const getMirrorPrefProvider = GetMirrorPrefFamily(); + +/// See also [getMirrorPref]. +class GetMirrorPrefFamily extends Family?>> { + /// See also [getMirrorPref]. + const GetMirrorPrefFamily(); + + /// See also [getMirrorPref]. + GetMirrorPrefProvider call( + String codeSource, + ) { + return GetMirrorPrefProvider( + codeSource, + ); + } + + @override + GetMirrorPrefProvider getProviderOverride( + covariant GetMirrorPrefProvider provider, + ) { + return call( + provider.codeSource, + ); + } + + 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'getMirrorPrefProvider'; +} + +/// See also [getMirrorPref]. +class GetMirrorPrefProvider + extends AutoDisposeFutureProvider?> { + /// See also [getMirrorPref]. + GetMirrorPrefProvider( + this.codeSource, + ) : super.internal( + (ref) => getMirrorPref( + ref, + codeSource, + ), + from: getMirrorPrefProvider, + name: r'getMirrorPrefProvider', + debugGetCreateSourceHash: + const bool.fromEnvironment('dart.vm.product') + ? null + : _$getMirrorPrefHash, + dependencies: GetMirrorPrefFamily._dependencies, + allTransitiveDependencies: + GetMirrorPrefFamily._allTransitiveDependencies, + ); + + final String codeSource; + + @override + bool operator ==(Object other) { + return other is GetMirrorPrefProvider && other.codeSource == codeSource; + } + + @override + int get hashCode { + var hash = _SystemHash.combine(0, runtimeType.hashCode); + hash = _SystemHash.combine(hash, codeSource.hashCode); + + return _SystemHash.finish(hash); + } +} +// ignore_for_file: type=lint +// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member diff --git a/lib/modules/library/providers/local_archive.dart b/lib/modules/library/providers/local_archive.dart index b8ab96cf..9a6d6422 100644 --- a/lib/modules/library/providers/local_archive.dart +++ b/lib/modules/library/providers/local_archive.dart @@ -3,8 +3,8 @@ import 'package:file_picker/file_picker.dart'; import 'package:mangayomi/main.dart'; import 'package:mangayomi/models/chapter.dart'; import 'package:mangayomi/models/manga.dart'; -import 'package:mangayomi/modules/archive_reader/models/models.dart'; -import 'package:mangayomi/modules/archive_reader/providers/archive_reader_providers.dart'; +import 'package:mangayomi/modules/manga/archive_reader/models/models.dart'; +import 'package:mangayomi/modules/manga/archive_reader/providers/archive_reader_providers.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'local_archive.g.dart'; diff --git a/lib/modules/library/providers/local_archive.g.dart b/lib/modules/library/providers/local_archive.g.dart index d4668000..83150fb8 100644 --- a/lib/modules/library/providers/local_archive.g.dart +++ b/lib/modules/library/providers/local_archive.g.dart @@ -7,7 +7,7 @@ part of 'local_archive.dart'; // ************************************************************************** String _$importArchivesFromFileHash() => - r'25ff2ca889a31d482a95af7cb9be8ebd9cf0dc89'; + r'f911dfd50c20ebbfec97322dd0bf44261a025341'; /// Copied from Dart SDK class _SystemHash { diff --git a/lib/modules/main_view/main_screen.dart b/lib/modules/main_view/main_screen.dart index 8a54f275..4b2c3f7b 100644 --- a/lib/modules/main_view/main_screen.dart +++ b/lib/modules/main_view/main_screen.dart @@ -76,17 +76,19 @@ class MainScreen extends ConsumerWidget { children: [ AnimatedContainer( duration: const Duration(milliseconds: 0), - width: isLongPressed - ? 0 - : location == null - ? 100 - : location != '/MangaLibrary' && - location != '/AnimeLibrary' && - location != '/history' && - location != '/browse' && - location != '/more' - ? 0 - : 100, + width: switch (isLongPressed) { + true => 0, + _ => switch (location) { + null => 100, + != '/MangaLibrary' && + != '/AnimeLibrary' && + != '/history' && + != '/browse' && + != '/more' => + 0, + _ => 100, + }, + }, child: NavigationRailTheme( data: NavigationRailThemeData( indicatorShape: RoundedRectangleBorder( @@ -176,17 +178,19 @@ class MainScreen extends ConsumerWidget { : AnimatedContainer( duration: const Duration(milliseconds: 0), width: mediaWidth(context, 1), - height: isLongPressed - ? 0 - : location == null - ? null - : location != '/MangaLibrary' && - location != '/AnimeLibrary' && - location != '/history' && - location != '/browse' && - location != '/more' - ? 0 - : null, + height: switch (isLongPressed) { + true => 0, + _ => switch (location) { + null => null, + != '/MangaLibrary' && + != '/AnimeLibrary' && + != '/history' && + != '/browse' && + != '/more' => + 0, + _ => null, + }, + }, child: NavigationBarTheme( data: NavigationBarThemeData( indicatorShape: RoundedRectangleBorder( diff --git a/lib/modules/archive_reader/models/models.dart b/lib/modules/manga/archive_reader/models/models.dart similarity index 100% rename from lib/modules/archive_reader/models/models.dart rename to lib/modules/manga/archive_reader/models/models.dart diff --git a/lib/modules/archive_reader/providers/archive_reader_providers.dart b/lib/modules/manga/archive_reader/providers/archive_reader_providers.dart similarity index 98% rename from lib/modules/archive_reader/providers/archive_reader_providers.dart rename to lib/modules/manga/archive_reader/providers/archive_reader_providers.dart index fc199f33..b4ae3356 100644 --- a/lib/modules/archive_reader/providers/archive_reader_providers.dart +++ b/lib/modules/manga/archive_reader/providers/archive_reader_providers.dart @@ -1,7 +1,7 @@ import 'dart:io'; import 'package:archive/archive_io.dart'; import 'package:flutter/foundation.dart'; -import 'package:mangayomi/modules/archive_reader/models/models.dart'; +import 'package:mangayomi/modules/manga/archive_reader/models/models.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; part 'archive_reader_providers.g.dart'; diff --git a/lib/modules/archive_reader/providers/archive_reader_providers.g.dart b/lib/modules/manga/archive_reader/providers/archive_reader_providers.g.dart similarity index 100% rename from lib/modules/archive_reader/providers/archive_reader_providers.g.dart rename to lib/modules/manga/archive_reader/providers/archive_reader_providers.g.dart diff --git a/lib/modules/webview/webview.dart b/lib/modules/webview/webview.dart index 5289e63e..6dc63d2d 100644 --- a/lib/modules/webview/webview.dart +++ b/lib/modules/webview/webview.dart @@ -10,6 +10,7 @@ import 'package:mangayomi/main.dart'; import 'package:mangayomi/models/settings.dart'; import 'package:mangayomi/providers/l10n_providers.dart'; import 'package:mangayomi/services/http_service/cloudflare/cookie.dart'; +import 'package:mangayomi/services/http_service/cloudflare/providers/cookie_providers.dart'; import 'package:mangayomi/utils/constant.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:share_plus/share_plus.dart'; @@ -182,7 +183,6 @@ class _MangaWebViewState extends ConsumerState { _url = url.toString(); }); }, - shouldOverrideUrlLoading: (controller, navigationAction) async { var uri = navigationAction.request.url!; @@ -213,7 +213,6 @@ class _MangaWebViewState extends ConsumerState { _url = url.toString(); }); }, - onProgressChanged: (controller, progress) async { setState(() { this.progress = progress / 100; @@ -233,12 +232,12 @@ class _MangaWebViewState extends ConsumerState { _canGoback = canGoback; _canGoForward = canGoForward; }); - },initialOptions: InAppWebViewGroupOptions( - crossPlatform: InAppWebViewOptions(userAgent: isar.settings.getSync(227)!.userAgent!), - ), - - initialUrlRequest: - URLRequest(url: Uri.parse(widget.url)), + }, + initialOptions: InAppWebViewGroupOptions( + crossPlatform: InAppWebViewOptions( + userAgent: isar.settings.getSync(227)!.userAgent!), + ), + initialUrlRequest: URLRequest(url: Uri.parse(widget.url)), ), ), ], @@ -256,10 +255,17 @@ Future getWebViewPath() async { ); } -decodeHtml(Webview webview) async { +Future decodeHtml(Webview webview, {String? sourceId}) async { final html = await webview .evaluateJavaScript("window.document.documentElement.outerHTML;"); - // final cookie = await webview.evaluateJavaScript("window.document.cookie;"); - // log(cookie!); - return jsonDecode(html!) as String; + final cookie = await webview.evaluateJavaScript("window.document.cookie;"); + if (cookie != null && sourceId != null) { + setCookieBA(cookie, sourceId); + } + + final res = jsonDecode(html!) as String; + + return res == "" || res.isEmpty + ? null + : res; } diff --git a/lib/services/get_anime_servers.dart b/lib/services/get_anime_servers.dart index 2d50208a..2c17b13a 100644 --- a/lib/services/get_anime_servers.dart +++ b/lib/services/get_anime_servers.dart @@ -43,7 +43,6 @@ Future<(List