Merge pull request #297 from xMohnad/anime/nyaa

Anime/nyaa
This commit is contained in:
Moustapha Kodjo Amadou
2025-06-26 06:01:02 +01:00
committed by GitHub
2 changed files with 111 additions and 42 deletions

View File

@@ -9,23 +9,21 @@ class Nyaa extends MProvider {
@override @override
Future<MPages> getPopular(int page) async { Future<MPages> getPopular(int page) async {
final res = final res = (await client.get(
(await client.get( Uri.parse(
Uri.parse( "${getBaseUrl()}/?f=0&c=${getPreferenceValue(source.id, "preferred_categorie_page")}&q=&s=downloads&o=desc&p=$page",
"${source.baseUrl}/?f=0&c=${getPreferenceValue(source.id, "preferred_categorie_page")}&q=&s=downloads&o=desc&p=$page", ),
), )).body;
)).body;
return parseAnimeList(res); return parseAnimeList(res);
} }
@override @override
Future<MPages> getLatestUpdates(int page) async { Future<MPages> getLatestUpdates(int page) async {
final res = final res = (await client.get(
(await client.get( Uri.parse(
Uri.parse( "${getBaseUrl()}/?f=0&c=${getPreferenceValue(source.id, "preferred_categorie_page")}&q=$page",
"${source.baseUrl}/?f=0&c=${getPreferenceValue(source.id, "preferred_categorie_page")}&q=$page", ),
), )).body;
)).body;
return parseAnimeList(res); return parseAnimeList(res);
} }
@@ -34,7 +32,7 @@ class Nyaa extends MProvider {
final filters = filterList.filters; final filters = filterList.filters;
String url = ""; String url = "";
url = url =
"${source.baseUrl}/?f=0&c=${getPreferenceValue(source.id, "preferred_categorie_page")}&q=${query.replaceAll(" ", "+")}&p=$page"; "${getBaseUrl()}/?f=0&c=${getPreferenceValue(source.id, "preferred_categorie_page")}&q=${query.replaceAll(" ", "+")}&p=$page";
for (var filter in filters) { for (var filter in filters) {
if (filter.type == "SortFilter") { if (filter.type == "SortFilter") {
url += "${ll(url)}s=${filter.values[filter.state.index].value}"; url += "${ll(url)}s=${filter.values[filter.state.index].value}";
@@ -46,22 +44,68 @@ class Nyaa extends MProvider {
return parseAnimeList(res); return parseAnimeList(res);
} }
String extractPanelBody(MDocument document) {
final panelBody = document.selectFirst('.panel-body');
if (panelBody == null) return "";
final rows = panelBody.select('.row');
final Map<String, String> info = {};
for (var row in rows) {
final labels = row.select('.col-md-1');
for (var label in labels) {
final key = label.text.replaceAll(":", "").trim();
final valueDiv = label.nextElementSibling;
if (valueDiv == null) continue;
final links = valueDiv.select('a');
String value;
if (links.isNotEmpty) {
value = links.map((a) => a.text.trim()).join(' - ');
} else {
value = valueDiv.text.trim();
}
info[key] = value;
}
}
final buffer = StringBuffer();
buffer.writeln("Torrent Info:\n");
info.forEach((k, v) {
buffer.writeln("${k.padRight(11)}: $v");
});
if (getPreferenceValue(source.id, "torrent_description_visible")) {
buffer.writeln("\n\n");
buffer.writeln("Torrent Description: \n");
buffer.writeln(
document
.select("#torrent-description")
.map((e) => e.text.trim())
.join("\n\n"),
);
}
return buffer.toString();
}
@override @override
Future<MManga> getDetail(String url) async { Future<MManga> getDetail(String url) async {
MManga anime = MManga(); MManga anime = MManga();
final res = (await client.get(Uri.parse(url))).body; final res = (await client.get(Uri.parse(url))).body;
final document = parseHtml(res); final document = parseHtml(res);
String description =
(document.xpathFirst('//div[@class="panel-body"]/text()') ?? "") anime.description = extractPanelBody(document);
.replaceAll("\n", "");
description += List<MChapter> chapters = [];
"\n\n${(document.xpathFirst('//div[@class="panel panel-default"]/text()') ?? "").trim().replaceAll("\n", "")}"; chapters.add(
anime.description = description; MChapter(
MChapter ep = MChapter(); name: "Torrent",
ep.name = "Torrent"; url: "${getBaseUrl()}/download/${substringAfterLast(url, '/')}.torrent",
ep.url = ),
"${source.baseUrl}/download/${substringAfterLast(url, '/')}.torrent"; );
anime.chapters = [ep]; anime.chapters = chapters;
return anime; return anime;
} }
@@ -100,9 +144,36 @@ class Nyaa extends MProvider {
entries: ["Anime", "Live Action"], entries: ["Anime", "Live Action"],
entryValues: ["1_0", "4_0"], entryValues: ["1_0", "4_0"],
), ),
SwitchPreferenceCompat(
key: "torrent_description_visible",
title: "Display Torrent Description",
summary:
"Enable to show the full torrent description in the details view.",
value: false,
),
EditTextPreference(
key: "domain_url",
title: 'Edit URL',
summary: "",
value: source.baseUrl,
dialogTitle: "URL",
dialogMessage: "",
),
]; ];
} }
String getBaseUrl() {
final baseUrl = getPreferenceValue(source.id, "domain_url")?.trim();
if (baseUrl == null || baseUrl.isEmpty) {
return source.baseUrl;
}
return baseUrl.endsWith("/")
? baseUrl.substring(0, baseUrl.length - 1)
: baseUrl;
}
MPages parseAnimeList(String res) { MPages parseAnimeList(String res) {
List<MManga> animeList = []; List<MManga> animeList = [];
final document = parseHtml(res); final document = parseHtml(res);
@@ -113,28 +184,26 @@ class Nyaa extends MProvider {
for (var value in values) { for (var value in values) {
MManga anime = MManga(); MManga anime = MManga();
anime.imageUrl = anime.imageUrl =
"${source.baseUrl}${getUrlWithoutDomain(value.selectFirst("td:nth-child(1) > a > img").getSrc)}"; "${getBaseUrl()}${getUrlWithoutDomain(value.selectFirst("td:nth-child(1) > a > img").getSrc)}";
MElement firstElement = MElement firstElement = value
value .select("td > a")
.select("td > a") .where(
.where( (MElement e) =>
(MElement e) => e.outerHtml.contains("/view/") &&
e.outerHtml.contains("/view/") && !e.outerHtml.contains("#comments"),
!e.outerHtml.contains("#comments"), )
) .toList()
.toList() .first;
.first;
anime.link = anime.link =
"${source.baseUrl}${getUrlWithoutDomain(firstElement.getHref)}"; "${getBaseUrl()}${getUrlWithoutDomain(firstElement.getHref)}";
anime.name = firstElement.attr("title"); anime.name = firstElement.attr("title");
animeList.add(anime); animeList.add(anime);
} }
final hasNextPage = final hasNextPage = xpath(
xpath( res,
res, '//ul[@class="pagination"]/li[contains(text(),"»")]/a/@href',
'//ul[@class="pagination"]/li[contains(text(),"»")]/a/@href', ).isNotEmpty;
).isNotEmpty;
return MPages(animeList, hasNextPage); return MPages(animeList, hasNextPage);
} }

View File

@@ -1,6 +1,6 @@
import '../../../../../model/source.dart'; import '../../../../../model/source.dart';
const _nyaaVersion = "0.0.3"; const _nyaaVersion = "0.0.4";
const _nyaaSourceCodeUrl = const _nyaaSourceCodeUrl =
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/src/all/nyaa/nyaa.dart"; "https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/$branchName/dart/anime/src/all/nyaa/nyaa.dart";