code refactor, added sources languages

This commit is contained in:
kodjomoustapha 2023-09-12 16:31:49 +01:00
parent 499002751c
commit 385677f67d
15 changed files with 169 additions and 87 deletions

View file

@ -43,6 +43,7 @@ import 'package:mangayomi/utils/xpath_selector.dart';
import 'package:xpath_selector_html_parser/xpath_selector_html_parser.dart';
import 'package:html/parser.dart' as parser;
import 'package:http/http.dart' as hp;
import 'package:encrypt/encrypt.dart' as encrypt;
class WordSet {
final List<String> words;
@ -981,6 +982,19 @@ class MBridge {
return type == 0 ? value.isEmpty : value.isNotEmpty;
}
static String cryptoHandler(
String text, String iv, String secretKeyString, bool encrypt) {
if (encrypt) {
final encryptt = _encrypt(secretKeyString, iv);
final en = encryptt.$1.encrypt(text, iv: encryptt.$2);
return en.base64;
} else {
final encryptt = _encrypt(secretKeyString, iv);
final en = encryptt.$1.decrypt64(text, iv: encryptt.$2);
return en;
}
}
}
final List<String> _dateFormats = [
@ -1050,6 +1064,34 @@ class $MBridge extends MBridge with $Bridge {
],
namedParams: []),
isStatic: true),
'cryptoHandler': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.stringType)),
params: [
BridgeParameter(
'text',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.stringType)),
false),
BridgeParameter(
'iv',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.stringType)),
false),
BridgeParameter(
'secretKeyString',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.stringType)),
false),
BridgeParameter(
'encrypt',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.boolType)),
false),
],
namedParams: []),
isStatic: true),
'encryptAESCryptoJS': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(
@ -1997,6 +2039,11 @@ class $MBridge extends MBridge with $Bridge {
static $String $bAse64(Runtime runtime, $Value? target, List<$Value?> args) =>
$String(MBridge.bAse64(args[0]!.$value, args[1]!.$value));
static $String $cryptoHandler(
Runtime runtime, $Value? target, List<$Value?> args) =>
$String(MBridge.cryptoHandler(
args[0]!.$value, args[1]!.$value, args[2]!.$value, args[3]!.$value));
static $String $encryptAESCryptoJS(
Runtime runtime, $Value? target, List<$Value?> args) =>
$String(MBridge.encryptAESCryptoJS(args[0]!.$value, args[1]!.$value));
@ -2212,3 +2259,11 @@ $VideoModel _toVideoModel(Video e) => $VideoModel.wrap(VideoModel()
..file = t.file
..label = t.label))
.toList()));
(encrypt.Encrypter, encrypt.IV) _encrypt(String keyy, String ivv) {
final key = encrypt.Key.fromUtf8(keyy);
final iv = encrypt.IV.fromUtf8(ivv);
final encrypter = encrypt.Encrypter(
encrypt.AES(key, mode: encrypt.AESMode.cbc, padding: 'PKCS7'));
return (encrypter, iv);
}

View file

@ -103,6 +103,8 @@ Runtime runtimeEval(Uint8List bytecode) {
'MBridge.deobfuscateJsPassword', $MBridge.$deobfuscateJsPassword);
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
'MBridge.querySelectorAll', $MBridge.$querySelectorAll);
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
'MBridge.cryptoHandler', $MBridge.$cryptoHandler);
runtime.setup();
return runtime;
}

View file

@ -225,5 +225,6 @@
"white":"White",
"black":"Black",
"grey":"Grey",
"automaic":"Automatic"
"automaic":"Automatic",
"preferred_domain":"Preferred Domain"
}

View file

@ -225,5 +225,6 @@
"white":"Blanc",
"black":"Noir",
"grey":"Gris",
"automaic":"Automatique"
"automaic":"Automatique",
"preferred_domain":"Domaine préféré"
}

View file

