mirror of
https://github.com/kodjodevf/mangayomi-extensions.git
synced 2026-02-14 02:41:39 +00:00
#3 New Anime Extensions (Indonesia)
This commit is contained in:
@@ -9,6 +9,9 @@ import 'src/en/kisskh/source.dart';
|
|||||||
import 'src/fr/animesultra/source.dart';
|
import 'src/fr/animesultra/source.dart';
|
||||||
import 'src/fr/franime/source.dart';
|
import 'src/fr/franime/source.dart';
|
||||||
import 'src/fr/otakufr/source.dart';
|
import 'src/fr/otakufr/source.dart';
|
||||||
|
import 'src/id/nimegami/source.dart';
|
||||||
|
import 'src/id/oploverz/source.dart';
|
||||||
|
import 'src/id/otakudesu/source.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
List<Source> _sourcesList = [
|
List<Source> _sourcesList = [
|
||||||
@@ -18,7 +21,10 @@ void main() {
|
|||||||
animesultraSource,
|
animesultraSource,
|
||||||
...zorothemeSourcesList,
|
...zorothemeSourcesList,
|
||||||
kisskhSource,
|
kisskhSource,
|
||||||
okanimeSource
|
okanimeSource,
|
||||||
|
otakudesu,
|
||||||
|
nimegami,
|
||||||
|
oploverz
|
||||||
];
|
];
|
||||||
final List<Map<String, dynamic>> jsonList =
|
final List<Map<String, dynamic>> jsonList =
|
||||||
_sourcesList.map((source) => source.toJson()).toList();
|
_sourcesList.map((source) => source.toJson()).toList();
|
||||||
|
|||||||
179
anime/src/id/nimegami/nimegami-v0.0.1.dart
Normal file
179
anime/src/id/nimegami/nimegami-v0.0.1.dart
Normal file
@@ -0,0 +1,179 @@
|
|||||||
|
import 'package:mangayomi/bridge_lib.dart';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
class NimeGami extends MProvider {
|
||||||
|
NimeGami();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<MPages> getPopular(MSource source, int page) async {
|
||||||
|
final data = {"url": "${source.baseUrl}/page/$page"};
|
||||||
|
final res = await http('GET', json.encode(data));
|
||||||
|
List<MManga> animeList = [];
|
||||||
|
final urls = xpath(res, '//div[@class="wrapper-2-a"]/article/a/@href');
|
||||||
|
final names = xpath(res, '//div[@class="wrapper-2-a"]/article/a/@title');
|
||||||
|
final images =
|
||||||
|
xpath(res, '//div[@class="wrapper-2-a"]/article/a/div/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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<MPages> getLatestUpdates(MSource source, int page) async {
|
||||||
|
final data = {"url": "${source.baseUrl}/page/$page"};
|
||||||
|
final res = await http('GET', json.encode(data));
|
||||||
|
List<MManga> animeList = [];
|
||||||
|
final urls = xpath(res, '//div[@class="post-article"]/article/div/a/@href');
|
||||||
|
final names =
|
||||||
|
xpath(res, '//div[@class="post-article"]/article/div/a/@title');
|
||||||
|
final images =
|
||||||
|
xpath(res, '//div[@class="post-article"]/article/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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<MPages> search(MSource source, String query, int page) async {
|
||||||
|
final data = {
|
||||||
|
"url": "${source.baseUrl}/page/$page/?s=$query&post_type=post"
|
||||||
|
};
|
||||||
|
final res = await http('GET', json.encode(data));
|
||||||
|
List<MManga> animeList = [];
|
||||||
|
final urls = xpath(res, '//div[@class="archive-a"]/article/div/a/@href');
|
||||||
|
final names = xpath(res, '//div[@class="archive-a"]/article/h2/a/@title');
|
||||||
|
final images =
|
||||||
|
xpath(res, '//div[@class="archive-a"]/article/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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<MManga> getDetail(MSource source, String url) async {
|
||||||
|
final data = {"url": url};
|
||||||
|
final res = await http('GET', json.encode(data));
|
||||||
|
MManga anime = MManga();
|
||||||
|
final description = xpath(res, '//*[@id="Sinopsis"]/p/text()');
|
||||||
|
if (description.isNotEmpty) {
|
||||||
|
anime.description = description.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
final author = xpath(res, '//tbody/tr[5]/td[2]/text()');
|
||||||
|
if (author.isNotEmpty) {
|
||||||
|
anime.author = author.first;
|
||||||
|
}
|
||||||
|
anime.genre = xpath(res, '//tr/td[@class="info_a"]/a/text()');
|
||||||
|
final epUrls = xpath(res, '//div[@class="list_eps_stream"]/li/@data')
|
||||||
|
.reversed
|
||||||
|
.toList();
|
||||||
|
final epNums =
|
||||||
|
xpath(res, '//div[@class="list_eps_stream"]/li/@id').reversed.toList();
|
||||||
|
final names = xpath(res, '//div[@class="list_eps_stream"]/li/text()')
|
||||||
|
.reversed
|
||||||
|
.toList();
|
||||||
|
List<MChapter>? episodesList = [];
|
||||||
|
for (var i = 0; i < epUrls.length; i++) {
|
||||||
|
MChapter episode = MChapter();
|
||||||
|
episode.name = names[i];
|
||||||
|
episode.url = json.encode({
|
||||||
|
"episodeIndex": int.parse(substringAfterLast(epNums[i], '_')),
|
||||||
|
'urls': json.decode(base64(epUrls[i], 0))
|
||||||
|
});
|
||||||
|
episodesList.add(episode);
|
||||||
|
}
|
||||||
|
anime.chapters = episodesList;
|
||||||
|
return anime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<MVideo>> getVideoList(MSource source, String url) async {
|
||||||
|
final resJson = json.decode(url);
|
||||||
|
final urls = resJson["urls"];
|
||||||
|
List<MVideo> videos = [];
|
||||||
|
List<MVideo> a = [];
|
||||||
|
for (var data in urls) {
|
||||||
|
final quality = data["format"];
|
||||||
|
for (var url in data["url"]) {
|
||||||
|
a = await extractVideos(quality, url);
|
||||||
|
videos.addAll(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return videos;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<MVideo>> extractVideos(String quality, String url) async {
|
||||||
|
List<MVideo> videos = [];
|
||||||
|
List<MVideo> a = [];
|
||||||
|
if (url.contains("video.nimegami.id")) {
|
||||||
|
final realUrl =
|
||||||
|
base64(substringBefore(substringAfter(url, "url="), "&"), 0);
|
||||||
|
final a = await extractHXFileVideos(realUrl, quality);
|
||||||
|
videos.addAll(a);
|
||||||
|
} else if (url.contains("berkasdrive") || url.contains("drive.nimegami")) {
|
||||||
|
final res = await http('GET', json.encode({"url": url}));
|
||||||
|
final source = xpath(res, '//source/@src');
|
||||||
|
if (source.isNotEmpty) {
|
||||||
|
videos.add(toVideo(source.first, "Berkasdrive - $quality"));
|
||||||
|
}
|
||||||
|
} else if (url.contains("hxfile.co")) {
|
||||||
|
final a = await extractHXFileVideos(url, quality);
|
||||||
|
videos.addAll(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
return videos;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<List<MVideo>> extractHXFileVideos(String url, String quality) async {
|
||||||
|
if (!url.contains("embed-")) {
|
||||||
|
url = url.replaceAll(".co/", ".co/embed-") + ".html";
|
||||||
|
}
|
||||||
|
final res = await http('GET', json.encode({"url": url}));
|
||||||
|
final script = xpath(res,
|
||||||
|
'//script[contains(text(), "eval") and contains(text(), "p,a,c,k,e,d")]/text()');
|
||||||
|
if (script.isNotEmpty) {
|
||||||
|
final videoUrl = substringBefore(
|
||||||
|
substringAfter(substringAfter(evalJs(script.first), "sources:[", ""),
|
||||||
|
"file\":\"", ""),
|
||||||
|
'"');
|
||||||
|
if (videoUrl.isNotEmpty) {
|
||||||
|
return [toVideo(videoUrl, "HXFile - $quality")];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
MVideo toVideo(String videoUrl, String quality) {
|
||||||
|
MVideo video = MVideo();
|
||||||
|
video
|
||||||
|
..url = videoUrl
|
||||||
|
..originalUrl = videoUrl
|
||||||
|
..quality = quality
|
||||||
|
..subtitles = [];
|
||||||
|
|
||||||
|
return video;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NimeGami main() {
|
||||||
|
return NimeGami();
|
||||||
|
}
|
||||||
17
anime/src/id/nimegami/source.dart
Normal file
17
anime/src/id/nimegami/source.dart
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import '../../../../model/source.dart';
|
||||||
|
import '../../../../utils/utils.dart';
|
||||||
|
|
||||||
|
Source get nimegami => _nimegami;
|
||||||
|
const nimegamiVersion = "0.0.1";
|
||||||
|
const nimegamiCodeUrl =
|
||||||
|
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/src/id/nimegami/nimegami-v$nimegamiVersion.dart";
|
||||||
|
Source _nimegami = Source(
|
||||||
|
name: "NimeGami",
|
||||||
|
baseUrl: "https://nimegami.id",
|
||||||
|
lang: "id",
|
||||||
|
typeSource: "single",
|
||||||
|
iconUrl: getIconUrl("nimegami", "id"),
|
||||||
|
sourceCodeUrl: nimegamiCodeUrl,
|
||||||
|
version: nimegamiVersion,
|
||||||
|
appMinVerReq: "0.0.7",
|
||||||
|
isManga: false);
|
||||||
157
anime/src/id/oploverz/oploverz-v0.0.1.dart
Normal file
157
anime/src/id/oploverz/oploverz-v0.0.1.dart
Normal file
@@ -0,0 +1,157 @@
|
|||||||
|
import 'package:mangayomi/bridge_lib.dart';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
class OploVerz extends MProvider {
|
||||||
|
OploVerz();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<MPages> getPopular(MSource source, int page) async {
|
||||||
|
final data = {
|
||||||
|
"url": "${source.baseUrl}/anime-list/page/$page/?order=popular"
|
||||||
|
};
|
||||||
|
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}/anime-list/page/$page/?order=latest"
|
||||||
|
};
|
||||||
|
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}/anime-list/page/$page/?title=$query"
|
||||||
|
};
|
||||||
|
final res = await http('GET', json.encode(data));
|
||||||
|
return parseAnimeList(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<MManga> getDetail(MSource source, String url) async {
|
||||||
|
final statusList = [
|
||||||
|
{"ongoing": 0, "completed": 1}
|
||||||
|
];
|
||||||
|
final data = {"url": url};
|
||||||
|
final res = await http('GET', json.encode(data));
|
||||||
|
MManga anime = MManga();
|
||||||
|
final status = xpath(res, '//*[@class="alternati"]/span[2]/text()');
|
||||||
|
print(status);
|
||||||
|
if (status.isNotEmpty) {
|
||||||
|
anime.status = parseStatus(status.first, statusList);
|
||||||
|
}
|
||||||
|
anime.description = xpath(res, '//*[@class="desc"]/div/text()').first;
|
||||||
|
|
||||||
|
anime.genre = xpath(res, '//*[@class="genre-info"]/a/text()');
|
||||||
|
final epUrls =
|
||||||
|
xpath(res, '//div[@class="epsleft")]/span[@class="lchx"]/a/@href');
|
||||||
|
final names =
|
||||||
|
xpath(res, '//div[@class="epsleft")]/span[@class="lchx"]/a/text()');
|
||||||
|
final dates =
|
||||||
|
xpath(res, '//div[@class="epsleft")]/span[@class="date"]/text()');
|
||||||
|
final dateUploads = parseDates(dates, "dd/MM/yyyy", "id");
|
||||||
|
List<MChapter>? episodesList = [];
|
||||||
|
for (var i = 0; i < epUrls.length; i++) {
|
||||||
|
MChapter episode = MChapter();
|
||||||
|
episode.name = names[i];
|
||||||
|
episode.dateUpload = dateUploads[i];
|
||||||
|
episode.url = epUrls[i];
|
||||||
|
episodesList.add(episode);
|
||||||
|
}
|
||||||
|
|
||||||
|
anime.chapters = episodesList;
|
||||||
|
return anime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<MVideo>> getVideoList(MSource source, String url) async {
|
||||||
|
final res = await http('GET', json.encode({"url": url}));
|
||||||
|
final dataPost = xpath(res,
|
||||||
|
'//*[@id="server"]/ul/li/div[contains(@id,"player-option")]/@data-post')
|
||||||
|
.first;
|
||||||
|
final dataNume = xpath(res,
|
||||||
|
'//*[@id="server"]/ul/li/div[contains(@id,"player-option")]/@data-nume')
|
||||||
|
.first;
|
||||||
|
final dataType = xpath(res,
|
||||||
|
'//*[@id="server"]/ul/li/div[contains(@id,"player-option")]/@data-type')
|
||||||
|
.first;
|
||||||
|
final body = {
|
||||||
|
"action": "player_ajax",
|
||||||
|
"post": dataPost,
|
||||||
|
"nume": dataNume,
|
||||||
|
"type": dataType
|
||||||
|
};
|
||||||
|
|
||||||
|
final ress = await http(
|
||||||
|
'POST',
|
||||||
|
json.encode({
|
||||||
|
"useFormBuilder": true,
|
||||||
|
"body": body,
|
||||||
|
"url": "${source.baseUrl}/wp-admin/admin-ajax.php"
|
||||||
|
}));
|
||||||
|
final playerLink =
|
||||||
|
xpath(ress, '//iframe[@class="playeriframe"]/@src').first;
|
||||||
|
print(playerLink);
|
||||||
|
final resPlayer = await http('GET', json.encode({"url": playerLink}));
|
||||||
|
var resJson = substringBefore(substringAfter(resPlayer, "= "), "<");
|
||||||
|
var streams = json.decode(resJson)["streams"] as List;
|
||||||
|
List<MVideo> videos = [];
|
||||||
|
for (var stream in streams) {
|
||||||
|
print(stream["play_url"]);
|
||||||
|
final videoUrl = stream["play_url"];
|
||||||
|
final quality = getQuality(stream["format_id"]);
|
||||||
|
|
||||||
|
MVideo video = MVideo();
|
||||||
|
video
|
||||||
|
..url = videoUrl
|
||||||
|
..originalUrl = videoUrl
|
||||||
|
..quality = quality
|
||||||
|
..subtitles = [];
|
||||||
|
videos.add(video);
|
||||||
|
}
|
||||||
|
|
||||||
|
return videos;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getQuality(int formatId) {
|
||||||
|
if (formatId == 18) {
|
||||||
|
return "Google - 360p";
|
||||||
|
} else if (formatId == 22) {
|
||||||
|
return "Google - 720p";
|
||||||
|
}
|
||||||
|
return "Unknown Resolution";
|
||||||
|
}
|
||||||
|
|
||||||
|
MPages parseAnimeList(String res) {
|
||||||
|
List<MManga> animeList = [];
|
||||||
|
final urls = xpath(res, '//div[@class="relat"]/article/div/div/a/@href');
|
||||||
|
final names = xpath(res, '//div[@class="relat"]/article/div/div/a/@title');
|
||||||
|
final images =
|
||||||
|
xpath(res, '//div[@class="relat"]/article/div/div/a/div/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);
|
||||||
|
}
|
||||||
|
final pages = xpath(res, '//div[@class="pagination"]/a/@href');
|
||||||
|
final pageNumberCurrent = xpath(res,
|
||||||
|
'//div[@class="pagination"]/span[@class="page-numbers current"]/text()');
|
||||||
|
|
||||||
|
bool hasNextPage = true;
|
||||||
|
if (pageNumberCurrent.isNotEmpty && pages.isNotEmpty) {
|
||||||
|
hasNextPage = !(pages.length == int.parse(pageNumberCurrent.first));
|
||||||
|
}
|
||||||
|
return MPages(animeList, hasNextPage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OploVerz main() {
|
||||||
|
return OploVerz();
|
||||||
|
}
|
||||||
17
anime/src/id/oploverz/source.dart
Normal file
17
anime/src/id/oploverz/source.dart
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import '../../../../model/source.dart';
|
||||||
|
import '../../../../utils/utils.dart';
|
||||||
|
|
||||||
|
Source get oploverz => _oploverz;
|
||||||
|
const oploverzVersion = "0.0.1";
|
||||||
|
const oploverzCodeUrl =
|
||||||
|
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/src/id/oploverz/oploverz-v$oploverzVersion.dart";
|
||||||
|
Source _oploverz = Source(
|
||||||
|
name: "Oploverz",
|
||||||
|
baseUrl: "https://oploverz.red",
|
||||||
|
lang: "id",
|
||||||
|
typeSource: "single",
|
||||||
|
iconUrl: getIconUrl("oploverz", "id"),
|
||||||
|
sourceCodeUrl: oploverzCodeUrl,
|
||||||
|
version: oploverzVersion,
|
||||||
|
appMinVerReq: "0.0.7",
|
||||||
|
isManga: false);
|
||||||
184
anime/src/id/otakudesu/otakudesu-v0.0.1.dart
Normal file
184
anime/src/id/otakudesu/otakudesu-v0.0.1.dart
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
import 'package:mangayomi/bridge_lib.dart';
|
||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
class OtakuDesu extends MProvider {
|
||||||
|
OtakuDesu();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<MPages> getPopular(MSource source, int page) async {
|
||||||
|
final data = {"url": "${source.baseUrl}/complete-anime/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}/ongoing-anime/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}/?s=$query&post_type=anime"};
|
||||||
|
final res = await http('GET', json.encode(data));
|
||||||
|
List<MManga> animeList = [];
|
||||||
|
final images = xpath(res, '//ul[@class="chivsrc"]/li/img/@src');
|
||||||
|
final names = xpath(res, '//ul[@class="chivsrc"]/li/h2/a/text()');
|
||||||
|
final urls = xpath(res, '//ul[@class="chivsrc"]/li/h2/a/@href');
|
||||||
|
|
||||||
|
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, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<MManga> getDetail(MSource source, String url) async {
|
||||||
|
final statusList = [
|
||||||
|
{"Ongoing": 0, "Completed": 1}
|
||||||
|
];
|
||||||
|
final data = {"url": url};
|
||||||
|
final res = await http('GET', json.encode(data));
|
||||||
|
MManga anime = MManga();
|
||||||
|
final status = xpath(
|
||||||
|
res, '//*[@class="infozingle"]/p[contains(text(), "Status")]/text()');
|
||||||
|
if (status.isNotEmpty) {
|
||||||
|
anime.status = parseStatus(status.first.split(':').last, statusList);
|
||||||
|
}
|
||||||
|
final description = xpath(res, '//*[@class="sinopc"]/text()');
|
||||||
|
if (description.isNotEmpty) {
|
||||||
|
anime.description = description.first;
|
||||||
|
}
|
||||||
|
|
||||||
|
final genre = xpath(
|
||||||
|
res, '//*[@class="infozingle"]/p[contains(text(), "Genre")]/text()');
|
||||||
|
if (genre.isNotEmpty) {
|
||||||
|
anime.genre = genre.first.split(':').last.split(',');
|
||||||
|
}
|
||||||
|
|
||||||
|
final epUrls = xpath(res, '//div[@class="episodelist"]/ul/li/span/a/@href');
|
||||||
|
final names = xpath(res, '//div[@class="episodelist"]/ul/li/span/a/text()');
|
||||||
|
|
||||||
|
final dates = xpath(
|
||||||
|
res, '//div[@class="episodelist"]/ul/li/span[@class="zeebr"]/text()');
|
||||||
|
final dateUploads = parseDates(dates, "d MMMM,yyyy", "id");
|
||||||
|
List<MChapter>? episodesList = [];
|
||||||
|
for (var i = 1; i < epUrls.length; i++) {
|
||||||
|
MChapter episode = MChapter();
|
||||||
|
episode.name = names[i];
|
||||||
|
episode.dateUpload = dateUploads[i];
|
||||||
|
episode.url = epUrls[i];
|
||||||
|
episodesList.add(episode);
|
||||||
|
}
|
||||||
|
anime.chapters = episodesList;
|
||||||
|
return anime;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<List<MVideo>> getVideoList(MSource source, String url) async {
|
||||||
|
List<MVideo> videos = [];
|
||||||
|
final res = await http('GET', json.encode({"url": url}));
|
||||||
|
final script =
|
||||||
|
xpath(res, '//script[contains(text(), "{action:")]/text()').first;
|
||||||
|
final nonceAction =
|
||||||
|
substringBefore(substringAfter(script, "{action:\""), '"');
|
||||||
|
final action = substringBefore(substringAfter(script, "action:\""), '"');
|
||||||
|
|
||||||
|
final resNonceAction = await http(
|
||||||
|
'POST',
|
||||||
|
json.encode({
|
||||||
|
"useFormBuilder": true,
|
||||||
|
"body": {"action": nonceAction},
|
||||||
|
"url": "${source.baseUrl}/wp-admin/admin-ajax.php"
|
||||||
|
}));
|
||||||
|
final nonce = substringBefore(substringAfter(resNonceAction, ":\""), '"');
|
||||||
|
final mirrorstream =
|
||||||
|
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 q = decodedData["q"];
|
||||||
|
final id = decodedData["id"];
|
||||||
|
final i = decodedData["i"];
|
||||||
|
final body = {"i": i, "id": id, "q": q, "nonce": nonce, "action": action};
|
||||||
|
|
||||||
|
final res = await http(
|
||||||
|
'POST',
|
||||||
|
json.encode({
|
||||||
|
"useFormBuilder": true,
|
||||||
|
"body": body,
|
||||||
|
"url": "${source.baseUrl}/wp-admin/admin-ajax.php"
|
||||||
|
}));
|
||||||
|
final html = base64(substringBefore(substringAfter(res, ":\""), '"'), 0);
|
||||||
|
final url = xpath(html, '//iframe/@src').first;
|
||||||
|
|
||||||
|
if (url.contains("yourupload")) {
|
||||||
|
final id = substringBefore(substringAfter(url, "id="), "&");
|
||||||
|
url = "https://yourupload.com/embed/$id";
|
||||||
|
a = await yourUploadExtractor(url, null, "YourUpload - $q", null);
|
||||||
|
} else if (url.contains("filelions")) {
|
||||||
|
a = await streamWishExtractor(url, "FileLions");
|
||||||
|
} else if (url.contains("desustream")) {
|
||||||
|
final res = await http('GET', json.encode({"url": url}));
|
||||||
|
final script =
|
||||||
|
xpath(res, '//script[contains(text(), "sources")]/text()').first;
|
||||||
|
final videoUrl = substringBefore(
|
||||||
|
substringAfter(substringAfter(script, "sources:[{"), "file':'"),
|
||||||
|
"'");
|
||||||
|
MVideo video = MVideo();
|
||||||
|
video
|
||||||
|
..url = videoUrl
|
||||||
|
..originalUrl = videoUrl
|
||||||
|
..quality = "DesuStream - $q"
|
||||||
|
..subtitles = [];
|
||||||
|
videos.add(video);
|
||||||
|
} else if (url.contains("mp4upload")) {
|
||||||
|
final res = await http('GET', json.encode({"url": url}));
|
||||||
|
final script =
|
||||||
|
xpath(res, '//script[contains(text(), "player.src")]/text()').first;
|
||||||
|
final videoUrl =
|
||||||
|
substringBefore(substringAfter(script, "src: \""), '"');
|
||||||
|
MVideo video = MVideo();
|
||||||
|
video
|
||||||
|
..url = videoUrl
|
||||||
|
..originalUrl = videoUrl
|
||||||
|
..quality = "Mp4upload - $q"
|
||||||
|
..subtitles = [];
|
||||||
|
videos.add(video);
|
||||||
|
}
|
||||||
|
videos.addAll(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
return videos;
|
||||||
|
}
|
||||||
|
|
||||||
|
MPages parseAnimeList(String res) {
|
||||||
|
List<MManga> animeList = [];
|
||||||
|
final urls =
|
||||||
|
xpath(res, '//div[@class="detpost"]/div[@class="thumb"]/a/@href');
|
||||||
|
final names = xpath(res,
|
||||||
|
'//div[@class="detpost"]/div[@class="thumb"]/a/div[@class="thumbz"]/h2/text()');
|
||||||
|
final images = xpath(res,
|
||||||
|
'//div[@class="detpost"]/div[@class="thumb"]/a/div[@class="thumbz"]/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);
|
||||||
|
}
|
||||||
|
final pages = xpath(
|
||||||
|
res, '//div[@class="pagenavix"]/a[@class="next page-numbers"]/@href');
|
||||||
|
return MPages(animeList, pages.isNotEmpty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
OtakuDesu main() {
|
||||||
|
return OtakuDesu();
|
||||||
|
}
|
||||||
17
anime/src/id/otakudesu/source.dart
Normal file
17
anime/src/id/otakudesu/source.dart
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import '../../../../model/source.dart';
|
||||||
|
import '../../../../utils/utils.dart';
|
||||||
|
|
||||||
|
Source get otakudesu => _otakudesu;
|
||||||
|
const otakudesuVersion = "0.0.1";
|
||||||
|
const otakudesuCodeUrl =
|
||||||
|
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/anime/src/id/otakudesu/otakudesu-v$otakudesuVersion.dart";
|
||||||
|
Source _otakudesu = Source(
|
||||||
|
name: "OtakuDesu",
|
||||||
|
baseUrl: "https://otakudesu.cam",
|
||||||
|
lang: "id",
|
||||||
|
typeSource: "single",
|
||||||
|
iconUrl: getIconUrl("otakudesu", "id"),
|
||||||
|
sourceCodeUrl: otakudesuCodeUrl,
|
||||||
|
version: otakudesuVersion,
|
||||||
|
appMinVerReq: "0.0.7",
|
||||||
|
isManga: false);
|
||||||
BIN
icons/mangayomi-id-nimegami.png
Normal file
BIN
icons/mangayomi-id-nimegami.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.6 KiB |
BIN
icons/mangayomi-id.oploverz.png
Normal file
BIN
icons/mangayomi-id.oploverz.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
BIN
icons/mangayomi-id.otakudesu.png
Normal file
BIN
icons/mangayomi-id.otakudesu.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.3 KiB |
Reference in New Issue
Block a user