Files
kodjodevf-mangayomi-extensions/dart/anime/src/it/animesaturn/animesaturn.dart
Francesco De Feo 106fc78b4b animesaturn: fix for this:
dart_eval runtime exception: Bad state: No element
List.first (dart:core-patch/growable_array.dart:344)
SIterable.SgetProperty (package:dart_eval/src/eval/shared/stdlib/core/iterable.dart:609)
SList. S getProperty (package:dart-_eval/s/eval/shared/stdib/core/list.dart:900)
at < asynchronous gap>
Shangri-La Frontier 2
RUNTIME STATE
6-=-=========
Program offset: 831
Shangri-La Frontier 2
Stack sample: [L7: Instance of "$Future<$Response>', L8: Instance of '$Response', L9: $" «html» <body» «script type="text/javascript" src="/min.js" > </script»<noscript»<h1 style="text-align:center;color:red;"› «strong»Please turn JavaScript on and reload the page.</ strong> </h1></noscripts ‹script»function toNumbers(d)(var e=;d.replace(//g,function(d)epush(parselnt(d,16));return e/function toHexfor(vard=[d=1==arguments.length&&arguments|01.constructor==Array?arguments[Ol:arguments, e=**,f=0;f<d.length;f+
+)e+=(16>dff]?")". "*)+d[f|.toString(16);return e.toLowerCase())var a=toNumbers("F4baf9d74d4cb868c5317e9802ca7c1f""),b=toNumbers("Ic2aabd2a4a9ed25aeae78669546c8f9"),c=toNumbers("2e34487f1b463e342a9ec7986e427e80");document.cookie="ASNew-
Gv="+ toHex(slowAES.decrypt(c,2,a,b))+"; path=/";location.href="http://www.animesaturn.cx/anime/Dan-Da-Dan?d=1";</script></body></html>", L10: Instance of '$MManga', L11: Function{func: Closure: (dynamic, dynamic, List<$Value?>) => $Value? from Function
'Xpath@1865285211': static.), L12: $"//div@class="container shadow rounded bg-dark-as-box mb-3 p-3 w-100 text-white"/textO", L13: D, *L14: null, L15: null, L16: null]
Args sample: 1
Call stack: [0, -1]
TRACE:
Nanatsu no Taizai: Mokushiroku no Yonkishi 2
Episodio 9
825: PushConstant (C55)
Tail: 100 Years Quest
826: BoxString (L12)
827: PushArg (L9)
Dragon Ball Daima
828: PushArg (L12)
829: InvokeDynamic (LO.C8)
on Ball Daimal
830: PushReturnValue O
831: PushObjectProperty (L13.C56) < < < EXCEPTION
832: PushReturnValue ()
833: PushObjectProperty (LO.C57)
834: PushReturnValue
2025-01-23 00:32:03 +01:00

362 lines
12 KiB
Dart

