mirror of
https://github.com/kodjodevf/mangayomi-extensions.git
synced 2026-02-14 19:01:15 +00:00
@@ -333,7 +333,8 @@ See [`MDocument` model](https://github.com/kodjodevf/mangayomi/blob/main/lib/eva
|
|||||||
- `String` substringBeforeLast(`String text`, `String pattern`)
|
- `String` substringBeforeLast(`String text`, `String pattern`)
|
||||||
|
|
||||||
### Crypto utils
|
### Crypto utils
|
||||||
- `String` evalJs(`String code`);
|
- `String` unpackJs(`String code`);
|
||||||
|
- `Future<String>` evalJs(`String code`);
|
||||||
- `String` deobfuscateJsPassword(`String inputString`)
|
- `String` deobfuscateJsPassword(`String inputString`)
|
||||||
- `String` encryptAESCryptoJS(`String plainText`, `String passphrase`)
|
- `String` encryptAESCryptoJS(`String plainText`, `String passphrase`)
|
||||||
- `String` decryptAESCryptoJS(`String encrypted`, `String passphrase`)
|
- `String` decryptAESCryptoJS(`String encrypted`, `String passphrase`)
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ class DataLifeEngine extends MProvider {
|
|||||||
final res = await http('GET', json.encode({"url": url}));
|
final res = await http('GET', json.encode({"url": url}));
|
||||||
final masterUrl = substringBefore(
|
final masterUrl = substringBefore(
|
||||||
substringAfter(
|
substringAfter(
|
||||||
substringAfter(substringAfter(evalJs(res), "sources:"), "file:\""),
|
substringAfter(substringAfter(unpackJs(res), "sources:"), "file:\""),
|
||||||
"src:\""),
|
"src:\""),
|
||||||
'"');
|
'"');
|
||||||
final masterPlaylistRes =
|
final masterPlaylistRes =
|
||||||
@@ -203,7 +203,7 @@ class DataLifeEngine extends MProvider {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
final masterUrl =
|
final masterUrl =
|
||||||
substringBefore(substringAfter(evalJs(js.first), "{file:\""), "\"}");
|
substringBefore(substringAfter(unpackJs(js.first), "{file:\""), "\"}");
|
||||||
final masterPlaylistRes =
|
final masterPlaylistRes =
|
||||||
await http('GET', json.encode({"url": masterUrl}));
|
await http('GET', json.encode({"url": masterUrl}));
|
||||||
List<MVideo> videos = [];
|
List<MVideo> videos = [];
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import 'src/ar/okanime/source.dart';
|
|||||||
import 'src/en/aniwave/source.dart';
|
import 'src/en/aniwave/source.dart';
|
||||||
import 'src/en/dramacool/source.dart';
|
import 'src/en/dramacool/source.dart';
|
||||||
import 'src/en/gogoanime/source.dart';
|
import 'src/en/gogoanime/source.dart';
|
||||||
|
import 'src/fr/animesama/source.dart';
|
||||||
import 'src/hi/yomovies/source.dart';
|
import 'src/hi/yomovies/source.dart';
|
||||||
import 'src/en/kisskh/source.dart';
|
import 'src/en/kisskh/source.dart';
|
||||||
import 'src/en/uhdmovies/source.dart';
|
import 'src/en/uhdmovies/source.dart';
|
||||||
@@ -40,7 +41,8 @@ void main() {
|
|||||||
...datalifeengineSourcesList,
|
...datalifeengineSourcesList,
|
||||||
filma24,
|
filma24,
|
||||||
dramacoolSource,
|
dramacoolSource,
|
||||||
yomoviesSource
|
yomoviesSource,
|
||||||
|
animesamaSource
|
||||||
];
|
];
|
||||||
final List<Map<String, dynamic>> jsonList =
|
final List<Map<String, dynamic>> jsonList =
|
||||||
_sourcesList.map((source) => source.toJson()).toList();
|
_sourcesList.map((source) => source.toJson()).toList();
|
||||||
|
|||||||
@@ -204,7 +204,13 @@ class Aniwave extends MProvider {
|
|||||||
final hosterSelection = preferenceHosterSelection(source.id);
|
final hosterSelection = preferenceHosterSelection(source.id);
|
||||||
final typeSelection = preferenceTypeSelection(source.id);
|
final typeSelection = preferenceTypeSelection(source.id);
|
||||||
if (typeSelection.contains(type.toLowerCase())) {
|
if (typeSelection.contains(type.toLowerCase())) {
|
||||||
if (url.contains("mp4upload") &&
|
if (url.contains("vidplay") || url.contains("mcloud")) {
|
||||||
|
final hosterName =
|
||||||
|
url.contains("vidplay") ? "VidPlay" : "MyCloud";
|
||||||
|
if (hosterSelection.contains(hosterName.toLowerCase())) {
|
||||||
|
a = await vidsrcExtractor(url, hosterName, type);
|
||||||
|
}
|
||||||
|
} else if (url.contains("mp4upload") &&
|
||||||
hosterSelection.contains("mp4upload")) {
|
hosterSelection.contains("mp4upload")) {
|
||||||
a = await mp4UploadExtractor(url, null, "", type);
|
a = await mp4UploadExtractor(url, null, "", type);
|
||||||
} else if (url.contains("streamtape") &&
|
} else if (url.contains("streamtape") &&
|
||||||
@@ -305,6 +311,111 @@ class Aniwave extends MProvider {
|
|||||||
return vrf;
|
return vrf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<List<MVideo>> vidsrcExtractor(
|
||||||
|
String url, String name, String type) async {
|
||||||
|
List<String> keys = json.decode(await http(
|
||||||
|
'GET',
|
||||||
|
json.encode({
|
||||||
|
"url":
|
||||||
|
"https://raw.githubusercontent.com/Claudemirovsky/worstsource-keys/keys/keys.json"
|
||||||
|
})));
|
||||||
|
final host = Uri.parse(url).host;
|
||||||
|
final apiUrl = await getApiUrl(url, keys);
|
||||||
|
final headers = {
|
||||||
|
"Accept": "application/json, text/javascript, */*; q=0.01",
|
||||||
|
"Host": host,
|
||||||
|
"Referer": Uri.decodeComponent(url),
|
||||||
|
"X-Requested-With": "XMLHttpRequest"
|
||||||
|
};
|
||||||
|
final res =
|
||||||
|
await http('GET', json.encode({"url": apiUrl, "headers": headers}));
|
||||||
|
if (res == "error") return [];
|
||||||
|
String masterUrl =
|
||||||
|
((json.decode(res)['result']['sources'] as List<Map<String, dynamic>>)
|
||||||
|
.first)['file'];
|
||||||
|
final tracks = (json.decode(res)['result']['tracks'] as List)
|
||||||
|
.where((e) => e['kind'] == 'captions' ? true : false)
|
||||||
|
.toList();
|
||||||
|
List<MTrack> subtitles = [];
|
||||||
|
|
||||||
|
for (var sub in tracks) {
|
||||||
|
try {
|
||||||
|
MTrack subtitle = MTrack();
|
||||||
|
subtitle
|
||||||
|
..label = sub["label"]
|
||||||
|
..file = sub["file"];
|
||||||
|
subtitles.add(subtitle);
|
||||||
|
} catch (_) {}
|
||||||
|
}
|
||||||
|
List<MVideo> videoList = [];
|
||||||
|
final masterPlaylistRes =
|
||||||
|
await http('GET', json.encode({"url": masterUrl}));
|
||||||
|
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 = "$name - $type - $quality"
|
||||||
|
..headers = {"Referer": "https://$host/"}
|
||||||
|
..subtitles = subtitles;
|
||||||
|
videoList.add(video);
|
||||||
|
}
|
||||||
|
return videoList;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> getApiUrl(String url, List<String> keyList) async {
|
||||||
|
final host = Uri.parse(url).host;
|
||||||
|
final paramsToString = Uri.parse(url)
|
||||||
|
.queryParameters
|
||||||
|
.entries
|
||||||
|
.map((e) => "${e.key}=${e.value}")
|
||||||
|
.join("&");
|
||||||
|
var vidId = substringBefore(substringAfterLast(url, "/"), "?");
|
||||||
|
var encodedID = encodeID(vidId, keyList);
|
||||||
|
final apiSlug = await callFromFuToken(host, encodedID);
|
||||||
|
String apiUrlString = "";
|
||||||
|
apiUrlString += "https://$host/$apiSlug";
|
||||||
|
if (paramsToString.isNotEmpty) {
|
||||||
|
apiUrlString += "?$paramsToString";
|
||||||
|
}
|
||||||
|
|
||||||
|
return apiUrlString;
|
||||||
|
}
|
||||||
|
|
||||||
|
String encodeID(String vidId, List<String> keyList) {
|
||||||
|
var rc4Key1 = keyList[0];
|
||||||
|
var rc4Key2 = keyList[1];
|
||||||
|
final rc4 = rc4Encrypt(rc4Key1, vidId.codeUnits);
|
||||||
|
final rc41 = rc4Encrypt(rc4Key2, rc4);
|
||||||
|
return base64.encode(rc41).replaceAll("/", "_").trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<String> callFromFuToken(String host, String data) async {
|
||||||
|
final fuTokenScript =
|
||||||
|
await http('GET', json.encode({"url": "https://$host/futoken"}));
|
||||||
|
String js = "";
|
||||||
|
js += "(function";
|
||||||
|
js += substringBefore(
|
||||||
|
substringAfter(substringAfter(fuTokenScript, "window"), "function")
|
||||||
|
.replaceAll("jQuery.ajax(", ""),
|
||||||
|
"+location.search");
|
||||||
|
js += "}(\"$data\"))";
|
||||||
|
final jsRes = await evalJs(js);
|
||||||
|
if (jsRes == "error") return "";
|
||||||
|
return jsRes;
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<dynamic> getFilterList(MSource source) {
|
List<dynamic> getFilterList(MSource source) {
|
||||||
return [
|
return [
|
||||||
|
|||||||
@@ -13,4 +13,5 @@ Source _aniwave = Source(
|
|||||||
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/anime/src/en/aniwave/icon.png",
|
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/anime/src/en/aniwave/icon.png",
|
||||||
sourceCodeUrl: _aniwaveCodeUrl,
|
sourceCodeUrl: _aniwaveCodeUrl,
|
||||||
version: _aniwaveVersion,
|
version: _aniwaveVersion,
|
||||||
|
appMinVerReq: "0.1.5",
|
||||||
isManga: false);
|
isManga: false);
|
||||||
|
|||||||
405
anime/src/fr/animesama/animesama.dart
Normal file
405
anime/src/fr/animesama/animesama.dart
Normal file
@@ -0,0 +1,405 @@
|
|||||||
|
import 'package:mangayomi/bridge_lib.dart';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
class AnimeSama extends MProvider {
|
||||||
|
AnimeSama();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<MPages> getPopular(MSource source, int page) async {
|
||||||
|
final data = {"url": "${source.baseUrl}/#$page"};
|
||||||
|
final doc = await http('GET', json.encode(data));
|
||||||
|
final regex = RegExp(r"""^\s*carteClassique\(\s*.*?\s*,\s*"(.*?)".*\)""",
|
||||||
|
multiLine: true);
|
||||||
|
var matches = regex.allMatches(doc).toList();
|
||||||
|
List<List<RegExpMatch>> chunks = chunked(matches, 5);
|
||||||
|
List<MManga> seasons = [];
|
||||||
|
if (page > 0 && page <= chunks.length) {
|
||||||
|
for (RegExpMatch match in chunks[page - 1]) {
|
||||||
|
seasons.addAll(await fetchAnimeSeasons(
|
||||||
|
"${source.baseUrl}/catalogue/${match.group(1)}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return MPages(seasons, page < chunks.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<MPages> getLatestUpdates(MSource source, int page) async {
|
||||||
|
final res = await http('GET', json.encode({"url": source.baseUrl}));
|
||||||
|
var document = parseHtml(res);
|
||||||
|
final latest = document
|
||||||
|
.select("h2")
|
||||||
|
.where((MElement e) =>
|
||||||
|
e.outerHtml.toLowerCase().contains("derniers ajouts"))
|
||||||
|
.toList();
|
||||||
|
final seasonElements = (latest.first.nextElementSibling as MElement)
|
||||||
|
.select(".scrollBarStyled > div")
|
||||||
|
.toList();
|
||||||
|
List<MManga> seasons = [];
|
||||||
|
for (var seasonElement in seasonElements) {
|
||||||
|
seasons.addAll(await fetchAnimeSeasons(
|
||||||
|
(seasonElement as MElement).getElementsByTagName("a").first.getHref));
|
||||||
|
}
|
||||||
|
return MPages(seasons, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<MPages> search(
|
||||||
|
MSource source, String query, int page, FilterList filterList) async {
|
||||||
|
final filters = filterList.filters;
|
||||||
|
final res = await http('GET',
|
||||||
|
json.encode({"url": "${source.baseUrl}/catalogue/listing_all.php"}));
|
||||||
|
var databaseElements = parseHtml(res).select(".cardListAnime");
|
||||||
|
List<MElement> elements = [];
|
||||||
|
elements = databaseElements
|
||||||
|
.where((MElement element) => element.select("h1, p").any((MElement e) =>
|
||||||
|
e.text.toLowerCase().contains(query.toLowerCase().trim())))
|
||||||
|
.toList();
|
||||||
|
for (var filter in filters) {
|
||||||
|
if (filter.type == "TypeFilter") {
|
||||||
|
final types = (filter.state as List).where((e) => e.state).toList();
|
||||||
|
elements = elements
|
||||||
|
.where((MElement element) =>
|
||||||
|
types.isEmpty ||
|
||||||
|
types.any((p) => element.className.contains(p.value)))
|
||||||
|
.toList();
|
||||||
|
} else if (filter.type == "LanguageFilter") {
|
||||||
|
final language = (filter.state as List).where((e) => e.state).toList();
|
||||||
|
elements = elements
|
||||||
|
.where((MElement element) =>
|
||||||
|
language.isEmpty ||
|
||||||
|
language.any((p) => element.className.contains(p.value)))
|
||||||
|
.toList();
|
||||||
|
} else if (filter.type == "GenreFilter") {
|
||||||
|
final included = (filter.state as List)
|
||||||
|
.where((e) => e.state == 1 ? true : false)
|
||||||
|
.toList();
|
||||||
|
final excluded = (filter.state as List)
|
||||||
|
.where((e) => e.state == 2 ? true : false)
|
||||||
|
.toList();
|
||||||
|
if (included.isNotEmpty) {
|
||||||
|
elements = elements
|
||||||
|
.where((MElement element) =>
|
||||||
|
included.every((p) => element.className.contains(p.value)))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
if (excluded.isNotEmpty) {
|
||||||
|
elements = elements
|
||||||
|
.where((MElement element) =>
|
||||||
|
excluded.every((p) => element.className.contains(p.value)))
|
||||||
|
.toList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<List<MElement>> chunks = chunked(elements, 5);
|
||||||
|
if (chunks.isEmpty) return MPages([], false);
|
||||||
|
List<MManga> seasons = [];
|
||||||
|
for (var seasonElement in chunks[page - 1]) {
|
||||||
|
seasons.addAll(await fetchAnimeSeasons(
|
||||||
|
seasonElement.getElementsByTagName("a").first.getHref));
|
||||||
|
}
|
||||||
|
|
||||||
|
return MPages(seasons, page < chunks.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<MManga> getDetail(MSource source, String url) async {
|
||||||
|
var animeUrl =
|
||||||
|
"${source.baseUrl}${substringBeforeLast(Uri.parse(url).path, "/")}";
|
||||||
|
var movie =
|
||||||
|
int.tryParse(url.split("#").length >= 2 ? url.split("#")[1] : "");
|
||||||
|
List<Map<String, dynamic>> playersList = [];
|
||||||
|
for (var lang in ["vostfr", "vf"]) {
|
||||||
|
final players = await fetchPlayers("$animeUrl/$lang");
|
||||||
|
if (players.isNotEmpty) {
|
||||||
|
playersList.add({"players": players, "lang": lang});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int maxLength = 0;
|
||||||
|
for (var sublist in playersList) {
|
||||||
|
for (var innerList in sublist["players"]) {
|
||||||
|
if (innerList.length > maxLength) {
|
||||||
|
maxLength = innerList.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<MChapter>? episodesList = [];
|
||||||
|
for (var episodeNumber = 0; episodeNumber < maxLength; episodeNumber++) {
|
||||||
|
List<String> langs = [];
|
||||||
|
List<Map<String, dynamic>> players = [];
|
||||||
|
for (var playerListt in playersList) {
|
||||||
|
for (var player in playerListt["players"]) {
|
||||||
|
if (player.length > episodeNumber) {
|
||||||
|
langs.add(playerListt["lang"]);
|
||||||
|
players.add(
|
||||||
|
{"lang": playerListt["lang"], "player": player[episodeNumber]});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MChapter episode = MChapter();
|
||||||
|
episode.name = movie == null ? 'Episode ${episodeNumber + 1}' : 'Film';
|
||||||
|
episode.scanlator = langs.toSet().toList().join(', ').toUpperCase();
|
||||||
|
episode.url = json.encode(players);
|
||||||
|
episodesList.add(episode);
|
||||||
|
}
|
||||||
|
|
||||||
|
MManga anime = MManga();
|
||||||
|
anime.chapters =
|
||||||
|
movie == null ? episodesList.reversed.toList() : [episodesList[movie]];
|
||||||
|
return anime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<MVideo>> getVideoList(MSource source, String url) async {
|
||||||
|
final players = json.decode(url);
|
||||||
|
List<MVideo> videos = [];
|
||||||
|
for (var player in players) {
|
||||||
|
String lang = (player["lang"] as String).toUpperCase();
|
||||||
|
String playerUrl = player["player"];
|
||||||
|
List<MVideo> a = [];
|
||||||
|
if (playerUrl.contains("sendvid")) {
|
||||||
|
a = await sendVidExtractor(playerUrl, null, lang);
|
||||||
|
} else if (playerUrl.contains("anime-sama.fr")) {
|
||||||
|
MVideo video = MVideo();
|
||||||
|
video
|
||||||
|
..url = playerUrl
|
||||||
|
..originalUrl = playerUrl
|
||||||
|
..quality = "${lang} - AS Player";
|
||||||
|
a = [video];
|
||||||
|
} else if (playerUrl.contains("sibnet.ru")) {
|
||||||
|
a = await sibnetExtractor(playerUrl, lang);
|
||||||
|
}
|
||||||
|
videos.addAll(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sortVideos(videos, source.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<dynamic> getFilterList(MSource source) {
|
||||||
|
return [
|
||||||
|
GroupFilter("TypeFilter", "Type", [
|
||||||
|
CheckBoxFilter("Anime", "Anime"),
|
||||||
|
CheckBoxFilter("Film", "Film"),
|
||||||
|
CheckBoxFilter("Autres", "Autres"),
|
||||||
|
]),
|
||||||
|
GroupFilter("LanguageFilter", "Langue", [
|
||||||
|
CheckBoxFilter("VF", "VF"),
|
||||||
|
CheckBoxFilter("VOSTFR", "VOSTFR"),
|
||||||
|
]),
|
||||||
|
GroupFilter("GenreFilter", "Genre", [
|
||||||
|
TriStateFilter("Action", "Action"),
|
||||||
|
TriStateFilter("Aventure", "Aventure"),
|
||||||
|
TriStateFilter("Combats", "Combats"),
|
||||||
|
TriStateFilter("Comédie", "Comédie"),
|
||||||
|
TriStateFilter("Drame", "Drame"),
|
||||||
|
TriStateFilter("Ecchi", "Ecchi"),
|
||||||
|
TriStateFilter("École", "School-Life"),
|
||||||
|
TriStateFilter("Fantaisie", "Fantasy"),
|
||||||
|
TriStateFilter("Horreur", "Horreur"),
|
||||||
|
TriStateFilter("Isekai", "Isekai"),
|
||||||
|
TriStateFilter("Josei", "Josei"),
|
||||||
|
TriStateFilter("Mystère", "Mystère"),
|
||||||
|
TriStateFilter("Psychologique", "Psychologique"),
|
||||||
|
TriStateFilter("Quotidien", "Slice-of-Life"),
|
||||||
|
TriStateFilter("Romance", "Romance"),
|
||||||
|
TriStateFilter("Seinen", "Seinen"),
|
||||||
|
TriStateFilter("Shônen", "Shônen"),
|
||||||
|
TriStateFilter("Shôjo", "Shôjo"),
|
||||||
|
TriStateFilter("Sports", "Sports"),
|
||||||
|
TriStateFilter("Surnaturel", "Surnaturel"),
|
||||||
|
TriStateFilter("Tournois", "Tournois"),
|
||||||
|
TriStateFilter("Yaoi", "Yaoi"),
|
||||||
|
TriStateFilter("Yuri", "Yuri"),
|
||||||
|
]),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
List<dynamic> getSourcePreferences(MSource source) {
|
||||||
|
return [
|
||||||
|
ListPreference(
|
||||||
|
key: "preferred_quality",
|
||||||
|
title: "Qualité préférée",
|
||||||
|
summary: "",
|
||||||
|
valueIndex: 0,
|
||||||
|
entries: ["1080p", "720p", "480p", "360p"],
|
||||||
|
entryValues: ["1080", "720", "480", "360"]),
|
||||||
|
ListPreference(
|
||||||
|
key: "voices_preference",
|
||||||
|
title: "Préférence des voix",
|
||||||
|
summary: "",
|
||||||
|
valueIndex: 0,
|
||||||
|
entries: ["Préférer VOSTFR", "Préférer VF"],
|
||||||
|
entryValues: ["vostfr", "vf"]),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<MManga>> fetchAnimeSeasons(String url) async {
|
||||||
|
final res = await http('GET', json.encode({"url": url}));
|
||||||
|
var document = parseHtml(res);
|
||||||
|
String animeName = document.getElementById("titreOeuvre")?.text ?? "";
|
||||||
|
|
||||||
|
var seasonRegex =
|
||||||
|
RegExp("^\\s*panneauAnime\\(\"(.*)\", \"(.*)\"\\)", multiLine: true);
|
||||||
|
var scripts = document
|
||||||
|
.select("h2 + p + div > script, h2 + div > script")
|
||||||
|
.map((MElement element) => element.text)
|
||||||
|
.toList()
|
||||||
|
.join("");
|
||||||
|
List<MManga> animeList = [];
|
||||||
|
|
||||||
|
List<RegExpMatch> seasonRegexReg = seasonRegex.allMatches(scripts).toList();
|
||||||
|
for (var animeIndex = 0; animeIndex < seasonRegexReg.length; animeIndex++) {
|
||||||
|
final seasonName = seasonRegexReg[animeIndex].group(1);
|
||||||
|
final seasonStem = seasonRegexReg[animeIndex].group(2);
|
||||||
|
if (seasonStem.toLowerCase().contains("film")) {
|
||||||
|
var moviesUrl = "$url/$seasonStem";
|
||||||
|
var movies = await fetchPlayers(moviesUrl);
|
||||||
|
if (movies.isNotEmpty) {
|
||||||
|
var movieNameRegex =
|
||||||
|
RegExp("^\\s*newSPF\\(\"(.*)\"\\);", multiLine: true);
|
||||||
|
var moviesDoc = await http('GET', json.encode({"url": moviesUrl}));
|
||||||
|
List<RegExpMatch> matches =
|
||||||
|
movieNameRegex.allMatches(moviesDoc).toList();
|
||||||
|
|
||||||
|
for (var i = 0; i < movies.length; i++) {
|
||||||
|
var title = "";
|
||||||
|
if (animeIndex == 0 && movies.length == 1) {
|
||||||
|
title = animeName;
|
||||||
|
} else if (matches.length > i) {
|
||||||
|
title = "$animeName ${(matches[i]).group(1)}";
|
||||||
|
} else if (movies.length == 1) {
|
||||||
|
title = "$animeName Film";
|
||||||
|
} else {
|
||||||
|
title = "$animeName Film ${i + 1}";
|
||||||
|
}
|
||||||
|
MManga anime = MManga();
|
||||||
|
anime.imageUrl = document.getElementById("coverOeuvre")?.getSrc;
|
||||||
|
anime.genre = (document.xpathFirst(
|
||||||
|
'//h2[contains(text(),"Genres")]/following-sibling::a/text()') ??
|
||||||
|
"")
|
||||||
|
.split(",");
|
||||||
|
anime.description = document.xpathFirst(
|
||||||
|
'//h2[contains(text(),"Synopsis")]/following-sibling::p/text()') ??
|
||||||
|
"";
|
||||||
|
|
||||||
|
anime.name = title;
|
||||||
|
anime.link = "$moviesUrl#$i";
|
||||||
|
anime.status = MStatus.completed;
|
||||||
|
animeList.add(anime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MManga anime = MManga();
|
||||||
|
anime.imageUrl = document.getElementById("coverOeuvre")?.getSrc;
|
||||||
|
anime.genre = (document.xpathFirst(
|
||||||
|
'//h2[contains(text(),"Genres")]/following-sibling::a/text()') ??
|
||||||
|
"")
|
||||||
|
.split(",");
|
||||||
|
anime.description = document.xpathFirst(
|
||||||
|
'//h2[contains(text(),"Synopsis")]/following-sibling::p/text()') ??
|
||||||
|
"";
|
||||||
|
anime.name =
|
||||||
|
'$animeName ${substringBefore(seasonName, ',').replaceAll('"', "")}';
|
||||||
|
anime.link = "$url/$seasonStem";
|
||||||
|
animeList.add(anime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return animeList;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<List<String>>> fetchPlayers(String url) async {
|
||||||
|
var docUrl = "$url/episodes.js";
|
||||||
|
List<List<String>> players = [];
|
||||||
|
var response = await http('GET', json.encode({"url": docUrl}));
|
||||||
|
|
||||||
|
if (response == "error") {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
var sanitizedDoc = sanitizeEpisodesJs(response);
|
||||||
|
for (var i = 1; i <= 8; i++) {
|
||||||
|
final numPlayers = getPlayers("eps$i", sanitizedDoc);
|
||||||
|
|
||||||
|
if (numPlayers != null) players.add(numPlayers);
|
||||||
|
}
|
||||||
|
|
||||||
|
final asPlayers = getPlayers("epsAS", sanitizedDoc);
|
||||||
|
if (asPlayers != null) players.add(asPlayers);
|
||||||
|
|
||||||
|
if (players.isEmpty) return [];
|
||||||
|
List<List<String>> finalPlayers = [];
|
||||||
|
for (var i = 0; i <= players[0].length; i++) {
|
||||||
|
for (var playerList in players) {
|
||||||
|
if (playerList.length > i) {
|
||||||
|
finalPlayers.add(playerList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return finalPlayers.toSet().toList();
|
||||||
|
}
|
||||||
|
|
||||||
|
List<String>? getPlayers(String playerName, String doc) {
|
||||||
|
var playerRegex = RegExp('$playerName\\s*=\\s*(\\[.*?\\])', dotAll: true);
|
||||||
|
var match = playerRegex.firstMatch(doc);
|
||||||
|
if (match == null) return null;
|
||||||
|
final regex = RegExp(r"""https?://[^\s\',\[\]]+""");
|
||||||
|
final matches = regex.allMatches(match.group(1));
|
||||||
|
List<String> urls = [];
|
||||||
|
for (var match in matches.toList()) {
|
||||||
|
urls.add((match as RegExpMatch).group(0).toString());
|
||||||
|
}
|
||||||
|
return urls;
|
||||||
|
}
|
||||||
|
|
||||||
|
String sanitizeEpisodesJs(String doc) {
|
||||||
|
return doc.replaceAll(
|
||||||
|
RegExp(r'(?<=\[|\,)\s*\"\s*(https?://[^\s\"]+)\s*\"\s*(?=\,|\])'), '');
|
||||||
|
}
|
||||||
|
|
||||||
|
List<List<dynamic>> chunked(List<dynamic> list, int size) {
|
||||||
|
List<List<dynamic>> chunks = [];
|
||||||
|
for (int i = 0; i < list.length; i += size) {
|
||||||
|
int end = list.length;
|
||||||
|
if (i + size < list.length) {
|
||||||
|
end = i + size;
|
||||||
|
}
|
||||||
|
chunks.add(list.sublist(i, end));
|
||||||
|
}
|
||||||
|
return chunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<MVideo> sortVideos(List<MVideo> videos, int sourceId) {
|
||||||
|
String quality = getPreferenceValue(sourceId, "preferred_quality");
|
||||||
|
String voice = getPreferenceValue(sourceId, "voices_preference");
|
||||||
|
|
||||||
|
videos.sort((MVideo a, MVideo b) {
|
||||||
|
int qualityMatchA = 0;
|
||||||
|
if (a.quality.contains(quality) &&
|
||||||
|
a.quality.toLowerCase().contains(voice)) {
|
||||||
|
qualityMatchA = 1;
|
||||||
|
}
|
||||||
|
int qualityMatchB = 0;
|
||||||
|
if (b.quality.contains(quality) &&
|
||||||
|
b.quality.toLowerCase().contains(voice)) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimeSama main() {
|
||||||
|
return AnimeSama();
|
||||||
|
}
|
||||||
BIN
anime/src/fr/animesama/icon.png
Normal file
BIN
anime/src/fr/animesama/icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.6 KiB |
17
anime/src/fr/animesama/source.dart
Normal file
17
anime/src/fr/animesama/source.dart
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import '../../../../model/source.dart';
|
||||||
|
|
||||||
|
Source get animesamaSource => _animesama;
|
||||||
|
const animesamaVersion = "0.0.1";
|
||||||
|
const animesamaCodeUrl =
|
||||||
|
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/anime/src/fr/animesama/animesama.dart";
|
||||||
|
Source _animesama = Source(
|
||||||
|
name: "Anime-Sama",
|
||||||
|
baseUrl: "https://anime-sama.fr",
|
||||||
|
lang: "fr",
|
||||||
|
typeSource: "single",
|
||||||
|
iconUrl:
|
||||||
|
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/anime/src/fr/animesama/icon.png",
|
||||||
|
sourceCodeUrl: animesamaCodeUrl,
|
||||||
|
appMinVerReq: "0.1.5",
|
||||||
|
version: animesamaVersion,
|
||||||
|
isManga: false);
|
||||||
@@ -362,7 +362,7 @@ class OtakuFr extends MProvider {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
final masterUrl =
|
final masterUrl =
|
||||||
substringBefore(substringAfter(evalJs(js.first), "{file:\""), "\"}");
|
substringBefore(substringAfter(unpackJs(js.first), "{file:\""), "\"}");
|
||||||
final masterPlaylistRes =
|
final masterPlaylistRes =
|
||||||
await http('GET', json.encode({"url": masterUrl}));
|
await http('GET', json.encode({"url": masterUrl}));
|
||||||
List<MVideo> videos = [];
|
List<MVideo> videos = [];
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ class NimeGami extends MProvider {
|
|||||||
'//script[contains(text(), "eval") and contains(text(), "p,a,c,k,e,d")]/text()');
|
'//script[contains(text(), "eval") and contains(text(), "p,a,c,k,e,d")]/text()');
|
||||||
if (script.isNotEmpty) {
|
if (script.isNotEmpty) {
|
||||||
final videoUrl = substringBefore(
|
final videoUrl = substringBefore(
|
||||||
substringAfter(substringAfter(evalJs(script.first), "sources:[", ""),
|
substringAfter(substringAfter(unpackJs(script.first), "sources:[", ""),
|
||||||
"file\":\"", ""),
|
"file\":\"", ""),
|
||||||
'"');
|
'"');
|
||||||
if (videoUrl.isNotEmpty) {
|
if (videoUrl.isNotEmpty) {
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ class MangaHere extends MProvider {
|
|||||||
res, "//script[contains(text(),'function(p,a,c,k,e,d)')]/text()")
|
res, "//script[contains(text(),'function(p,a,c,k,e,d)')]/text()")
|
||||||
.first
|
.first
|
||||||
.replaceAll("eval", "");
|
.replaceAll("eval", "");
|
||||||
String deobfuscatedScript = evalJs(script);
|
String deobfuscatedScript = unpackJs(script);
|
||||||
int a = deobfuscatedScript.indexOf("newImgs=['") + 10;
|
int a = deobfuscatedScript.indexOf("newImgs=['") + 10;
|
||||||
int b = deobfuscatedScript.indexOf("'];");
|
int b = deobfuscatedScript.indexOf("'];");
|
||||||
List<String> urls = deobfuscatedScript.substring(a, b).split("','");
|
List<String> urls = deobfuscatedScript.substring(a, b).split("','");
|
||||||
@@ -197,7 +197,7 @@ class MangaHere extends MProvider {
|
|||||||
String secretKeyScript = res
|
String secretKeyScript = res
|
||||||
.substring(secretKeyScriptLocation, secretKeyScriptEndLocation)
|
.substring(secretKeyScriptLocation, secretKeyScriptEndLocation)
|
||||||
.replaceAll("eval", "");
|
.replaceAll("eval", "");
|
||||||
String secretKeyDeobfuscatedScript = evalJs(secretKeyScript);
|
String secretKeyDeobfuscatedScript = unpackJs(secretKeyScript);
|
||||||
int secretKeyStartLoc = secretKeyDeobfuscatedScript.indexOf("'");
|
int secretKeyStartLoc = secretKeyDeobfuscatedScript.indexOf("'");
|
||||||
int secretKeyEndLoc = secretKeyDeobfuscatedScript.indexOf(";");
|
int secretKeyEndLoc = secretKeyDeobfuscatedScript.indexOf(";");
|
||||||
|
|
||||||
@@ -231,7 +231,7 @@ class MangaHere extends MProvider {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
String deobfuscatedScript = evalJs(responseText.replaceAll("eval", ""));
|
String deobfuscatedScript = unpackJs(responseText.replaceAll("eval", ""));
|
||||||
|
|
||||||
int baseLinkStartPos = deobfuscatedScript.indexOf("pix=") + 5;
|
int baseLinkStartPos = deobfuscatedScript.indexOf("pix=") + 5;
|
||||||
int baseLinkEndPos =
|
int baseLinkEndPos =
|
||||||
|
|||||||
Reference in New Issue
Block a user