@ -187,7 +187,7 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
builder: (context) {
return AlertDialog(
title: Text(
l10n.relative_timestamp,
l10n.preferred_domain,
),
content: SizedBox(
width: mediaWidth(context, 0.8),
@ -246,7 +246,7 @@ class _ExtensionDetailState extends ConsumerState<ExtensionDetail> {
);
});
},
title: Text(l10n.relative_timestamp),
title: Text(l10n.preferred_domain),
subtitle: Text(
widget.source.baseUrl!,
style: TextStyle(

View file

@ -4,7 +4,6 @@ import 'package:isar/isar.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/providers/l10n_providers.dart';
import 'package:mangayomi/utils/language.dart';
import 'package:mangayomi/modules/browse/extension/widgets/extension_lang_list_tile_widget.dart';
class ExtensionsLang extends ConsumerWidget {
@ -14,8 +13,6 @@ class ExtensionsLang extends ConsumerWidget {
@override
Widget build(BuildContext context, WidgetRef ref) {
final l10n = l10nLocalizations(context)!;
final languages = languagesMap.entries.map((e) => e.value).toList();
languages.sort((a, b) => a.compareTo(b));
return Scaffold(
appBar: AppBar(
title: Text(l10n.extensions),
@ -29,6 +26,9 @@ class ExtensionsLang extends ConsumerWidget {
.watch(fireImmediately: true),
builder: (context, snapshot) {
List<Source>? entries = snapshot.hasData ? snapshot.data : [];
final languages = entries!.map((e) => e.lang!).toSet().toList();
languages.sort((a, b) => a.compareTo(b));
return ListView.builder(
itemCount: languages.length,
itemBuilder: (context, index) {
@ -44,7 +44,7 @@ class ExtensionsLang extends ConsumerWidget {
}
});
},
value: entries!
value: entries
.where((element) =>
element.lang!.toLowerCase() == lang.toLowerCase() &&
element.isActive!)

View file

@ -1,3 +1,4 @@
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:grouped_list/grouped_list.dart';
@ -83,7 +84,23 @@ class SourcesFilterScreen extends ConsumerWidget {
.secondaryHeaderColor
.withOpacity(0.5),
borderRadius: BorderRadius.circular(5)),
child: const Icon(Icons.source_outlined),
child: element.iconUrl!.isEmpty
? const Icon(Icons.source_outlined)
: CachedNetworkImage(
imageUrl: element.iconUrl!,
fit: BoxFit.contain,
width: 37,
height: 37,
errorWidget: (context, url, error) {
return const SizedBox(
width: 37,
height: 37,
child: Center(
child: Icon(Icons.source_outlined),
),
);
},
),
),
onChanged: (bool? value) {
isar.writeTxnSync(() {

View file

@ -1401,10 +1401,10 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
onPressed: () {
final manga = widget.manga!;
final source =
getSource(widget.manga!.lang!, widget.manga!.source!);
String url = source!.apiUrl!.isEmpty
? widget.manga!.link!
: "${source.baseUrl}${widget.manga!.link!}";
getSource(widget.manga!.lang!, widget.manga!.source!)!;
String url = widget.manga!.link!.startsWith('/')
? "${source.baseUrl}${widget.manga!.link!}"
: widget.manga!.link!;
Map<String, String> data = {
'url': url,

View file

@ -376,6 +376,9 @@ class _MangaChapterPageGalleryState
final double _imageDetailY = 0;
void _onBtnTapped(int index, bool isPrev, {bool isSlide = false}) {
if (_isView) {
_isViewFunction();
}
final readerMode = ref.watch(_selectedValue);
final animatePageTransitions =
ref.watch(animatePageTransitionsStateProvider);
@ -637,10 +640,10 @@ class _MangaChapterPageGalleryState
IconButton(
onPressed: () {
final manga = chapter.manga.value!;
final source = getSource(manga.lang!, manga.source!);
String url = source!.apiUrl!.isEmpty
? chapter.url!
: "${source.baseUrl}/${chapter.url!}";
final source = getSource(manga.lang!, manga.source!)!;
String url = chapter.url!.startsWith('/')
? "${source.baseUrl}/${chapter.url!}"
: chapter.url!;
Map<String, String> data = {
'url': url,
'sourceId': source.id.toString(),

View file

@ -1,5 +1,5 @@
import 'package:http/http.dart' as http;
import 'package:js_packer/js_packer.dart';
import 'package:mangayomi/eval/m_bridge.dart';
import 'package:mangayomi/models/video.dart';
import 'package:mangayomi/utils/extensions.dart';
import 'package:mangayomi/utils/xpath_selector.dart';
@ -16,7 +16,7 @@ class FilemoonExtractor {
.queryXPath('//script[contains(text(), "eval")]/text()')
.attr;
final unpacked = _evalJs(jsEval!) ?? '';
final unpacked = MBridge.evalJs(jsEval!);
final masterUrl = unpacked.isNotEmpty
? unpacked.substringAfter('{file:"').substringBefore('"}')
@ -54,8 +54,3 @@ class FilemoonExtractor {
}
}
}
String? _evalJs(String script) {
final jsPacker = JSPacker(script);
return jsPacker.unpack();
}

View file

@ -1,10 +1,8 @@
import 'dart:convert';
import 'package:encrypt/encrypt.dart';
import 'package:flutter/services.dart';
import 'package:html/dom.dart';
import 'package:http/http.dart' as http;
import 'package:mangayomi/eval/m_bridge.dart';
import 'package:mangayomi/models/video.dart';
import 'package:encrypt/encrypt.dart' as encrypt;
import 'package:html/parser.dart' as parser;
import 'package:mangayomi/utils/extensions.dart';
@ -32,21 +30,17 @@ class GogoCdnExtractor {
RegExp(r'container-(\d+)').firstMatch(document)?.group(1);
final decryptionKey =
RegExp(r'videocontent-(\d+)').firstMatch(document)?.group(1);
final encryptAjaxParams = _cryptoHandler(
final encryptAjaxParams = MBridge.cryptoHandler(
RegExp(r'data-value="([^"]+)').firstMatch(document)?.group(1) ?? "",
Uint8List.fromList(iv.codeUnits),
Uint8List.fromList(secretKey.codeUnits),
encrypt: false,
iv,
secretKey,
false,
).substringAfter("&");
final httpUrl = Uri.parse(serverUrl);
final host = "https://${httpUrl.host}/";
final id = httpUrl.queryParameters['id'];
final encryptedId = _cryptoHandler(
id ?? "",
Uint8List.fromList(iv.codeUnits),
Uint8List.fromList(secretKey.codeUnits),
);
final encryptedId = MBridge.cryptoHandler(id ?? "", iv, secretKey, true);
final token = httpUrl.queryParameters['token'];
final qualityPrefix = token != null ? "Gogostream - " : "Vidstreaming - ";
@ -58,11 +52,8 @@ class GogoCdnExtractor {
headers: {"X-Requested-With": "XMLHttpRequest"});
final jsonResponse = encryptAjaxResponse.body;
final data = json.decode(jsonResponse)["data"];
final decryptedData = _cryptoHandler(
data ?? "",
Uint8List.fromList(iv.codeUnits),
Uint8List.fromList(decryptionKey!.codeUnits),
encrypt: false);
final decryptedData =
MBridge.cryptoHandler(data ?? "", iv, decryptionKey!, false);
final videoList = <Video>[];
final autoList = <Video>[];
final array = json.decode(decryptedData)["source"];
@ -111,31 +102,4 @@ class GogoCdnExtractor {
return [];
}
}
String _cryptoHandler(
String string,
Uint8List iv,
Uint8List secretKeyString, {
bool encrypt = true,
}) {
if (encrypt) {
final encryptt = _encrypt(
String.fromCharCodes(secretKeyString), String.fromCharCodes(iv));
final aa = encryptt.$1.encrypt(string, iv: encryptt.$2);
return aa.base64;
} else {
final encryptt = _encrypt(
String.fromCharCodes(secretKeyString), String.fromCharCodes(iv));
final aa = encryptt.$1.decrypt64(string, iv: encryptt.$2);
return aa;
}
}
}
(encrypt.Encrypter, encrypt.IV) _encrypt(String keyy, String ivv) {
final key = encrypt.Key.fromUtf8(keyy);
final iv = encrypt.IV.fromUtf8(ivv);
final encrypter =
encrypt.Encrypter(encrypt.AES(key, mode: AESMode.cbc, padding: 'PKCS7'));
return (encrypter, iv);
}

View file

@ -1,5 +1,5 @@
import 'package:http/http.dart' as http;
import 'package:js_packer/js_packer.dart';
import 'package:mangayomi/eval/m_bridge.dart';
import 'package:mangayomi/models/video.dart';
import 'package:mangayomi/utils/extensions.dart';
import 'package:mangayomi/utils/xpath_selector.dart';
@ -22,7 +22,7 @@ class Mp4uploadExtractor {
.attrs;
if (scriptElementWithEval.isNotEmpty) {
script = _evalJs(script)!;
script = MBridge.evalJs(script);
} else {
final scriptElementWithSrc = xpathSelector(response.body)
.queryXPath('//script[contains(text(), "player.src")]/text()')
@ -52,8 +52,3 @@ class Mp4uploadExtractor {
}
}
}
String? _evalJs(String script) {
final jsPacker = JSPacker(script);
return jsPacker.unpack();
}

View file

@ -1,5 +1,5 @@
import 'package:js_packer/js_packer.dart';
import 'package:http/http.dart' as http;
import 'package:mangayomi/eval/m_bridge.dart';
import 'package:mangayomi/models/video.dart';
import 'package:mangayomi/utils/extensions.dart';
import 'package:mangayomi/utils/xpath_selector.dart';
@ -20,12 +20,12 @@ class StreamWishExtractor {
return [];
}
String? masterUrl = _evalJs(jsEval.first!)
?.substringAfter('source')
String? masterUrl = MBridge.evalJs(jsEval.first!)
.substringAfter('source')
.substringAfter('file:"')
.substringBefore('"');
if (masterUrl == null) return [];
if (masterUrl.isEmpty) return [];
final playlistHeaders = Map<String, String>.from(headers)
..addAll({
@ -58,8 +58,3 @@ class StreamWishExtractor {
}
}
}
String? _evalJs(String script) {
final jsPacker = JSPacker(script);
return jsPacker.unpack();
}

View file

@ -8,13 +8,13 @@ class CryptoAES {
static String encryptAESCryptoJS(String plainText, String passphrase) {
try {
final salt = genRandomWithNonZero(8);
var keyndIV = deriveKeyAndIV(passphrase, salt);
var keyndIV = deriveKeyAndIV(passphrase.trim(), salt);
final key = encrypt.Key(keyndIV.$1);
final iv = encrypt.IV(keyndIV.$2);
final encrypter = encrypt.Encrypter(
encrypt.AES(key, mode: encrypt.AESMode.cbc, padding: "PKCS7"));
final encrypted = encrypter.encrypt(plainText, iv: iv);
final encrypted = encrypter.encrypt(plainText.trim(), iv: iv);
Uint8List encryptedBytesWithSalt = Uint8List.fromList(
createUint8ListFromString("Salted__") + salt + encrypted.bytes);
return base64.encode(encryptedBytesWithSalt);
@ -30,7 +30,7 @@ class CryptoAES {
Uint8List encryptedBytes =
encryptedBytesWithSalt.sublist(16, encryptedBytesWithSalt.length);
final salt = encryptedBytesWithSalt.sublist(8, 16);
var keyndIV = deriveKeyAndIV(passphrase, salt);
var keyndIV = deriveKeyAndIV(passphrase.trim(), salt);
final key = encrypt.Key(keyndIV.$1);
final iv = encrypt.IV(keyndIV.$2);

View file

@ -64,4 +64,58 @@ final languagesMap = {
"čeština": "cs",
"Kurdî": "ku",
"Magyar": "hu",
"Cebuano": "ceb",
"English (United States)": "en-us",
"Esperanto": "eo",
"Estonian": "et",
"Faroese": "fo",
"Irish": "ga",
"Guarani": "gn",
"Gujarati": "gu",
"Hausa": "ha",
"Haitian Creole": "ht",
"Armenian": "hy",
"Igbo": "ig",
"Icelandic": "is",
"Georgian": "ka",
"Javanese": "jv",
"Kazakh": "kk",
"Cambodian": "km",
"Kannada": "kn",
"Kyrgyz": "ky",
"Luxembourgish": "lb",
"Laothian": "lo",
"Latvian": "lv",
"Malagasy": "mg",
"Maori": "mi",
"Macedonian": "mk",
"Marathi": "mr",
"Maltese": "mt",
"Nepali": "ne",
"Nyanja": "ny",
"Pashto": "ps",
"Portuguese (Portugal)": "pt-pt",
"Romansh": "rm",
"Sindhi": "sd",
"Sinhalese": "si",
"Slovak": "sk",
"Slovenian": "sl",
"Samoan": "sm",
"Shona": "sn",
"Somali": "so",
"Albanian": "sq",
"Serbian": "sr",
"Sesotho": "st",
"Swahili": "sw",
"Tamil": "ta",
"Tajik": "tg",
"Tigrinya": "ti",
"Turkmen": "tk",
"Tonga": "to",
"Urdu": "ur",
"Yoruba": "yo",
"Chinese (Traditional)": "zh-tw",
"Latin": "la",
"Uzbek": "uz",
"Tagalog": "tl"
};