Merge pull request #257 from Schnitzel5/novel/annasarchive

added Anna's Archive (+ extension notes)
This commit is contained in:
Moustapha Kodjo Amadou
2025-05-10 11:56:58 +01:00
committed by GitHub
5 changed files with 188 additions and 5 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -0,0 +1,177 @@
const mangayomiSources = [
{
"name": "Annas Archive",
"lang": "en",
"baseUrl": "https://annas-archive.org",
"apiUrl": "",
"iconUrl":
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/javascript/icon/all.annasarchive.png",
"typeSource": "single",
"itemType": 2,
"version": "0.0.1",
"appMinVerReq": "0.6.1",
"dateFormat": "",
"dateFormatLocale": "",
"pkgPath": "novel/src/all/annasarchive.js",
"isNsfw": false,
"hasCloudflare": true,
"notes": "EPUBs are automatically downloaded to view chapters! Downloads from Libgen might be slow!",
},
];
class DefaultExtension extends MProvider {
headers = {
Priority: "u=0, i",
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36",
};
getHeaders(url) {
throw new Error("getHeaders not implemented");
}
mangaListFromPage(res) {
const doc = new Document(res.body.replaceAll(/<!--|-->/g, ""));
const mangaElements = doc.select("a");
const list = [];
for (const element of mangaElements) {
const name = element.selectFirst("h3")?.text.replaceAll("🔍", "").trim();
const imageUrl = element.selectFirst("img").getSrc;
const link = element.getHref;
if (link.includes("/md5/")) {
list.push({ name, imageUrl, link });
}
}
const hasNextPage = true;
return { list: list, hasNextPage };
}
async getPopular(page) {
let url = `${this.source.baseUrl}/search?index=&page=${page}&q=&display=&ext=epub&src=lgli&sort=`;
if (this.source.lang != "all") {
url += `&lang=${this.source.lang}`;
}
const res = await new Client().get(url, this.headers);
return this.mangaListFromPage(res);
}
async getLatestUpdates(page) {
let url = `${this.source.baseUrl}/search?index=&page=${page}&q=&display=&ext=epub&src=lgli&sort=newest`;
if (this.source.lang != "all") {
url += `&lang=${this.source.lang}`;
}
const res = await new Client().get(url, this.headers);
return this.mangaListFromPage(res);
}
async search(query, page, filters) {
let url = `${this.source.baseUrl}/search?index=&page=${page}&q=${query}&display=&ext=epub&src=lgli&sort=`;
if (this.source.lang != "all") {
url += `&lang=${this.source.lang}`;
}
const res = await new Client().get(url, this.headers);
return this.mangaListFromPage(res);
}
async getDetail(url) {
const client = new Client();
const res = await client.get(this.source.baseUrl + url, this.headers);
const doc = new Document(res.body);
const main = doc.selectFirst('main[class="main"]');
const name = doc.selectFirst('div.text-3xl.font-bold')?.text.trim();
const description = doc
.selectFirst('div[class="mb-1"]')
?.text.trim()
.replace("description", "");
const author = doc.selectFirst('div[class="italic"]')?.text.replaceAll("🔍", "").trim();
const status = 1;
const genre = [];
const mirrorLink = main
.selectFirst('ul[class="list-inside mb-4 ml-1 js-show-external hidden"]')
.select("li > a")
.find((el) => el.getHref?.includes("libgen.is")).getHref;
const bookLink = await this._getMirrorLink(client, mirrorLink);
if (!bookLink) {
return {
description,
genre,
author,
status,
chapters: [],
};
}
const book = await parseEpub(name, bookLink, {
Connection: "Keep-Alive",
...this.headers,
});
const chapters = [];
for (const chapterTitle of book.chapters) {
chapters.push({
name: chapterTitle,
url: mirrorLink + ";;;" + chapterTitle,
dateUpload: String(Date.now()),
scanlator: null,
});
}
return {
description,
genre,
author,
status,
chapters,
};
}
async _getMirrorLink(client, mirrorLink) {
const res = await client.get(mirrorLink, {
Origin: this.source.baseUrl,
...this.headers,
});
const doc = new Document(res.body);
const links = doc.select(
"a"
);
const libgenRs = links.find((el) => el.getHref?.includes("books.ms"))?.getHref;
const libgenLi = links.find((el) => el.getHref?.includes("libgen.li"))?.getHref;
if (libgenRs && (await client.head(libgenRs, this.headers)).statusCode === 200) {
const response = await client.get(libgenRs, this.headers);
const document = new Document(response.body);
return document.selectFirst('div#download > h2 > a')?.getHref;
} else if (libgenLi && (await client.head(libgenLi, this.headers)).statusCode === 200) {
const response = await client.get(libgenLi, this.headers);
const document = new Document(response.body);
return "https://libgen.li/" + document.selectFirst('tbody > tr > td > a')?.getHref;
}
return null;
}
async getHtmlContent(name, url) {
const urls = url.split(";;;");
const client = await new Client();
const bookLink = await this._getMirrorLink(client, urls[0]);
return await parseEpubChapter(name, bookLink, {
Connection: "Keep-Alive",
...this.headers,
}, urls[1]);
}
async cleanHtmlContent(html) {
return html;
}
getFilterList() {
return [];
}
getSourcePreferences() {
throw new Error("getSourcePreferences not implemented");
}
}

