added new anime servers extractors

This commit is contained in:
kodjomoustapha 2023-07-30 03:02:09 +01:00
parent 6abbfda911
commit c230dd88da
19 changed files with 444 additions and 37 deletions

View file

@ -70,7 +70,7 @@ class VideoModel {
String? url;
String? quality;
String? originalUrl;
Map<dynamic, dynamic>? headers;
Map<String, String>? headers;
VideoModel({this.url, this.quality, this.originalUrl, this.headers});
}

View file

@ -93,7 +93,7 @@ class $VideoModel implements VideoModel, $Instance {
case 'originalUrl':
$value.originalUrl = value.$reified;
case 'headers':
$value.headers = value.$reified as Map;
$value.headers = value.$reified as Map<String, String>;
default:
_superclass.$setProperty(runtime, identifier, value);
@ -107,7 +107,7 @@ class $VideoModel implements VideoModel, $Instance {
String? get quality => $value.quality;
@override
Map? get headers => $value.headers;
Map<String, String>? get headers => $value.headers;
@override
String? get originalUrl => $value.originalUrl;

View file

@ -15,12 +15,15 @@ import 'package:mangayomi/eval/bridge_class/model.dart';
import 'package:mangayomi/eval/bridge_class/video_model.dart';
import 'package:mangayomi/services/anime_extractors/dood_extractor.dart';
import 'package:mangayomi/services/anime_extractors/gogo_cdn_extractor.dart';
import 'package:mangayomi/services/anime_extractors/mp4_upload_extractor.dart';
import 'package:mangayomi/services/anime_extractors/my_tv_extractor.dart';
import 'package:mangayomi/services/anime_extractors/send_vid_extractor.dart';
import 'package:mangayomi/services/anime_extractors/sibnet_extractor.dart';
import 'package:mangayomi/services/anime_extractors/stream_tape_extractor.dart';
import 'package:mangayomi/main.dart';
import 'package:mangayomi/models/source.dart';
import 'package:mangayomi/models/video.dart';
import 'package:mangayomi/modules/webview/webview.dart';
import 'package:mangayomi/services/anime_extractors/mp4_upload_extractor.dart';
import 'package:mangayomi/services/anime_extractors/stream_tape_extractor.dart';
import 'package:mangayomi/services/http_service/cloudflare/cloudflare_bypass.dart';
import 'package:mangayomi/utils/constant.dart';
import 'package:mangayomi/utils/reg_exp_matcher.dart';
@ -188,6 +191,8 @@ class MBridge {
return [val.last];
} else if (type == 4) {
return val.where((element) => element.toString().isNotEmpty).toList();
} else if (type == 5) {
return val.reversed.toList();
}
return val;
}
@ -288,8 +293,10 @@ class MBridge {
return html!;
}
static List<dynamic> jsonDecodeToList(String source) {
return jsonDecode(source) as List;
static List<dynamic> jsonDecodeToList(String source, int type) {
return type == 0
? jsonDecode(source) as List
: (jsonDecode(source) as List).map((e) => jsonEncode(e)).toList();
}
static String evalJs(String code) {
@ -305,7 +312,8 @@ class MBridge {
}
}
static List<String> jsonPathToList(String source, String expression) {
static List<String> jsonPathToList(
String source, String expression, int type) {
try {
if (jsonDecode(source) is List) {
List<dynamic> values = [];
@ -321,7 +329,13 @@ class MBridge {
List<String> list = [];
for (var data in values) {
final jsonRes = JsonPath(expression).read(data);
list.add(jsonRes.first.value.toString());
String val = "";
if (type == 0) {
val = jsonRes.first.value.toString();
} else {
val = jsonEncode(jsonRes.first.value);
}
list.add(val);
}
return list;
} else {
@ -518,10 +532,15 @@ class MBridge {
);
}
static Future<List<Video>> mp4UploadExtractor(String url,
Map<String, String>? headers, String prefix, String suffix) async {
static Future<List<Video>> mp4UploadExtractor(
String url, String? headers, String prefix, String suffix) async {
Map<String, String> newHeaders = {};
if (headers != null) {
newHeaders = (jsonDecode(headers) as Map)
.map((key, value) => MapEntry(key.toString(), value.toString()));
}
return await Mp4uploadExtractor()
.videosFromUrl(url, headers ?? {}, prefix: prefix, suffix: suffix);
.videosFromUrl(url, newHeaders, prefix: prefix, suffix: suffix);
}
static Future<List<Video>> streamTapeExtractor(String url) async {
@ -681,6 +700,51 @@ class MBridge {
throw Exception(e);
}
}
static Future<List<Video>> sibnetExtractor(String url) async {
return await SibnetExtractor().videosFromUrl(
url,
);
}
static Future<List<Video>> sendVidExtractor(
String url, String? headers, String prefix) async {
Map<String, String> newHeaders = {};
if (headers != null) {
newHeaders = (jsonDecode(headers) as Map)
.map((key, value) => MapEntry(key.toString(), value.toString()));
}
return await SendvidExtractor(newHeaders)
.videosFromUrl(url, prefix: prefix);
}
static Future<List<Video>> myTvExtractor(String url) async {
return await MytvExtractor().videosFromUrl(
url,
);
}
static List<Video> toVideos(
String url, String quality, String originalUrl, String? headers) {
Map<String, String> newHeaders = {};
if (headers != null) {
newHeaders = (jsonDecode(headers) as Map)
.map((key, value) => MapEntry(key.toString(), value.toString()));
}
return [Video(url, quality, originalUrl, headers: newHeaders)];
}
static bool isEmptyOrIsNotEmpty(dynamic value, int type) {
if (value is List) {
return type == 0 ? value.isEmpty : value.isNotEmpty;
}
if (value is String) {
return type == 0 ? value.isEmpty : value.isNotEmpty;
}
return type == 0 ? value.isEmpty : value.isNotEmpty;
}
}
final List<String> _dateFormats = [
@ -732,6 +796,74 @@ class $MBridge extends MBridge with $Bridge {
returns: BridgeTypeAnnotation($type), params: [], namedParams: []))
},
methods: {
'isEmptyOrIsNotEmpty': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.boolType)),
params: [
BridgeParameter(
'value',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.dynamicType)),
false),
BridgeParameter(
'type',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.intType)),
false),
],
namedParams: []),
isStatic: true),
'sibnetExtractor': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future,
[BridgeTypeRef.type(RuntimeTypes.dynamicType)])),
params: [
BridgeParameter(
'url',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.stringType)),
false),
],
namedParams: []),
isStatic: true),
'myTvExtractor': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future,
[BridgeTypeRef.type(RuntimeTypes.dynamicType)])),
params: [
BridgeParameter(
'url',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.stringType)),
false),
],
namedParams: []),
isStatic: true),
'sendVidExtractor': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.future,
[BridgeTypeRef.type(RuntimeTypes.dynamicType)])),
params: [
BridgeParameter(
'url',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.stringType)),
false),
BridgeParameter(
'headers',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.stringType),
nullable: true),
false),
BridgeParameter(
'prefix',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.stringType)),
false),
],
namedParams: []),
isStatic: true),
'subString': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(
@ -773,6 +905,35 @@ class $MBridge extends MBridge with $Bridge {
],
namedParams: []),
isStatic: true),
'toVideos': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(BridgeTypeRef(CoreTypes.list,
[BridgeTypeRef.type(RuntimeTypes.dynamicType)])),
params: [
BridgeParameter(
'url',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.stringType)),
false),
BridgeParameter(
'quality',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.stringType)),
false),
BridgeParameter(
'originalUrl',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.stringType)),
false),
BridgeParameter(
'headers',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.stringType),
nullable: true),
true),
],
namedParams: []),
isStatic: true),
'jsonPathToString': BridgeMethodDef(
BridgeFunctionDef(
returns: BridgeTypeAnnotation(
@ -834,6 +995,11 @@ class $MBridge extends MBridge with $Bridge {
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.stringType)),
false),
BridgeParameter(
'type',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.intType)),
false),
],
namedParams: []),
isStatic: true),
@ -847,6 +1013,11 @@ class $MBridge extends MBridge with $Bridge {
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.stringType)),
false),
BridgeParameter(
'type',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.intType)),
false),
],
namedParams: []),
isStatic: true),
@ -1109,7 +1280,7 @@ class $MBridge extends MBridge with $Bridge {
BridgeParameter(
'headers',
BridgeTypeAnnotation(
BridgeTypeRef.type(RuntimeTypes.mapType),
BridgeTypeRef.type(RuntimeTypes.stringType),
nullable: true),
false),
BridgeParameter(
@ -1268,6 +1439,19 @@ class $MBridge extends MBridge with $Bridge {
.toList());
}
static $List $toVideos(Runtime runtime, $Value? target, List<$Value?> args) {
final value = MBridge.toVideos(
args[0]!.$value, args[1]!.$value, args[2]!.$value, args[3]!.$value);
return $List.wrap(value
.map((e) => $VideoModel.wrap(VideoModel()
..headers = e.headers
..originalUrl = e.originalUrl
..quality = e.quality
..url = e.url))
.toList());
}
static $String $jsonPathToString(
Runtime runtime, $Value? target, List<$Value?> args) {
return $String(MBridge.jsonPathToString(
@ -1300,6 +1484,7 @@ class $MBridge extends MBridge with $Bridge {
return $List.wrap(MBridge.jsonPathToList(
args[0]!.$value,
args[1]!.$value,
args[2]!.$value,
).map((e) => $String(e)).toList());
}
@ -1307,6 +1492,7 @@ class $MBridge extends MBridge with $Bridge {
Runtime runtime, $Value? target, List<$Value?> args) {
return $List.wrap(MBridge.jsonDecodeToList(
args[0]!.$value,
args[1]!.$value,
).map((e) => $String(e.toString())).toList());
}
@ -1327,7 +1513,7 @@ class $MBridge extends MBridge with $Bridge {
static $Instance $stringParseValue(
Runtime runtime, $Value? target, List<$Value?> args) =>
$String(MBridge.stringParseValue(
args[0]!.$value,
args[0]!.$value.toString(),
));
static $String $regExp(Runtime runtime, $Value? target, List<$Value?> args) =>
$String(MBridge.regExp(
@ -1414,6 +1600,45 @@ class $MBridge extends MBridge with $Bridge {
..quality = e.quality
..url = e.url))
.toList())));
static $Future $sendVidExtractor(
Runtime runtime, $Value? target, List<$Value?> args) =>
$Future.wrap(MBridge.sendVidExtractor(
args[0]!.$value, args[1]!.$value, args[2]!.$value)
.then((value) => $List.wrap(value
.map((e) => $VideoModel.wrap(VideoModel()
..headers = e.headers
..originalUrl = e.originalUrl
..quality = e.quality
..url = e.url))
.toList())));
static $Future $sibnetExtractor(
Runtime runtime, $Value? target, List<$Value?> args) =>
$Future.wrap(MBridge.sibnetExtractor(args[0]!.$value)
.then((value) => $List.wrap(value
.map((e) => $VideoModel.wrap(VideoModel()
..headers = e.headers
..originalUrl = e.originalUrl
..quality = e.quality
..url = e.url))
.toList())));
static $Future $myTvExtractor(
Runtime runtime, $Value? target, List<$Value?> args) =>
$Future.wrap(MBridge.myTvExtractor(args[0]!.$value)
.then((value) => $List.wrap(value
.map((e) => $VideoModel.wrap(VideoModel()
..headers = e.headers
..originalUrl = e.originalUrl
..quality = e.quality
..url = e.url))
.toList())));
static $bool $isEmptyOrIsNotEmpty(
Runtime runtime, $Value? target, List<$Value?> args) {
return $bool(MBridge.isEmptyOrIsNotEmpty(
args[0]!.$value,
args[1]!.$value,
));
}
@override
$Value? $bridgeGet(String identifier) {
throw UnimplementedError();

View file

@ -26,8 +26,18 @@ Runtime runtimeEval(Uint8List bytecode) {
'MBridge.streamTapeExtractor', $MBridge.$streamTapeExtractor);
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
'MBridge.mp4UploadExtractor', $MBridge.$mp4UploadExtractor);
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
'MBridge.myTvExtractor', $MBridge.$myTvExtractor);
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
'MBridge.sendVidExtractor', $MBridge.$sendVidExtractor);
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
'MBridge.sibnetExtractor', $MBridge.$sibnetExtractor);
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
'MBridge.jsonPathToString', $MBridge.$jsonPathToString);
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
'MBridge.toVideos', $MBridge.$toVideos);
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
'MBridge.isEmptyOrIsNotEmpty', $MBridge.$isEmptyOrIsNotEmpty);
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',
'MBridge.jsonPathToList', $MBridge.$jsonPathToList);
runtime.registerBridgeFunc('package:bridge_lib/bridge_lib.dart',

View file

@ -184,8 +184,8 @@
"description": "Description",
"episode_progress": "Progression: {n}",
"n_episodes": "{n} épisodes",
"manga_sources":"Sources d'animés",
"anime_sources":"Sources des mangas",
"manga_sources":"Sources des mangas",
"anime_sources":"Sources d'animés",
"anime_extensions":"Extensions d'animés",
"manga_extensions":"Extensions des mangas",
"anime":"Animé",

View file

@ -42,7 +42,8 @@ Future fetchAnimeSourcesList(FetchAnimeSourcesListRef ref, {int? id}) async {
..name = source.name
..version = source.version
..versionLast = source.version
..isManga = source.isManga);
..isManga = source.isManga
..isFullData = source.isFullData);
});
// log("successfully installed");
}
@ -97,7 +98,8 @@ Future fetchAnimeSourcesList(FetchAnimeSourcesListRef ref, {int? id}) async {
..name = source.name
..version = source.version
..versionLast = source.version
..isManga = source.isManga);
..isManga = source.isManga
..isFullData = source.isFullData);
// log("new source");
}
}

View file

@ -44,7 +44,8 @@ Future fetchMangaSourcesList(FetchMangaSourcesListRef ref, {int? id}) async {
..name = source.name
..version = source.version
..versionLast = source.version
..isManga = source.isManga);
..isManga = source.isManga
..isFullData = source.isFullData);
});
// log("successfully installed");
}
@ -99,7 +100,8 @@ Future fetchMangaSourcesList(FetchMangaSourcesListRef ref, {int? id}) async {
..name = source.name
..version = source.version
..versionLast = source.version
..isManga = source.isManga);
..isManga = source.isManga
..isFullData = source.isFullData);
// log("new source");
}
}

View file

@ -18,6 +18,17 @@ Future<dynamic> updateMangaDetail(UpdateMangaDetailRef ref,
final mangaS = MangaModel(
name: manga.name,
link: manga.link,
genre: manga.genre,
author: manga.author,
status: switch (manga.status) {
Status.ongoing => 0,
Status.completed => 1,
Status.onHiatus => 2,
Status.canceled => 3,
Status.publishingFinished => 4,
_ => 5,
},
description: manga.description,
imageUrl: manga.imageUrl,
baseUrl: source.baseUrl,
apiUrl: source.apiUrl,

View file

@ -386,7 +386,7 @@ class _MangaHomeScreenState extends ConsumerState<MangaHomeScreen> {
controller: _scrollController,
itemCount: _length,
itemBuilder: (context, index) {
if (index == _length - 1) {
if (index == _length - 1 && _isLoading) {
return buildProgressIndicator();
}
return MangaHomeImageCard(

View file

@ -7,7 +7,7 @@ pushMangaReaderView({
required Chapter chapter,
}) {
if (chapter.manga.value!.isManga!) {
context.pushReplacement('/mangareaderview', extra: chapter);
context.push('/mangareaderview', extra: chapter);
} else {
context.push('/animestreamview', extra: chapter);
}
@ -17,5 +17,9 @@ pushReplacementMangaReaderView({
required BuildContext context,
required Chapter chapter,
}) {
context.pushReplacement('/mangareaderview', extra: chapter);
if (chapter.manga.value!.isManga!) {
context.pushReplacement('/mangareaderview', extra: chapter);
} else {
context.pushReplacement('/animestreamview', extra: chapter);
}
}

View file

@ -112,10 +112,21 @@ void pushToMangaReaderDetail(
Manga(
imageUrl: getManga!.imageUrl,
name: getManga.name!.trim().trimLeft().trimRight(),
genre: [],
author: "",
status: Status.unknown,
description: "",
genre: getManga.genre == null
? []
: getManga.genre!.map((e) => e.toString()).toList(),
author: getManga.author ?? "",
status: getManga.status == null
? Status.unknown
: switch (getManga.status) {
0 => Status.ongoing,
1 => Status.completed,
2 => Status.onHiatus,
3 => Status.canceled,
4 => Status.publishingFinished,
_ => Status.unknown,
},
description: getManga.description ?? "",
link: getManga.link,
source: getManga.source,
lang: lang,

View file

@ -0,0 +1,36 @@
import 'package:http/http.dart' as http;
import 'package:html/parser.dart' show parse;
import 'package:mangayomi/models/video.dart';
import 'package:mangayomi/utils/extensions.dart';
class MytvExtractor {
final http.Client client = http.Client();
Future<List<Video>> videosFromUrl(String url) async {
final response = await client.get(Uri.parse(url));
final document = parse(response.body);
final videoList = <Video>[];
document.querySelectorAll("script").forEach((script) {
if (script.text.contains("CreatePlayer(\"v")) {
final videosString = script.text;
final videoUrl = videosString
.substringAfter("\"v=")
.substringBefore("\\u0026tp=video")
.replaceAll("%26", "&")
.replaceAll("%3a", ":")
.replaceAll("%2f", "/")
.replaceAll("%3f", "?")
.replaceAll("%3d", "=");
if (!videoUrl.contains("https:")) {
videoList.add(Video(videoUrl, "Stream", videoUrl));
} else {
videoList.add(Video(videoUrl, "Mytv", videoUrl));
}
}
});
return videoList;
}
}

View file

@ -0,0 +1,61 @@
import 'package:http/http.dart' as http;
import 'package:html/parser.dart' as parser;
import 'package:mangayomi/models/video.dart';
import 'package:mangayomi/utils/extensions.dart';
class SendvidExtractor {
final http.Client client = http.Client();
final Map<String, String> headers;
SendvidExtractor(this.headers);
Future<List<Video>> videosFromUrl(String url, {String prefix = ""}) async {
final videoList = <Video>[];
final response = await client.get(Uri.parse(url));
final document = parser.parse(response.body);
final masterUrl =
document.querySelector("source#video_source")?.attributes["src"];
if (masterUrl == null) {
return videoList;
}
final masterHeaders = Map<String, String>.from(headers)
..addAll({
"Accept": "*/*",
"Host": Uri.parse(masterUrl).host,
"Origin": "https://${Uri.parse(url).host}",
"Referer": "https://${Uri.parse(url).host}/",
});
final masterPlaylistResponse =
await client.get(Uri.parse(masterUrl), headers: masterHeaders);
final masterPlaylist = masterPlaylistResponse.body;
final masterBase =
"https://${Uri.parse(masterUrl).host}${Uri.parse(masterUrl).pathSegments.join("/")}/";
masterPlaylist
.substringAfter("#EXT-X-STREAM-INF:")
.split("#EXT-X-STREAM-INF:")
.forEach((it) {
final quality =
"Sendvid:${it.substringAfter("RESOLUTION=").substringAfter("x").substringBefore(",")}p ";
final videoUrl =
masterBase + it.substringAfter("\n").substringBefore("\n");
final videoHeaders = Map<String, String>.from(headers)
..addAll({
"Accept": "*/*",
"Host": Uri.parse(videoUrl).host,
"Origin": "https://${Uri.parse(url).host}",
"Referer": "https://${Uri.parse(url).host}/",
});
videoList.add(
Video(videoUrl, prefix + quality, videoUrl, headers: videoHeaders));
});
return videoList;
}
}

View file

@ -0,0 +1,36 @@
import 'package:http/http.dart' as http;
import 'package:mangayomi/models/video.dart';
import 'package:mangayomi/utils/extensions.dart';
class SibnetExtractor {
final http.Client client = http.Client();
Future<List<Video>> videosFromUrl(String url) async {
List<Video> videoList = [];
final response = await client.get(Uri.parse(url));
if (response.statusCode != 200) {
return [];
}
String script = response.body;
String slug = script
.substringAfter("player.src")
.substringAfter("src:")
.substringAfter("\"")
.substringBefore("\"");
String videoUrl =
slug.contains("http") ? slug : "https://${Uri.parse(url).host}$slug";
Map<String, String> videoHeaders = {
"Referer": url,
};
videoList.add(
Video(videoUrl, "Sibnet", videoUrl, headers: videoHeaders),
);
return videoList;
}
}

View file

@ -33,8 +33,8 @@ Future<List<Video>> getAnimeServers(
sourceId: source.id,
))
];
var res =
await runtime.executeLib('package:package:mangayomi/main.dart', 'getVideoList');
var res = await runtime.executeLib(
'package:package:mangayomi/main.dart', 'getVideoList');
if (res is $List) {
video = res.$reified
.map(

View file

@ -50,9 +50,12 @@ Future<List<MangaModel?>> getLatestUpdatesManga(
newManga.add(newMangaa);
}
latestUpdatesManga = newManga;
} else {
latestUpdatesManga =
(res.$reified as List<dynamic>).map((e) => e as MangaModel).toList();
}
} catch (_) {
throw Exception("");
} catch (e) {
throw Exception(e);
}
return latestUpdatesManga;

View file

@ -23,9 +23,9 @@ Future<MangaModel> getMangaDetail(
..lang = source.lang)
];
var result = await runtime.executeLib('package:package:mangayomi/main.dart',
source.isManga! ? 'getMangaDetail' : 'getAnimeDetail');
try {
var result = await runtime.executeLib('package:package:mangayomi/main.dart',
source.isManga! ? 'getMangaDetail' : 'getAnimeDetail');
if (result is $MangaModel) {
final value = result.$reified;
mangadetail = value;

View file

@ -50,9 +50,12 @@ Future<List<MangaModel?>> getPopularManga(
newManga.add(newMangaa);
}
popularManga = newManga;
} else {
popularManga =
(res.$reified as List<dynamic>).map((e) => e as MangaModel).toList();
}
} catch (_) {
throw Exception("");
} catch (e) {
throw Exception(e);
}
return popularManga;

View file

@ -51,9 +51,12 @@ Future<List<MangaModel?>> searchManga(
newManga.add(newMangaa);
}
manga = newManga;
} else {
manga =
(res.$reified as List<dynamic>).map((e) => e as MangaModel).toList();
}
} catch (_) {
throw Exception("");
} catch (e) {
throw Exception(e);
}
return manga;
}