Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MyAnimeList (manga) fixes #5467

Merged
merged 3 commits into from
Feb 15, 2023
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 73 additions & 23 deletions src/web/mjs/connectors/MyAnimeListManga.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,19 @@ export default class MyAnimeListManga extends Connector {
super.label = 'MyAnimeList (Manga)';
this.tags = [ 'manga', 'high-quality', 'english' ];
this.url = 'https://myanimelist.net';
this.links = {
login: 'https://myanimelist.net/login.php'
};
this.config = {
throttle: {
label: 'Throttle Requests [ms]',
description: 'Enter the timespan in [ms] to delay consecuitive HTTP requests.\nThe website may reject to many consecuitive requests',
input: 'numeric',
min: 0,
max: 5000,
value: 500
}
};
}

async _getMangaFromURI(uri) {
Expand All @@ -20,30 +33,51 @@ export default class MyAnimeListManga extends Connector {
}

async _getMangas() {
let request = new Request(new URL('/read/manga', this.url), this.requestOptions);
let data = await this.fetchDOM(request, 'tr.ranking-list td.title div.detail > a:first-of-type');
return data.map(element => {
return {
id: element.href.split('/').pop(),
title: element.text.trim()
};
});
let mangaList = [];
for (let page = 1, run = true; run; page++) {
const mangas = await this._getMangasFromPage(page);
mangas.length > 0 ? mangaList.push(...mangas) : run = false;
}
return mangaList;
}

async _getChapters(manga) {
let request = new Request(new URL('/read/manga/detail/' + manga.id, this.url), this.requestOptions);
let data = await this.fetchDOM(request, 'table.top-ranking-table tr td div.detail a:first-of-type');
async _getMangasFromPage(page) {
const uri = new URL('/store/search?p=' + page, this.url);
const request = new Request(uri, this.requestOptions);
const data = await this.fetchDOM(request, 'div.items a.item');
return data.map(element => {
return {
id: this.getRootRelativeOrAbsoluteLink(element, this.url),
title: element.text.trim(),
language: ''
title: element.querySelector('span.title').textContent.trim()
};
});
}

async _getChapters(manga) {
let request = new Request(new URL(manga.id, this.url), this.requestOptions);
const data = await this.fetchDOM(request, 'div.v-manga-store-purchase-bulk-button');
const jObject= JSON.parse(data[0].dataset['items']);
return jObject.filter(element => element.is_previewable || element.is_free || element.is_possessed)
.map(element => {
const isPossessed = !element.is_possessed ? false : element.is_possessed; //value can be null instead of false
const isFull = element.is_free || isPossessed;
let title = element.numbering_text.trim();
title += isFull ? '' : ' [Preview]';
return {
id: this.getRootRelativeOrAbsoluteLink(isFull ? element.viewer_url : element.preview_url, this.url),
title: title,
language: ''
};
});
}

async _getPages(chapter) {
let request = new Request(new URL(chapter.id, this.url), this.requestOptions);
//TODO : add support for light novels : its modified Publus reader
if (chapter.id.includes('novel_viewer')) {
throw new Error('Light Novels are not supported :/');
MikeZeDev marked this conversation as resolved.
Show resolved Hide resolved
}
const url = new URL(chapter.id, this.url);
let request = new Request(url, this.requestOptions);
let data = await this.fetchDOM(request, 'div.v-manga-store-viewer');
if(data.length === 0) {
throw new Error('You must first login to see this page!');
Expand All @@ -52,18 +86,34 @@ export default class MyAnimeListManga extends Connector {
return data.manuscript.filenames.map(file => {
let uri = new URL(data.manuscript.image_base_url + '/' + file);
uri.search = data.manuscript.query_params_part;
return this.createConnectorURI(uri.href);
return this.createConnectorURI({imageUrl : uri.href, referer : url, mode : 'xor'});
});
}

async _handleConnectorURI(payload) {
let request = new Request(payload, this.requestOptions);
let response = await fetch(request);
let data = await response.arrayBuffer();
return {
mimeType: response.headers.get('content-type'),
data: this._decryptImage(data)
};
await this.wait(this.config.throttle.value);
//handling modes already in case of future addition of light novels support
switch(payload.mode) {
case 'xor': {
const Xreferal = new URL(payload.referer);
let request = new Request(payload.imageUrl, this.requestOptions);
request.headers.set('Accept', 'application/json, text/plain, */*');
request.headers.set('X-Requested-With', 'XMLHttpRequest');
request.headers.set('X-Referral-Path', Xreferal.pathname );
request.headers.set('x-origin', this.url);
request.headers.set('x-referer', payload.referer);
let response = await fetch(request);
let data = await response.arrayBuffer();
return {
mimeType: response.headers.get('content-type'),
data: this._decryptImage(data)
};
}

case 'puzzle' : {
//
}
}
}

_decryptImage(encrypted) {
Expand All @@ -78,4 +128,4 @@ export default class MyAnimeListManga extends Connector {
}
return decrypted;
}
}
}