import 'package:mangayomi/bridge_lib.dart';
import 'dart:convert';
class AnimeSaturn extends MProvider {
AnimeSaturn({required this.source});
MSource source;
final Client client = Client(source);
@override
Future<MPages> getPopular(int page) async {
final res = (await client
.get(Uri.parse("${source.baseUrl}/animeincorso?page=$page")))
.body;
List<MManga> animeList = [];
final urls = xpath(res,
'//*[@class="sebox"]/div[@class="msebox"]/div[@class="headsebox"]/div[@class="tisebox"]/h2/a/@href');
final names = xpath(res,
'//*[@class="sebox"]/div[@class="msebox"]/div[@class="headsebox"]/div[@class="tisebox"]/h2/a/text()');
final images = xpath(res,
'//*[@class="sebox"]/div[@class="msebox"]/div[@class="bigsebox"]/div/img[@class="attachment-post-thumbnail size-post-thumbnail wp-post-image"]/@src');
for (var i = 0; i < names.length; i++) {
MManga anime = MManga();
anime.name = formatTitle(names[i]);
anime.imageUrl = images[i];
anime.link = urls[i];
animeList.add(anime);
}
return MPages(animeList, true);
}
@override
Future<MPages> getLatestUpdates(int page) async {
final res =
(await client.get(Uri.parse("${source.baseUrl}/newest?page=$page")))
.body;
List<MManga> animeList = [];
final urls = xpath(res, '//*[@class="card mb-4 shadow-sm"]/a/@href');
final names = xpath(res, '//*[@class="card mb-4 shadow-sm"]/a/@title');
final images = xpath(res,
'//*[@class="card mb-4 shadow-sm"]/a/img[@class="new-anime"]/@src');
for (var i = 0; i < names.length; i++) {
MManga anime = MManga();
anime.name = formatTitle(names[i]);
anime.imageUrl = images[i];
anime.link = urls[i];
animeList.add(anime);
}
return MPages(animeList, true);
}
@override
Future<MPages> search(String query, int page, FilterList filterList) async {
final filters = filterList.filters;
String url = "";
if (query.isNotEmpty) {
url = "${source.baseUrl}/animelist?search=$query";
} else {
url = "${source.baseUrl}/filter?";
int variantgenre = 0;
int variantstate = 0;
int variantyear = 0;
for (var filter in filters) {
if (filter.type == "GenreFilter") {
final genre = (filter.state as List).where((e) => e.state).toList();
if (genre.isNotEmpty) {
for (var st in genre) {
url += "&categories%5B${variantgenre}%5D=${st.value}";
variantgenre++;
}
}
} else if (filter.type == "YearList") {
final years = (filter.state as List).where((e) => e.state).toList();
if (years.isNotEmpty) {
for (var st in years) {
url += "&years%5B${variantyear}%5D=${st.value}";
variantyear++;
}
}
} else if (filter.type == "StateList") {
final states = (filter.state as List).where((e) => e.state).toList();
if (states.isNotEmpty) {
for (var st in states) {
url += "&states%5B${variantstate}%5D=${st.value}";
variantstate++;
}
}
} else if (filter.type == "LangList") {
final lang = filter.values[filter.state].value;
if (lang.isNotEmpty) {
url += "&language%5B0%5D=$lang";
}
}
}
url += "&page=$page";
}
final res = (await client.get(Uri.parse(url))).body;
List<MManga> animeList = [];
List<String> urls = [];
List<String> names = [];
List<String> images = [];
if (query.isNotEmpty) {
urls = xpath(res,
'//*[@class="list-group"]/li[@class="list-group-item bg-dark-as-box-shadow"]/div[@class="item-archivio"]/div[@class="info-archivio"]/h3/a[@class="badge badge-archivio badge-light"]/@href');
names = xpath(res,
'//*[@class="list-group"]/li[@class="list-group-item bg-dark-as-box-shadow"]/div[@class="item-archivio"]/div[@class="info-archivio"]/h3/a[@class="badge badge-archivio badge-light"]/text()');
images = xpath(res,
'//*[@class="list-group"]/li[@class="list-group-item bg-dark-as-box-shadow"]/div[@class="item-archivio"]/a/img/@src');
} else {
urls = xpath(res, '//*[@class="card mb-4 shadow-sm"]/a/@href');
names = xpath(res, '//*[@class="card mb-4 shadow-sm"]/a/text()');
images = xpath(res,
'//*[@class="card mb-4 shadow-sm"]/a/img[@class="new-anime"]/@src');
}
for (var i = 0; i < names.length; i++) {
MManga anime = MManga();
anime.name = formatTitle(names[i]);
anime.imageUrl = images[i];
anime.link = urls[i];
animeList.add(anime);
}
return MPages(animeList, query.isEmpty);
}
@override
Future<MManga> getDetail(String url) async {
final statusList = [
{"In corso": 0, "Finito": 1}
];
final res = (await client.get(Uri.parse(url))).body;
MManga anime = MManga();
final detailsList = xpath(res,
'//div[@class="container shadow rounded bg-dark-as-box mb-3 p-3 w-100 text-white"]/text()');
if (detailsList.isNotEmpty) {
final details = detailsList.first;
anime.status = parseStatus(
details.substring(
details.indexOf("Stato:") + 6, details.indexOf("Data di uscita:")),
statusList);
anime.author = details.substring(7, details.indexOf("Stato:"));
}
final description = xpath(res, '//*[@id="shown-trama"]/text()');
final descriptionFull = xpath(res, '//*[@id="full-trama"]/text()');
if (description.isNotEmpty) {
anime.description = description.first;
} else {
anime.description = "";
}
if (descriptionFull.isNotEmpty) {
if (descriptionFull.first.length > anime.description.length) {
anime.description = descriptionFull.first;
}
}
anime.genre = xpath(res,
'//*[@class="container shadow rounded bg-dark-as-box mb-3 p-3 w-100"]/a/text()');
final epUrls = xpath(res,
'//*[@class="btn-group episodes-button episodi-link-button"]/a/@href');
final titles = xpath(res,
'//*[@class="btn-group episodes-button episodi-link-button"]/a/text()');
List<MChapter>? episodesList = [];
for (var i = 0; i < epUrls.length; i++) {
MChapter episode = MChapter();
episode.name = titles[i];
episode.url = epUrls[i];
episodesList.add(episode);
}
anime.chapters = episodesList.reversed.toList();
return anime;
}
@override
Future<List<MVideo>> getVideoList(String url) async {
final res = (await client.get(Uri.parse(url))).body;
final urlVid = xpath(res, '//a[contains(@href,"/watch")]/@href').first;
final resVid = (await client.get(Uri.parse(urlVid))).body;
String masterUrl = "";
if (resVid.contains("jwplayer(")) {
masterUrl = substringBefore(substringAfter(resVid, "file: \""), "\"");
} else {
masterUrl = parseHtml(resVid).selectFirst("source").attr("src");
}
List<MVideo> videos = [];
if (masterUrl.endsWith("playlist.m3u8")) {
final masterPlaylistRes = (await client.get(Uri.parse(masterUrl))).body;
for (var it in substringAfter(masterPlaylistRes, "#EXT-X-STREAM-INF:")
.split("#EXT-X-STREAM-INF:")) {
final quality =
"${substringBefore(substringBefore(substringAfter(substringAfter(it, "RESOLUTION="), "x"), ","), "\n")}p";
String videoUrl = substringBefore(substringAfter(it, "\n"), "\n");
if (!videoUrl.startsWith("http")) {
videoUrl =
"${masterUrl.split("/").sublist(0, masterUrl.split("/").length - 1).join("/")}/$videoUrl";
}
MVideo video = MVideo();
video
..url = videoUrl
..originalUrl = videoUrl
..quality = quality;
videos.add(video);
}
} else {
MVideo video = MVideo();
video
..url = masterUrl
..originalUrl = masterUrl
..quality = "Qualità predefinita";
videos.add(video);
}
return sortVideos(videos, source.id);
}
String formatTitle(String titlestring) {
return titlestring
.replaceAll("(ITA) ITA", "Dub ITA")
.replaceAll("(ITA)", "Dub ITA")
.replaceAll("Sub ITA", "");
}
@override
List<dynamic> getFilterList() {
return [
HeaderFilter("Ricerca per titolo ignora i filtri e viceversa"),
GroupFilter("GenreFilter", "Generi", [
CheckBoxFilter("Arti Marziali", "Arti Marziali"),
CheckBoxFilter("Avventura", "Avventura"),
CheckBoxFilter("Azione", "Azione"),
CheckBoxFilter("Bambini", "Bambini"),
CheckBoxFilter("Commedia", "Commedia"),
CheckBoxFilter("Demenziale", "Demenziale"),
CheckBoxFilter("Demoni", "Demoni"),
CheckBoxFilter("Drammatico", "Drammatico"),
CheckBoxFilter("Ecchi", "Ecchi"),
CheckBoxFilter("Fantasy", "Fantasy"),
CheckBoxFilter("Gioco", "Gioco"),
CheckBoxFilter("Harem", "Harem"),
CheckBoxFilter("Hentai", "Hentai"),
CheckBoxFilter("Horror", "Horror"),
CheckBoxFilter("Josei", "Josei"),
CheckBoxFilter("Magia", "Magia"),
CheckBoxFilter("Mecha", "Mecha"),
CheckBoxFilter("Militari", "Militari"),
CheckBoxFilter("Mistero", "Mistero"),
CheckBoxFilter("Musicale", "Musicale"),
CheckBoxFilter("Parodia", "Parodia"),
CheckBoxFilter("Polizia", "Polizia"),
CheckBoxFilter("Psicologico", "Psicologico"),
CheckBoxFilter("Romantico", "Romantico"),
CheckBoxFilter("Samurai", "Samurai"),
CheckBoxFilter("Sci-Fi", "Sci-Fi"),
CheckBoxFilter("Scolastico", "Scolastico"),
CheckBoxFilter("Seinen", "Seinen"),
CheckBoxFilter("Sentimentale", "Sentimentale"),
CheckBoxFilter("Shoujo Ai", "Shoujo Ai"),
CheckBoxFilter("Shoujo", "Shoujo"),
CheckBoxFilter("Shounen Ai", "Shounen Ai"),
CheckBoxFilter("Shounen", "Shounen"),
CheckBoxFilter("Slice of Life", "Slice of Life"),
CheckBoxFilter("Soprannaturale", "Soprannaturale"),
CheckBoxFilter("Spazio", "Spazio"),
CheckBoxFilter("Sport", "Sport"),
CheckBoxFilter("Storico", "Storico"),
CheckBoxFilter("Superpoteri", "Superpoteri"),
CheckBoxFilter("Thriller", "Thriller"),
CheckBoxFilter("Vampiri", "Vampiri"),
CheckBoxFilter("Veicoli", "Veicoli"),
CheckBoxFilter("Yaoi", "Yaoi"),
CheckBoxFilter("Yuri", "Yuri"),
]),
GroupFilter("YearList", "Anno di Uscita", [
for (var i = 1969; i < 2022; i++)
CheckBoxFilter(i.toString(), i.toString()),
]),
GroupFilter("StateList", "Stato", [
CheckBoxFilter("In corso", "0"),
CheckBoxFilter("Finito", "1"),
CheckBoxFilter("Non rilasciato", "2"),
CheckBoxFilter("Droppato", "3"),
]),
SelectFilter("LangList", "Lingua", 0, [
SelectFilterOption("", ""),
SelectFilterOption("Subbato", "0"),
SelectFilterOption("Doppiato", "1"),
]),
];
}
@override
List<dynamic> getSourcePreferences() {
return [
ListPreference(
key: "preferred_quality",
title: "Qualità preferita",
summary: "",
valueIndex: 0,
entries: ["1080p", "720p", "480p", "360p", "240p", "144p"],
entryValues: ["1080", "720", "480", "360", "240", "144"]),
];
}
List<MVideo> sortVideos(List<MVideo> videos, int sourceId) {
String quality = getPreferenceValue(sourceId, "preferred_quality");
videos.sort((MVideo a, MVideo b) {
int qualityMatchA = 0;
if (a.quality.contains(quality)) {
qualityMatchA = 1;
}
int qualityMatchB = 0;
if (b.quality.contains(quality)) {
qualityMatchB = 1;
}
if (qualityMatchA != qualityMatchB) {
return qualityMatchB - qualityMatchA;
}
final regex = RegExp(r'(\d+)p');
final matchA = regex.firstMatch(a.quality);
final matchB = regex.firstMatch(b.quality);
final int qualityNumA = int.tryParse(matchA?.group(1) ?? '0') ?? 0;
final int qualityNumB = int.tryParse(matchB?.group(1) ?? '0') ?? 0;
return qualityNumB - qualityNumA;
});
return videos;
}
}
AnimeSaturn main(MSource source) {
return AnimeSaturn(source: source);
}