diff --git a/lib/eval/model/m_bridge.dart b/lib/eval/model/m_bridge.dart index 8a988e4..59181f0 100644 --- a/lib/eval/model/m_bridge.dart +++ b/lib/eval/model/m_bridge.dart @@ -6,7 +6,6 @@ import 'package:flutter/material.dart'; import 'package:html/dom.dart'; import 'package:intl/date_symbol_data_local.dart'; import 'package:intl/intl.dart'; -import 'package:js_packer/js_packer.dart'; import 'package:json_path/json_path.dart'; import 'package:mangayomi/eval/model/document.dart'; import 'package:mangayomi/models/manga.dart'; @@ -27,6 +26,7 @@ import 'package:mangayomi/services/anime_extractors/voe_extractor.dart'; import 'package:mangayomi/services/anime_extractors/your_upload_extractor.dart'; import 'package:mangayomi/utils/cryptoaes/crypto_aes.dart'; import 'package:mangayomi/utils/cryptoaes/deobfuscator.dart'; +import 'package:mangayomi/utils/cryptoaes/js_unpacker.dart'; import 'package:mangayomi/utils/extensions/string_extensions.dart'; import 'package:mangayomi/utils/reg_exp_matcher.dart'; import 'package:xpath_selector_html_parser/xpath_selector_html_parser.dart'; @@ -124,8 +124,7 @@ class MBridge { static $Value? _unpackJs(_, __, List<$Value?> args) { String code = args[0]!.$reified; try { - final jsPacker = JSPacker(code); - return $String(jsPacker.unpack() ?? ""); + return $String(JsUnpacker.unpackAndCombine(code) ?? ""); } catch (_) { return $String(""); } diff --git a/lib/modules/anime/anime_player_view.dart b/lib/modules/anime/anime_player_view.dart index 5c5ae52..a798f0f 100644 --- a/lib/modules/anime/anime_player_view.dart +++ b/lib/modules/anime/anime_player_view.dart @@ -660,7 +660,7 @@ class _AnimeStreamPageState extends riv.ConsumerState { List fitList = [ BoxFit.contain, BoxFit.cover, - BoxFit.fill, + BoxFit.cover, BoxFit.fitHeight, BoxFit.fitWidth, BoxFit.none diff --git a/lib/modules/browse/global_search/global_search_screen.dart b/lib/modules/browse/global_search/global_search_screen.dart index 56c6156..9b63f33 100644 --- a/lib/modules/browse/global_search/global_search_screen.dart +++ b/lib/modules/browse/global_search/global_search_screen.dart @@ -282,7 +282,7 @@ class _MangaGlobalImageCardState extends ConsumerState : getMangaDetail.imageUrl!), width: 110, height: 150, - fit: BoxFit.fill)); + fit: BoxFit.cover)); }, ), BottomTextWidget( diff --git a/lib/modules/history/history_screen.dart b/lib/modules/history/history_screen.dart index 98080a9..7c5bc33 100644 --- a/lib/modules/history/history_screen.dart +++ b/lib/modules/history/history_screen.dart @@ -266,7 +266,7 @@ class _HistoryTabState extends ConsumerState { manga.imageUrl!), width: 60, height: 90, - fit: BoxFit.fill), + fit: BoxFit.cover), ), ), ), diff --git a/lib/modules/main_view/main_screen.dart b/lib/modules/main_view/main_screen.dart index dec4621..8e29281 100644 --- a/lib/modules/main_view/main_screen.dart +++ b/lib/modules/main_view/main_screen.dart @@ -274,7 +274,7 @@ class MainScreen extends ConsumerWidget { child: Image.asset( "assets/app_icons/icon.png", color: Colors.black, - fit: BoxFit.fill, + fit: BoxFit.cover, height: 100, ), ), @@ -286,7 +286,7 @@ class MainScreen extends ConsumerWidget { child: Image.asset( "assets/app_icons/icon.png", color: Colors.black, - fit: BoxFit.fill, + fit: BoxFit.cover, height: 100, ), ), diff --git a/lib/modules/manga/detail/manga_detail_view.dart b/lib/modules/manga/detail/manga_detail_view.dart index 74c82a4..2ad8886 100644 --- a/lib/modules/manga/detail/manga_detail_view.dart +++ b/lib/modules/manga/detail/manga_detail_view.dart @@ -1439,7 +1439,7 @@ class _MangaDetailViewState extends ConsumerState borderRadius: const BorderRadius.all(Radius.circular(5)), image: DecorationImage( image: imageProvider, - fit: BoxFit.fill, + fit: BoxFit.cover, ), ), ), @@ -1698,6 +1698,7 @@ class _MangaDetailViewState extends ConsumerState ..customCoverImage = null ..customCoverFromTracker = null); }); + Navigator.pop(context); } else if (value == 1) { FilePickerResult? result = await FilePicker.platform.pickFiles( diff --git a/lib/modules/manga/reader/providers/reader_controller_provider.dart b/lib/modules/manga/reader/providers/reader_controller_provider.dart index d1b73ee..5080aa9 100644 --- a/lib/modules/manga/reader/providers/reader_controller_provider.dart +++ b/lib/modules/manga/reader/providers/reader_controller_provider.dart @@ -39,7 +39,7 @@ BoxFit getBoxFit(ScaleType scaleType) { ScaleType.fitScreen => BoxFit.contain, ScaleType.originalSize => BoxFit.cover, ScaleType.smartFit => BoxFit.contain, - _ => BoxFit.fill + _ => BoxFit.cover }; } diff --git a/lib/modules/more/about/about_screen.dart b/lib/modules/more/about/about_screen.dart index e8cc9e5..31767c0 100644 --- a/lib/modules/more/about/about_screen.dart +++ b/lib/modules/more/about/about_screen.dart @@ -64,7 +64,7 @@ class _AboutScreenState extends ConsumerState { color: Theme.of(context).brightness == Brightness.light ? Colors.black : Colors.white, - fit: BoxFit.fill, + fit: BoxFit.cover, height: 100, ), ), diff --git a/lib/modules/more/more_screen.dart b/lib/modules/more/more_screen.dart index 97e6455..d3cf0d0 100644 --- a/lib/modules/more/more_screen.dart +++ b/lib/modules/more/more_screen.dart @@ -24,7 +24,7 @@ class MoreScreen extends StatelessWidget { color: Theme.of(context).brightness == Brightness.light ? Colors.black : Colors.white, - fit: BoxFit.fill, + fit: BoxFit.cover, height: 100, ), ), diff --git a/lib/modules/widgets/cover_view_widget.dart b/lib/modules/widgets/cover_view_widget.dart index 5d46bcc..4262a0c 100644 --- a/lib/modules/widgets/cover_view_widget.dart +++ b/lib/modules/widgets/cover_view_widget.dart @@ -47,7 +47,7 @@ class CoverViewWidget extends StatelessWidget { ) : Ink.image( height: 200, - fit: BoxFit.fill, + fit: BoxFit.cover, image: image!, child: Stack( children: children, diff --git a/lib/services/anime_extractors/filemoon.dart b/lib/services/anime_extractors/filemoon.dart index 2fc85c7..c5e0282 100644 --- a/lib/services/anime_extractors/filemoon.dart +++ b/lib/services/anime_extractors/filemoon.dart @@ -1,7 +1,7 @@ import 'package:http_interceptor/http_interceptor.dart'; -import 'package:js_packer/js_packer.dart'; import 'package:mangayomi/models/video.dart'; import 'package:mangayomi/services/http/interceptor.dart'; +import 'package:mangayomi/utils/cryptoaes/js_unpacker.dart'; import 'package:mangayomi/utils/extensions/string_extensions.dart'; import 'package:mangayomi/utils/xpath_selector.dart'; @@ -18,7 +18,7 @@ class FilemoonExtractor { .queryXPath('//script[contains(text(), "eval")]/text()') .attr; - final unpacked = JSPacker(jsEval!).unpack() ?? ""; + final unpacked = JsUnpacker.unpackAndCombine(jsEval!) ?? ""; final masterUrl = unpacked.isNotEmpty ? unpacked.substringAfter('{file:"').substringBefore('"}') diff --git a/lib/services/anime_extractors/mp4upload_extractor.dart b/lib/services/anime_extractors/mp4upload_extractor.dart index 6035bb4..b9b4a50 100644 --- a/lib/services/anime_extractors/mp4upload_extractor.dart +++ b/lib/services/anime_extractors/mp4upload_extractor.dart @@ -1,7 +1,7 @@ import 'package:http_interceptor/http_interceptor.dart'; -import 'package:js_packer/js_packer.dart'; import 'package:mangayomi/models/video.dart'; import 'package:mangayomi/services/http/interceptor.dart'; +import 'package:mangayomi/utils/cryptoaes/js_unpacker.dart'; import 'package:mangayomi/utils/extensions/string_extensions.dart'; import 'package:mangayomi/utils/xpath_selector.dart'; @@ -23,7 +23,7 @@ class Mp4uploadExtractor { .attrs; if (scriptElementWithEval.isNotEmpty) { - script = JSPacker(script).unpack() ?? ""; + script = JsUnpacker.unpackAndCombine(script) ?? ""; } else { final scriptElementWithSrc = xpathSelector(response.body) .queryXPath('//script[contains(text(), "player.src")]/text()') diff --git a/lib/services/anime_extractors/streamwish_extractor.dart b/lib/services/anime_extractors/streamwish_extractor.dart index 32e31ae..314d4ec 100644 --- a/lib/services/anime_extractors/streamwish_extractor.dart +++ b/lib/services/anime_extractors/streamwish_extractor.dart @@ -1,7 +1,7 @@ import 'package:http_interceptor/http_interceptor.dart'; -import 'package:js_packer/js_packer.dart'; import 'package:mangayomi/models/video.dart'; import 'package:mangayomi/services/http/interceptor.dart'; +import 'package:mangayomi/utils/cryptoaes/js_unpacker.dart'; import 'package:mangayomi/utils/extensions/others.dart'; import 'package:mangayomi/utils/extensions/string_extensions.dart'; import 'package:mangayomi/utils/xpath_selector.dart'; @@ -26,7 +26,7 @@ class StreamWishExtractor { .let( (script) { if (script.contains("function(p,a,c")) { - return JSPacker(script).unpack() ?? ""; + return JsUnpacker.unpackAndCombine(script) ?? ""; } return script; }, diff --git a/lib/utils/cryptoaes/js_unpacker.dart b/lib/utils/cryptoaes/js_unpacker.dart new file mode 100644 index 0000000..4ea52f6 --- /dev/null +++ b/lib/utils/cryptoaes/js_unpacker.dart @@ -0,0 +1,85 @@ +import 'dart:math'; + +class JsUnpacker { + static final RegExp _packedRegex = RegExp( + r"eval[(]function[(]p,a,c,k,e,[r|d]?", + caseSensitive: false, + multiLine: true); + + static final RegExp _packedExtractRegex = RegExp( + r"[}][(]'(.*)', *(\d+), *(\d+), *'(.*?)'[.]split[(]'[|]'[)]", + caseSensitive: false, + multiLine: true); + + static final RegExp _unpackReplaceRegex = + RegExp(r"\b\w+\b", caseSensitive: false, multiLine: true); + + static bool detect(String scriptBlock) { + return _packedRegex.hasMatch(scriptBlock); + } + + static List detectMultiple(List scriptBlocks) { + return scriptBlocks.where(detect).toList(); + } + + static List unpack(String scriptBlock) { + return detect(scriptBlock) ? _unpacking(scriptBlock).toList() : []; + } + + static String? unpackAndCombine(String scriptBlock) { + final unpacked = unpack(scriptBlock); + return unpacked.isEmpty ? null : unpacked.join(' '); + } + + static Iterable _unpacking(String scriptBlock) sync* { + final matches = _packedExtractRegex.allMatches(scriptBlock); + for (final match in matches) { + final payload = match.group(1); + final symtab = match.group(4)?.split('|'); + final radix = int.tryParse(match.group(2)!) ?? 10; + final count = int.tryParse(match.group(3)!) ?? 0; + final unbaser = Unbaser(radix); + + if (symtab != null && symtab.length == count) { + final unpackedPayload = + payload!.replaceAllMapped(_unpackReplaceRegex, (match) { + final word = match.group(0)!; + final unbased = symtab[unbaser.unbase(word)]; + return unbased.isEmpty ? word : unbased; + }); + yield unpackedPayload; + } + } + } +} + +class Unbaser { + final int base; + static const Map _alphabet = { + 52: "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOP", + 54: "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQR", + 62: "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", + 95: " !\"#\$%&\\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" + }; + + Unbaser(this.base); + + int unbase(String value) { + if (base >= 2 && base <= 36) { + return int.tryParse(value, radix: base) ?? 0; + } else { + final dict = _alphabet[base] + ?.split('') + .asMap() + .map((index, c) => MapEntry(c, index)); + var returnVal = 0; + + final valArray = value.runes.toList().reversed.toList(); + for (var i = 0; i < valArray.length; i++) { + final cipher = String.fromCharCode(valArray[i]); + returnVal += pow(base, i).toInt() * (dict?[cipher] ?? 0).toInt(); + } + return returnVal; + } + } +} \ No newline at end of file diff --git a/pubspec.lock b/pubspec.lock index b84ed22..09095d0 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -734,14 +734,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.6.7" - js_packer: - dependency: "direct main" - description: - name: js_packer - sha256: f45ffa90165a810d7134f0b96b54068e4aac9d80a8b181eafa3978ec6dbc66a3 - url: "https://pub.dev" - source: hosted - version: "0.0.5" json_annotation: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 1b4740a..981ebd6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -51,7 +51,6 @@ dependencies: flutter_web_auth_2: ^3.1.1 numberpicker: ^2.1.2 encrypt: ^5.0.3 - js_packer: ^0.0.5 media_kit: ^1.1.10+1 media_kit_video: git: