New source Aniwave (EN)

This commit is contained in:
kodjomoustapha
2023-11-17 18:56:08 +01:00
parent cc3a077c4e
commit f4703303f4
8 changed files with 272 additions and 10 deletions

View File

@@ -4,6 +4,7 @@ import 'dart:io';
import '../model/source.dart';
import 'multisrc/zorotheme/sources.dart';
import 'src/ar/okanime/source.dart';
import 'src/en/aniwave/source.dart';
import 'src/en/gogoanime/source.dart';
import 'src/en/kisskh/source.dart';
import 'src/fr/animesultra/source.dart';
@@ -24,7 +25,8 @@ void main() {
okanimeSource,
otakudesu,
nimegami,
oploverz
oploverz,
aniwave
];
final List<Map<String, dynamic>> jsonList =
_sourcesList.map((source) => source.toJson()).toList();

View File

@@ -0,0 +1,242 @@
import 'package:mangayomi/bridge_lib.dart';
import 'dart:convert';
class Aniwave extends MProvider {
Aniwave();
@override
Future<MPages> getPopular(MSource source, int page) async {
final data = {"url": "${source.baseUrl}/filter?sort=trending&page=$page"};
final res = await http('GET', json.encode(data));
return parseAnimeList(res);
}
@override
Future<MPages> getLatestUpdates(MSource source, int page) async {
final data = {
"url": "${source.baseUrl}/filter?sort=recently_updated&page=$page"
};
final res = await http('GET', json.encode(data));
return parseAnimeList(res);
}
@override
Future<MPages> search(MSource source, String query, int page) async {
final data = {"url": "${source.baseUrl}/filter?keyword=$query"};
final res = await http('GET', json.encode(data));
return parseAnimeList(res);
}
@override
Future<MManga> getDetail(MSource source, String url) async {
final statusList = [
{"Releasing": 0, "Completed": 1}
];
final data = {"url": "${source.baseUrl}${url}"};
final res = await http('GET', json.encode(data));
MManga anime = MManga();
final status = xpath(res, '//div[contains(text(),"Status")]/span/text()');
if (status.isNotEmpty) {
anime.status = parseStatus(status.first, statusList);
}
final description = xpath(res,
'//*[contains(@class,"synopsis")]/div[@class="shorting"]/div[@class="content"]/text()');
if (description.isNotEmpty) {
anime.description = description.first;
}
final author = xpath(res, '//div[contains(text(),"Studio")]/span/text()');
if (author.isNotEmpty) {
anime.author = author.first;
}
anime.genre = xpath(res, '//div[contains(text(),"Genre")]/span/a/text()');
final id = querySelectorAll(res,
selector: "div[data-id]",
typeElement: 3,
attributes: "data-id",
typeRegExp: 0)
.first;
final encrypt = vrfEncrypt(id);
final vrf = "vrf=${Uri.encodeComponent(encrypt)}";
final dataEp = {"url": "${source.baseUrl}/ajax/episode/list/$id?$vrf"};
final resEp = await http('GET', json.encode(dataEp));
final html = json.decode(resEp)["result"];
List<MChapter>? episodesList = [];
final epsHtml = querySelectorAll(html,
selector: "div.episodes ul > li",
typeElement: 2,
attributes: "",
typeRegExp: 0);
for (var epHtml in epsHtml) {
final title = xpath(epHtml, '//li/@title').isNotEmpty
? xpath(epHtml, '//li/@title').first
: "";
final ids = xpath(epHtml, '//a/@data-ids').first;
final sub = xpath(epHtml, '//a/@data-sub').first;
final dub = xpath(epHtml, '//a/@data-dub').first;
final softsub = title.toLowerCase().contains("softsub") ? "1" : "";
final fillerEp = title.toLowerCase().contains("filler") ? "1" : "";
final epNum = xpath(epHtml, '//a/@data-num').first;
String scanlator = "";
if (sub == "1") {
scanlator += "Sub";
}
if (softsub == "1") {
scanlator += ", Softsub";
}
if (dub == "1") {
scanlator += ", Dub";
}
if (fillerEp == "1") {
scanlator += ", • Filler Episode";
}
MChapter episode = MChapter();
episode.name = "Episode $epNum";
episode.scanlator = scanlator;
episode.url = "$ids&epurl=$url/ep-$epNum";
episodesList.add(episode);
}
anime.chapters = episodesList.reversed.toList();
return anime;
}
@override
Future<List<MVideo>> getVideoList(MSource source, String url) async {
final ids = substringBefore(url, "&");
final encrypt = vrfEncrypt(ids);
final vrf = "vrf=${Uri.encodeComponent(encrypt)}";
final res = await http('GET',
json.encode({"url": "${source.baseUrl}/ajax/server/list/$ids?$vrf"}));
final html = json.decode(res)["result"];
final vidsHtml = querySelectorAll(html,
selector: "div.servers > div",
typeElement: 2,
attributes: "",
typeRegExp: 0);
List<MVideo> videos = [];
for (var vidHtml in vidsHtml) {
final type = xpath(vidHtml, '//div/@data-type').first;
final serversIds = xpath(vidHtml, '//li/@data-link-id');
for (int i = 0; i < serversIds.length; i++) {
final serverId = serversIds[i];
final encrypt = vrfEncrypt(serverId);
final vrf = "vrf=${Uri.encodeComponent(encrypt)}";
final res = await http(
'GET',
json.encode(
{"url": "${source.baseUrl}/ajax/server/$serverId?$vrf"}));
final status = json.decode(res)["status"];
if (status == 200) {
List<MVideo> a = [];
final url = vrfDecrypt(json.decode(res)["result"]["url"]);
if (url.contains("mp4upload")) {
a = await mp4UploadExtractor(url, null, "", type);
} else if (url.contains("streamtape")) {
a = await streamTapeExtractor(url, "StreamTape - $type");
} else if (url.contains("filemoon")) {
a = await filemoonExtractor(url, "", type);
}
videos.addAll(a);
}
}
}
return videos;
}
MPages parseAnimeList(String res) {
List<MManga> animeList = [];
final urls = xpath(res, '//div[@class="item "]/div/div/div/a/@href');
final names = xpath(res, '//div[@class="item "]/div/div/div/a/text()');
final images = xpath(res, '//div[@class="item "]/div/div/a/img/@src');
for (var i = 0; i < names.length; i++) {
MManga anime = MManga();
anime.name = names[i];
anime.imageUrl = images[i];
anime.link = urls[i];
animeList.add(anime);
}
return MPages(animeList, true);
}
List<int> rc4Encrypt(String key, List<int> message) {
List<int> _key = utf8.encode(key);
int _i = 0, _j = 0;
List<int> _box = List.generate(256, (i) => i);
int x = 0;
for (int i = 0; i < 256; i++) {
x = (x + _box[i] + _key[i % _key.length]) % 256;
var tmp = _box[i];
_box[i] = _box[x];
_box[x] = tmp;
}
List<int> out = [];
for (var char in message) {
_i = (_i + 1) % 256;
_j = (_j + _box[_i]) % 256;
var tmp = _box[_i];
_box[_i] = _box[_j];
_box[_j] = tmp;
final c = char ^ (_box[(_box[_i] + _box[_j]) % 256]);
out.add(c);
}
return out;
}
String vrfEncrypt(String input) {
final rc4 = rc4Encrypt("ysJhV6U27FVIjjuk", input.codeUnits);
final vrf = base64Url.encode(rc4);
final vrf1 = base64.encode(vrf.codeUnits);
List<int> vrf2 = vrfShift(vrf1.codeUnits);
final vrf3 = base64.encode(vrf2);
return utf8.decode(rot13(vrf3.codeUnits));
}
String vrfDecrypt(String input) {
final decode = base64Url.decode(input);
final rc4 = rc4Encrypt("hlPeNwkncH0fq9so", decode);
return Uri.decodeComponent(utf8.decode(rc4));
}
List<int> vrfShift(List<int> vrf) {
var shifts = [-3, 3, -4, 2, -2, 5, 4, 5];
for (var i = 0; i < vrf.length; i++) {
var shift = shifts[i % 8];
vrf[i] = (vrf[i] + shift) & 0xFF;
}
return vrf;
}
List<int> rot13(List<int> vrf) {
for (var i = 0; i < vrf.length; i++) {
var byte = vrf[i];
if (byte >= 'A'.codeUnitAt(0) && byte <= 'Z'.codeUnitAt(0)) {
vrf[i] = (byte - 'A'.codeUnitAt(0) + 13) % 26 + 'A'.codeUnitAt(0);
} else if (byte >= 'a'.codeUnitAt(0) && byte <= 'z'.codeUnitAt(0)) {
vrf[i] = (byte - 'a'.codeUnitAt(0) + 13) % 26 + 'a'.codeUnitAt(0);
}
}
return vrf;
}
}
Map<String, String> getMirrorPref() {
return {
"aniwave.to": "https://aniwave.to",
"aniwave.bz": "https://aniwave.bz",
"aniwave.ws": "https://aniwave.ws",
};
}
Aniwave main() {
return Aniwave();
}

View File

@@ -0,0 +1,17 @@
import '../../../../model/source.dart';
import '../../../../utils/utils.dart';
Source get aniwave => _aniwave;
const aniwaveVersion = "0.0.1";
const aniwaveCodeUrl =
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/src/en/aniwave/aniwave-v$aniwaveVersion.dart";
Source _aniwave = Source(
name: "Aniwave",
baseUrl: "https://aniwave.to",
lang: "en",
typeSource: "single",
iconUrl: getIconUrl("aniwave", "en"),
sourceCodeUrl: aniwaveCodeUrl,
version: aniwaveVersion,
appMinVerReq: "0.0.8",
isManga: false);

View File

@@ -96,7 +96,7 @@ class NimeGami extends MProvider {
episode.name = names[i];
episode.url = json.encode({
"episodeIndex": int.parse(substringAfterLast(epNums[i], '_')),
'urls': json.decode(base64(epUrls[i], 0))
'urls': json.decode(utf8.decode(base64Url.decode(epUrls[i])))
});
episodesList.add(episode);
}
@@ -124,8 +124,8 @@ class NimeGami extends MProvider {
List<MVideo> videos = [];
List<MVideo> a = [];
if (url.contains("video.nimegami.id")) {
final realUrl =
base64(substringBefore(substringAfter(url, "url="), "&"), 0);
final realUrl = utf8.decode(
base64Url.decode(substringBefore(substringAfter(url, "url="), "&")));
final a = await extractHXFileVideos(realUrl, quality);
videos.addAll(a);
} else if (url.contains("berkasdrive") || url.contains("drive.nimegami")) {

View File

@@ -2,7 +2,7 @@ import '../../../../model/source.dart';
import '../../../../utils/utils.dart';
Source get nimegami => _nimegami;
const nimegamiVersion = "0.0.1";
const nimegamiVersion = "0.0.2";
const nimegamiCodeUrl =
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/src/id/nimegami/nimegami-v$nimegamiVersion.dart";
Source _nimegami = Source(
@@ -13,5 +13,5 @@ Source _nimegami = Source(
iconUrl: getIconUrl("nimegami", "id"),
sourceCodeUrl: nimegamiCodeUrl,
version: nimegamiVersion,
appMinVerReq: "0.0.7",
appMinVerReq: "0.0.8",
isManga: false);

View File

@@ -101,7 +101,7 @@ class OtakuDesu extends MProvider {
xpath(res, '//*[@class="mirrorstream"]/ul/li/a/@data-content');
for (var stream in mirrorstream) {
List<MVideo> a = [];
final decodedData = json.decode(base64(stream, 0));
final decodedData = json.decode(utf8.decode(base64Url.decode(stream)));
final q = decodedData["q"];
final id = decodedData["id"];
final i = decodedData["i"];
@@ -114,7 +114,8 @@ class OtakuDesu extends MProvider {
"body": body,
"url": "${source.baseUrl}/wp-admin/admin-ajax.php"
}));
final html = base64(substringBefore(substringAfter(res, ":\""), '"'), 0);
final html = utf8.decode(
base64Url.decode(substringBefore(substringAfter(res, ":\""), '"')));
final url = xpath(html, '//iframe/@src').first;
if (url.contains("yourupload")) {

View File

@@ -2,7 +2,7 @@ import '../../../../model/source.dart';
import '../../../../utils/utils.dart';
Source get otakudesu => _otakudesu;
const otakudesuVersion = "0.0.1";
const otakudesuVersion = "0.0.2";
const otakudesuCodeUrl =
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/src/id/otakudesu/otakudesu-v$otakudesuVersion.dart";
Source _otakudesu = Source(
@@ -13,5 +13,5 @@ Source _otakudesu = Source(
iconUrl: getIconUrl("otakudesu", "id"),
sourceCodeUrl: otakudesuCodeUrl,
version: otakudesuVersion,
appMinVerReq: "0.0.7",
appMinVerReq: "0.0.8",
isManga: false);