View File

@@ -7,12 +7,13 @@ const mangayomiSources = [{
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/javascript/icon/en.novelupdates.png",
"typeSource": "single",
"itemType": 2,
"version": "0.0.3",
"version": "0.0.4",
"dateFormat": "",
"dateFormatLocale": "",
"pkgPath": "novel/src/en/novelupdates.js",
"isNsfw": false,
"hasCloudflare": true
"hasCloudflare": true,
"notes": "This extension requires you to login to view the chapters!"
}];
class DefaultExtension extends MProvider {
@@ -180,7 +181,7 @@ class DefaultExtension extends MProvider {
};
}
async getHtmlContent(url) {
async getHtmlContent(name, url) {
const client = await new Client();
const res = await client.get(url, {
Priority: "u=0, i",

View File

@@ -7,7 +7,7 @@ const mangayomiSources = [{
"https://raw.githubusercontent.com/kodjodevf/mangayomi-extensions/main/javascript/icon/en.wordrain69.png",
"typeSource": "single",
"itemType": 2,
"version": "0.0.3",
"version": "0.0.4",
"dateFormat": "",
"dateFormatLocale": "",
"pkgPath": "novel/src/en/wordrain69.js",
@@ -115,7 +115,7 @@ class DefaultExtension extends MProvider {
};
}
async getHtmlContent(url) {
async getHtmlContent(name, url) {
const client = await new Client();
const res = await client.get(url);
return await this.cleanHtmlContent(res.body);

View File

@@ -37,6 +37,8 @@ class Source {
int? sourceCodeLanguage;
String? notes;
Source({
this.id = null,
this.name = "",
@@ -57,6 +59,7 @@ class Source {
this.appMinVerReq = "0.5.0",
this.additionalParams = "",
this.sourceCodeLanguage = 0,
this.notes = "",
});
Source.fromJson(Map<String, dynamic> json) {
final sourceCodeLang = json['sourceCodeLanguage'] ?? 0;
@@ -84,6 +87,7 @@ class Source {
version = json['version'] ?? "";
additionalParams = json['additionalParams'] ?? "";
sourceCodeLanguage = sourceCodeLang;
notes = json['notes'] ?? "";
}
Map<String, dynamic> toJson() {
@@ -107,6 +111,7 @@ class Source {
"appMinVerReq": appMinVerReq,
"additionalParams": additionalParams,
"sourceCodeLanguage": sourceCodeLanguage,
"notes": notes,
};
}
}