mirror of
https://github.com/kodjodevf/mangayomi-extensions.git
synced 2026-02-14 10:51:17 +00:00
fix: Refresh contain issue
This commit is contained in:
@@ -1,280 +1,306 @@
|
||||
const mangayomiSources = [{
|
||||
const mangayomiSources = [
|
||||
{
|
||||
"name": "Mangapill",
|
||||
"lang": "en",
|
||||
"baseUrl": "https://mangapill.com",
|
||||
"apiUrl": "",
|
||||
"iconUrl": "https://www.google.com/s2/favicons?sz=64&domain=https://mangapill.com/",
|
||||
"iconUrl":
|
||||
"https://www.google.com/s2/favicons?sz=64&domain=https://mangapill.com/",
|
||||
"typeSource": "single",
|
||||
"isManga": true,
|
||||
"version": "1.0.2",
|
||||
"version": "1.0.3",
|
||||
"dateFormat": "",
|
||||
"dateFormatLocale": "",
|
||||
"pkgPath": "manga/src/en/mangapill.js"
|
||||
}];
|
||||
}
|
||||
];
|
||||
|
||||
class DefaultExtension extends MProvider {
|
||||
getHeaders(url) {
|
||||
return {
|
||||
"Referer": this.source.baseUrl
|
||||
}
|
||||
getHeaders(url) {
|
||||
return {
|
||||
"Referer": this.source.baseUrl,
|
||||
};
|
||||
}
|
||||
|
||||
statusCode(status) {
|
||||
return (
|
||||
{
|
||||
"publishing": 0,
|
||||
"finished": 1,
|
||||
"on hiatus": 2,
|
||||
"discontinued": 3,
|
||||
"not yet published": 4,
|
||||
}[status] ?? 5
|
||||
);
|
||||
}
|
||||
|
||||
async getPreference(key) {
|
||||
const preferences = new SharedPreferences();
|
||||
return parseInt(preferences.get(key));
|
||||
}
|
||||
|
||||
async getMangaList(slug) {
|
||||
var lang = await this.getPreference("pref_title_lang");
|
||||
|
||||
var url = `${this.source.baseUrl}/${slug}`;
|
||||
var res = await new Client().get(url, this.getHeaders());
|
||||
var doc = new Document(res.body);
|
||||
var list = [];
|
||||
var mangaElements = doc.select("div.grid.gap-3.lg > div");
|
||||
for (var manga of mangaElements) {
|
||||
var details = manga.selectFirst("div").select("a");
|
||||
var detLen = details.length;
|
||||
details = details[detLen - 1];
|
||||
|
||||
var imageUrl = manga.selectFirst("img").getSrc;
|
||||
var link = details.getHref;
|
||||
var nameSection = details.select("div");
|
||||
|
||||
var name =
|
||||
nameSection[1] && lang == 2 ? nameSection[1].text : nameSection[0].text;
|
||||
|
||||
list.push({ name, imageUrl, link });
|
||||
}
|
||||
var hasNextPage = false;
|
||||
if (slug.includes("search?q")) {
|
||||
hasNextPage = doc.selectFirst(".container.py-3 a.btn.btn-sm").className
|
||||
? true
|
||||
: false;
|
||||
}
|
||||
return { list, hasNextPage };
|
||||
}
|
||||
|
||||
async getNavPage(prefKey) {
|
||||
var val = await this.getPreference(prefKey);
|
||||
var slug = "";
|
||||
switch (val) {
|
||||
case 1: {
|
||||
slug = "mangas/new";
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
slug = "chapters";
|
||||
break;
|
||||
}
|
||||
}
|
||||
return await this.getMangaList(slug);
|
||||
}
|
||||
|
||||
async getPopular(page) {
|
||||
return await this.getNavPage("pref_popular_content");
|
||||
}
|
||||
get supportsLatest() {
|
||||
throw new Error("supportsLatest not implemented");
|
||||
}
|
||||
|
||||
async getLatestUpdates(page) {
|
||||
return await this.getNavPage("pref_latest_content");
|
||||
}
|
||||
|
||||
async searchManga(query, status, type, genre, page) {
|
||||
var slug = `search?q=${query}&status=${status}&type=${type}${genre}&page=${page}`;
|
||||
return await this.getMangaList(slug);
|
||||
}
|
||||
|
||||
async search(query, page, filters) {
|
||||
var type = filters[0].values[filters[0].state].value;
|
||||
var status = filters[1].values[filters[1].state].value;
|
||||
|
||||
var genre = "";
|
||||
for (var filter of filters[2].state) {
|
||||
if (filter.state == true) genre += `&genre=${filter.value}`;
|
||||
}
|
||||
return await this.searchManga(query, status, type, genre, page);
|
||||
}
|
||||
|
||||
async getMangaDetail(slug) {
|
||||
var lang = await this.getPreference("pref_title_lang");
|
||||
var baseUrl = this.source.baseUrl;
|
||||
if (slug.includes(baseUrl)) slug = slug.replace(baseUrl, "");
|
||||
|
||||
var link = `${baseUrl}${slug}`;
|
||||
var res = await new Client().get(link, this.getHeaders());
|
||||
var doc = new Document(res.body);
|
||||
|
||||
var mangaName = doc.selectFirst(".mb-3 .font-bold.text-lg").text;
|
||||
if (doc.selectFirst(".mb-3 .text-sm.text-secondary") && lang == 2)
|
||||
mangaName = doc.selectFirst(".mb-3 .text-sm.text-secondary").text;
|
||||
var description = doc
|
||||
.selectFirst("meta[name='description']")
|
||||
.attr("content");
|
||||
var imageUrl = doc.selectFirst(".w-full.h-full").getSrc;
|
||||
var statusText = doc
|
||||
.select(".grid.grid-cols-1 > div")[1]
|
||||
.selectFirst("div").text;
|
||||
var status = this.statusCode(statusText);
|
||||
|
||||
var genre = [];
|
||||
var genreList = doc.select("a.mr-1");
|
||||
for (var gen of genreList) {
|
||||
genre.push(gen.text);
|
||||
}
|
||||
|
||||
statusCode(status) {
|
||||
return {
|
||||
"publishing": 0,
|
||||
"finished": 1,
|
||||
"on hiatus": 2,
|
||||
"discontinued": 3,
|
||||
"not yet published": 4,
|
||||
}[status] ?? 5;
|
||||
var chapters = [];
|
||||
var chapList = doc.select("div.my-3.grid > a");
|
||||
for (var chap of chapList) {
|
||||
var name = chap.text;
|
||||
var url = chap.getHref;
|
||||
chapters.push({ name, url });
|
||||
}
|
||||
return {
|
||||
name: mangaName,
|
||||
description,
|
||||
link,
|
||||
imageUrl,
|
||||
status,
|
||||
genre,
|
||||
chapters,
|
||||
};
|
||||
}
|
||||
|
||||
async getDetail(url) {
|
||||
return await this.getMangaDetail(url);
|
||||
}
|
||||
// For anime episode video list
|
||||
async getVideoList(url) {
|
||||
throw new Error("getVideoList not implemented");
|
||||
}
|
||||
|
||||
// For manga chapter pages
|
||||
async getPageList(url) {
|
||||
var link = `${this.source.baseUrl}${url}`;
|
||||
|
||||
var res = await new Client().get(link, this.getHeaders());
|
||||
var doc = new Document(res.body);
|
||||
|
||||
var urls = [];
|
||||
|
||||
var pages = doc.select("chapter-page");
|
||||
for (var page of pages) {
|
||||
var img = page.selectFirst("img").getSrc;
|
||||
if (img != null) urls.push(img);
|
||||
}
|
||||
|
||||
async getPreference(key) {
|
||||
const preferences = new SharedPreferences();
|
||||
return parseInt(preferences.get(key))
|
||||
}
|
||||
return urls;
|
||||
}
|
||||
|
||||
async getMangaList(slug) {
|
||||
var lang = await this.getPreference("pref_title_lang");
|
||||
getFilterList() {
|
||||
return [
|
||||
{
|
||||
type_name: "SelectFilter",
|
||||
name: "Type",
|
||||
state: 0,
|
||||
values: [
|
||||
["All", ""],
|
||||
["Manga", "manga"],
|
||||
["Novel", "novel"],
|
||||
["One-Shot", "one-shot"],
|
||||
["Doujinshi", "doujinshi"],
|
||||
["Manhwa", "manhwa"],
|
||||
["Manhua", "manhua"],
|
||||
["Oel", "oel"],
|
||||
].map((x) => ({ type_name: "SelectOption", name: x[0], value: x[1] })),
|
||||
},
|
||||
{
|
||||
type_name: "SelectFilter",
|
||||
name: "Status",
|
||||
state: 0,
|
||||
values: [
|
||||
["All", ""],
|
||||
["Publishing", "publishing"],
|
||||
["Finished", "finished"],
|
||||
["On hiatus", "on hiatus"],
|
||||
["Discontinued", "discontinued"],
|
||||
["Not yet published", "not yet published"],
|
||||
].map((x) => ({ type_name: "SelectOption", name: x[0], value: x[1] })),
|
||||
},
|
||||
{
|
||||
type_name: "GroupFilter",
|
||||
name: "Genre",
|
||||
state: [
|
||||
["Action", "Action"],
|
||||
["Adventure", "Adventure"],
|
||||
["Cars", "Cars"],
|
||||
["Comedy", "Comedy"],
|
||||
["Dementia", "Dementia"],
|
||||
["Demons", "Demons"],
|
||||
["Doujinshi", "Doujinshi"],
|
||||
["Drama", "Drama"],
|
||||
["Ecchi", "Ecchi"],
|
||||
["Fantasy", "Fantasy"],
|
||||
["Game", "Game"],
|
||||
["Gender Bender", "Gender Bender"],
|
||||
["Harem", "Harem"],
|
||||
["Historical", "Historical"],
|
||||
["Horror", "Horror"],
|
||||
["Isekai", "Isekai"],
|
||||
["Josei", "Josei"],
|
||||
["Kids", "Kids"],
|
||||
["Magic", "Magic"],
|
||||
["Martial Arts", "Martial Arts"],
|
||||
["Mecha", "Mecha"],
|
||||
["Military", "Military"],
|
||||
["Music", "Music"],
|
||||
["Mystery", "Mystery"],
|
||||
["Parody", "Parody"],
|
||||
["Police", "Police"],
|
||||
["Psychological", "Psychological"],
|
||||
["Romance", "Romance"],
|
||||
["Samurai", "Samurai"],
|
||||
["School", "School"],
|
||||
["Sci-Fi", "Sci-Fi"],
|
||||
["Seinen", "Seinen"],
|
||||
["Shoujo", "Shoujo"],
|
||||
["Shoujo Ai", "Shoujo Ai"],
|
||||
["Shounen", "Shounen"],
|
||||
["Shounen Ai", "Shounen Ai"],
|
||||
["Slice of Life", "Slice of Life"],
|
||||
["Space", "Space"],
|
||||
["Sports", "Sports"],
|
||||
["Super Power", "Super Power"],
|
||||
["Supernatural", "Supernatural"],
|
||||
["Thriller", "Thriller"],
|
||||
["Tragedy", "Tragedy"],
|
||||
["Vampire", "Vampire"],
|
||||
["Yaoi", "Yaoi"],
|
||||
["Yuri", "Yuri"],
|
||||
].map((x) => ({ type_name: "CheckBox", name: x[0], value: x[1] })),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
var url = `${this.source.baseUrl}/${slug}`
|
||||
var res = await new Client().get(url, this.getHeaders());
|
||||
var doc = new Document(res.body);
|
||||
var list = [];
|
||||
var mangaElements = doc.select("div.grid.gap-3.lg > div")
|
||||
for (var manga of mangaElements) {
|
||||
var details = manga.selectFirst('div').select('a');
|
||||
var detLen = details.length
|
||||
details = details[detLen - 1]
|
||||
|
||||
var imageUrl = manga.selectFirst("img").getSrc;
|
||||
var link = details.getHref;
|
||||
var nameSection = details.select('div');
|
||||
|
||||
var name = (nameSection[1] && lang == 2) ? nameSection[1].text : nameSection[0].text
|
||||
|
||||
list.push({ name, imageUrl, link });
|
||||
}
|
||||
var hasNextPage = false;
|
||||
if (slug.includes("search?q")) {
|
||||
hasNextPage = doc.selectFirst(".container.py-3 a.btn.btn-sm").className ? true : false
|
||||
}
|
||||
return { list, hasNextPage }
|
||||
}
|
||||
|
||||
async getNavPage(prefKey) {
|
||||
var val = await this.getPreference(prefKey);
|
||||
var slug = ''
|
||||
switch (val) {
|
||||
case 1: {
|
||||
slug = 'mangas/new'
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
slug = 'chapters'
|
||||
break;
|
||||
}
|
||||
}
|
||||
return await this.getMangaList(slug)
|
||||
}
|
||||
|
||||
async getPopular(page) {
|
||||
return await this.getNavPage("pref_popular_content");
|
||||
}
|
||||
get supportsLatest() {
|
||||
throw new Error("supportsLatest not implemented");
|
||||
}
|
||||
|
||||
async getLatestUpdates(page) {
|
||||
return await this.getNavPage("pref_latest_content");
|
||||
}
|
||||
|
||||
async searchManga(query, status, type, genre, page) {
|
||||
var slug = `search?q=${query}&status=${status}&type=${type}${genre}&page=${page}`
|
||||
return await this.getMangaList(slug)
|
||||
}
|
||||
|
||||
async search(query, page, filters) {
|
||||
var type = filters[0].values[filters[0].state].value
|
||||
var status = filters[1].values[filters[1].state].value
|
||||
|
||||
var genre = ""
|
||||
for (var filter of filters[2].state) {
|
||||
if (filter.state == true)
|
||||
genre += `&genre=${filter.value}`
|
||||
}
|
||||
return await this.searchManga(query, status, type, genre, page);
|
||||
}
|
||||
|
||||
async getMangaDetail(slug) {
|
||||
var lang = await this.getPreference("pref_title_lang");
|
||||
|
||||
var link = `${this.source.baseUrl}${slug}`
|
||||
var res = await new Client().get(link, this.getHeaders());
|
||||
var doc = new Document(res.body);
|
||||
|
||||
var mangaName = doc.selectFirst(".mb-3 .font-bold.text-lg").text
|
||||
if (doc.selectFirst(".mb-3 .text-sm.text-secondary") && lang == 2) mangaName = doc.selectFirst(".mb-3 .text-sm.text-secondary").text
|
||||
var description = doc.selectFirst("meta[name='description']").attr("content")
|
||||
var imageUrl = doc.selectFirst(".w-full.h-full").getSrc
|
||||
var statusText = doc.select(".grid.grid-cols-1 > div")[1].selectFirst("div").text
|
||||
var status = this.statusCode(statusText)
|
||||
|
||||
var genre = []
|
||||
var genreList = doc.select("a.mr-1")
|
||||
for (var gen of genreList) { genre.push(gen.text) }
|
||||
|
||||
var chapters = []
|
||||
var chapList = doc.select("div.my-3.grid > a")
|
||||
for (var chap of chapList) {
|
||||
var name = chap.text
|
||||
var url = chap.getHref
|
||||
chapters.push({ name, url })
|
||||
}
|
||||
return { name: mangaName, description, link, imageUrl, status, genre, chapters }
|
||||
}
|
||||
|
||||
async getDetail(url) {
|
||||
return await this.getMangaDetail(url);
|
||||
|
||||
}
|
||||
// For anime episode video list
|
||||
async getVideoList(url) {
|
||||
throw new Error("getVideoList not implemented");
|
||||
}
|
||||
|
||||
// For manga chapter pages
|
||||
async getPageList(url) {
|
||||
var link = `${this.source.baseUrl}${url}`
|
||||
|
||||
var res = await new Client().get(link, this.getHeaders());
|
||||
var doc = new Document(res.body);
|
||||
|
||||
var urls = [];
|
||||
|
||||
var pages = doc.select("chapter-page")
|
||||
for (var page of pages) {
|
||||
var img = page.selectFirst("img").getSrc
|
||||
if (img != null) urls.push(img);
|
||||
}
|
||||
|
||||
return urls
|
||||
}
|
||||
|
||||
getFilterList() {
|
||||
return [
|
||||
{
|
||||
type_name: "SelectFilter",
|
||||
name: "Type",
|
||||
state: 0,
|
||||
values: [
|
||||
["All", ""],
|
||||
["Manga", "manga"],
|
||||
["Novel", "novel"],
|
||||
["One-Shot", "one-shot"],
|
||||
["Doujinshi", "doujinshi"],
|
||||
["Manhwa", "manhwa"],
|
||||
["Manhua", "manhua"],
|
||||
["Oel", "oel"]
|
||||
].map(x => ({ type_name: 'SelectOption', name: x[0], value: x[1] }))
|
||||
},
|
||||
{
|
||||
type_name: "SelectFilter",
|
||||
name: "Status",
|
||||
state: 0,
|
||||
values: [
|
||||
["All", ""],
|
||||
["Publishing", "publishing"],
|
||||
["Finished", "finished"],
|
||||
["On hiatus", "on hiatus"],
|
||||
["Discontinued", "discontinued"],
|
||||
["Not yet published", "not yet published"]
|
||||
].map(x => ({ type_name: 'SelectOption', name: x[0], value: x[1] }))
|
||||
}, {
|
||||
type_name: "GroupFilter",
|
||||
name: "Genre",
|
||||
state: [
|
||||
["Action", "Action"],
|
||||
["Adventure", "Adventure"],
|
||||
["Cars", "Cars"],
|
||||
["Comedy", "Comedy"],
|
||||
["Dementia", "Dementia"],
|
||||
["Demons", "Demons"],
|
||||
["Doujinshi", "Doujinshi"],
|
||||
["Drama", "Drama"],
|
||||
["Ecchi", "Ecchi"],
|
||||
["Fantasy", "Fantasy"],
|
||||
["Game", "Game"],
|
||||
["Gender Bender", "Gender Bender"],
|
||||
["Harem", "Harem"],
|
||||
["Historical", "Historical"],
|
||||
["Horror", "Horror"],
|
||||
["Isekai", "Isekai"],
|
||||
["Josei", "Josei"],
|
||||
["Kids", "Kids"],
|
||||
["Magic", "Magic"],
|
||||
["Martial Arts", "Martial Arts"],
|
||||
["Mecha", "Mecha"],
|
||||
["Military", "Military"],
|
||||
["Music", "Music"],
|
||||
["Mystery", "Mystery"],
|
||||
["Parody", "Parody"],
|
||||
["Police", "Police"],
|
||||
["Psychological", "Psychological"],
|
||||
["Romance", "Romance"],
|
||||
["Samurai", "Samurai"],
|
||||
["School", "School"],
|
||||
["Sci-Fi", "Sci-Fi"],
|
||||
["Seinen", "Seinen"],
|
||||
["Shoujo", "Shoujo"],
|
||||
["Shoujo Ai", "Shoujo Ai"],
|
||||
["Shounen", "Shounen"],
|
||||
["Shounen Ai", "Shounen Ai"],
|
||||
["Slice of Life", "Slice of Life"],
|
||||
["Space", "Space"],
|
||||
["Sports", "Sports"],
|
||||
["Super Power", "Super Power"],
|
||||
["Supernatural", "Supernatural"],
|
||||
["Thriller", "Thriller"],
|
||||
["Tragedy", "Tragedy"],
|
||||
["Vampire", "Vampire"],
|
||||
["Yaoi", "Yaoi"],
|
||||
["Yuri", "Yuri"]
|
||||
].map(x => ({ type_name: 'CheckBox', name: x[0], value: x[1] }))
|
||||
}
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
getSourcePreferences() {
|
||||
return [{
|
||||
key: 'pref_popular_content',
|
||||
listPreference: {
|
||||
title: 'Preferred popular content',
|
||||
summary: '',
|
||||
valueIndex: 0,
|
||||
entries: ["New Mangas", "Recent Chapters"],
|
||||
entryValues: ["1", "2"]
|
||||
}
|
||||
}, {
|
||||
key: 'pref_latest_content',
|
||||
listPreference: {
|
||||
title: 'Preferred latest content',
|
||||
summary: '',
|
||||
valueIndex: 1,
|
||||
entries: ["New Mangas", "Recent Chapters"],
|
||||
entryValues: ["1", "2"]
|
||||
}
|
||||
}, {
|
||||
key: 'pref_title_lang',
|
||||
listPreference: {
|
||||
title: 'Preferred title language',
|
||||
summary: '',
|
||||
valueIndex: 0,
|
||||
entries: ["Romaji", "English"],
|
||||
entryValues: ["1", "2"]
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
getSourcePreferences() {
|
||||
return [
|
||||
{
|
||||
key: "pref_popular_content",
|
||||
listPreference: {
|
||||
title: "Preferred popular content",
|
||||
summary: "",
|
||||
valueIndex: 0,
|
||||
entries: ["New Mangas", "Recent Chapters"],
|
||||
entryValues: ["1", "2"],
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "pref_latest_content",
|
||||
listPreference: {
|
||||
title: "Preferred latest content",
|
||||
summary: "",
|
||||
valueIndex: 1,
|
||||
entries: ["New Mangas", "Recent Chapters"],
|
||||
entryValues: ["1", "2"],
|
||||
},
|
||||
},
|
||||
{
|
||||
key: "pref_title_lang",
|
||||
listPreference: {
|
||||
title: "Preferred title language",
|
||||
summary: "",
|
||||
valueIndex: 0,
|
||||
entries: ["Romaji", "English"],
|
||||
entryValues: ["1", "2"],
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,340 +1,459 @@
|
||||
const mangayomiSources = [{
|
||||
const mangayomiSources = [
|
||||
{
|
||||
"name": "ReadComicOnline",
|
||||
"lang": "en",
|
||||
"baseUrl": "https://readcomiconline.li",
|
||||
"apiUrl": "",
|
||||
"iconUrl": "https://www.google.com/s2/favicons?sz=256&domain=https://readcomiconline.li/",
|
||||
"iconUrl":
|
||||
"https://www.google.com/s2/favicons?sz=256&domain=https://readcomiconline.li/",
|
||||
"typeSource": "single",
|
||||
"itemType": 0,
|
||||
"version": "0.1.2",
|
||||
"version": "0.1.3",
|
||||
"pkgPath": "manga/src/en/readcomiconline.js"
|
||||
}];
|
||||
}
|
||||
];
|
||||
|
||||
class DefaultExtension extends MProvider {
|
||||
constructor() {
|
||||
super();
|
||||
this.client = new Client();
|
||||
}
|
||||
constructor() {
|
||||
super();
|
||||
this.client = new Client();
|
||||
}
|
||||
|
||||
getPreference(key) {
|
||||
return new SharedPreferences().get(key);
|
||||
}
|
||||
getPreference(key) {
|
||||
return new SharedPreferences().get(key);
|
||||
}
|
||||
|
||||
getHeaders() {
|
||||
return {
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6832.64 Safari/537.36",
|
||||
"Referer": this.source.baseUrl,
|
||||
"Origin": this.source.baseUrl,
|
||||
getHeaders() {
|
||||
return {
|
||||
"User-Agent":
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.6832.64 Safari/537.36",
|
||||
"Referer": this.source.baseUrl,
|
||||
"Origin": this.source.baseUrl,
|
||||
};
|
||||
}
|
||||
|
||||
async request(slug) {
|
||||
var url = slug;
|
||||
var baseUrl = this.source.baseUrl;
|
||||
if (!slug.includes(baseUrl)) url = baseUrl + slug;
|
||||
var res = await this.client.get(url, this.getHeaders());
|
||||
return new Document(res.body);
|
||||
}
|
||||
|
||||
async getListPage(slug, page) {
|
||||
var url = `${slug}page=${page}`;
|
||||
var doc = await this.request(url);
|
||||
var baseUrl = this.source.baseUrl;
|
||||
var list = [];
|
||||
|
||||
var comicList = doc.select(".list-comic > .item");
|
||||
comicList.forEach((item) => {
|
||||
var name = item.selectFirst(".title").text;
|
||||
var link = item.selectFirst("a").getHref;
|
||||
var imageSlug = item.selectFirst("img").getSrc;
|
||||
var imageUrl = imageSlug.includes("http")
|
||||
? imageSlug
|
||||
: `${baseUrl}${imageSlug}`;
|
||||
list.push({ name, link, imageUrl });
|
||||
});
|
||||
|
||||
var pager = doc.select("ul.pager > li");
|
||||
|
||||
var hasNextPage = false;
|
||||
if (pager.length > 0)
|
||||
hasNextPage = pager[pager.length - 1].text.includes("Last")
|
||||
? true
|
||||
: false;
|
||||
|
||||
return { list, hasNextPage };
|
||||
}
|
||||
|
||||
async getPopular(page) {
|
||||
return await this.getListPage("/ComicList/MostPopular?", page);
|
||||
}
|
||||
get supportsLatest() {
|
||||
throw new Error("supportsLatest not implemented");
|
||||
}
|
||||
async getLatestUpdates(page) {
|
||||
return await this.getListPage("/ComicList/LatestUpdate?", page);
|
||||
}
|
||||
async search(query, page, filters) {
|
||||
function getFilter(state) {
|
||||
var rd = "";
|
||||
state.forEach((item) => {
|
||||
if (item.state) {
|
||||
rd += `${item.value},`;
|
||||
}
|
||||
});
|
||||
return rd.slice(0, -1);
|
||||
}
|
||||
|
||||
async request(slug) {
|
||||
var url = slug
|
||||
var baseUrl = this.source.baseUrl
|
||||
if (!slug.includes(baseUrl)) url = baseUrl + slug;
|
||||
var res = await this.client.get(url, this.getHeaders());
|
||||
return new Document(res.body);
|
||||
var isFiltersAvailable = !filters || filters.length != 0;
|
||||
var genre = isFiltersAvailable ? getFilter(filters[0].state) : [];
|
||||
var status = isFiltersAvailable
|
||||
? filters[1].values[filters[1].state].value
|
||||
: "";
|
||||
var year = isFiltersAvailable
|
||||
? filters[2].values[filters[2].state].value
|
||||
: "";
|
||||
|
||||
var slug = `/AdvanceSearch?comicName=${query}&ig=${encodeURIComponent(
|
||||
genre
|
||||
)}&status=${status}&pubDate=${year}&`;
|
||||
|
||||
return await this.getListPage(slug, page);
|
||||
}
|
||||
|
||||
async getDetail(url) {
|
||||
function statusCode(status) {
|
||||
return (
|
||||
{
|
||||
"Ongoing": 0,
|
||||
"Completed": 1,
|
||||
}[status] ?? 5
|
||||
);
|
||||
}
|
||||
|
||||
async getListPage(slug, page) {
|
||||
var url = `${slug}page=${page}`
|
||||
var doc = await this.request(url);
|
||||
var baseUrl = this.source.baseUrl
|
||||
var list = []
|
||||
var baseUrl = this.source.baseUrl;
|
||||
if (url.includes(baseUrl)) url = url.replace(baseUrl, "");
|
||||
|
||||
var comicList = doc.select(".list-comic > .item")
|
||||
comicList.forEach(item => {
|
||||
var name = item.selectFirst(".title").text;
|
||||
var link = item.selectFirst("a").getHref
|
||||
var imageSlug = item.selectFirst("img").getSrc
|
||||
var imageUrl = imageSlug.includes("http") ? imageSlug : `${baseUrl}${imageSlug}`;
|
||||
list.push({ name, link, imageUrl });
|
||||
});
|
||||
var doc = await this.request(url);
|
||||
|
||||
var pager = doc.select("ul.pager > li")
|
||||
var detailsSection = doc.selectFirst(".barContent");
|
||||
var name = detailsSection.selectFirst("a").text;
|
||||
var imageSlug = doc.selectFirst(".rightBox").selectFirst("img").getSrc;
|
||||
var imageUrl = imageSlug.includes("http")
|
||||
? imageSlug
|
||||
: `${this.source.baseUrl}${imageSlug}`;
|
||||
var pTag = detailsSection.select("p");
|
||||
|
||||
var hasNextPage = false
|
||||
if (pager.length > 0) hasNextPage = pager[pager.length - 1].text.includes("Last") ? true : false;
|
||||
var description = pTag[pTag.length - 2].text;
|
||||
|
||||
return { list, hasNextPage }
|
||||
var status = 5;
|
||||
var genre = [];
|
||||
var author = "";
|
||||
var artist = "";
|
||||
|
||||
pTag.forEach((p) => {
|
||||
var itemText = p.text.trim();
|
||||
|
||||
if (itemText.includes("Genres")) {
|
||||
genre = itemText.replace("Genres:", "").trim().split(", ");
|
||||
} else if (itemText.includes("Status")) {
|
||||
var sts = itemText.replace("Status: ", "").trim().split("\n")[0];
|
||||
status = statusCode(sts);
|
||||
} else if (itemText.includes("Writer")) {
|
||||
author = itemText.replace("Writer: ", "");
|
||||
} else if (itemText.includes("Artist")) {
|
||||
artist = itemText.replace("Artist: ", "");
|
||||
}
|
||||
});
|
||||
var chapters = [];
|
||||
var tr = doc.selectFirst("table").select("tr");
|
||||
tr.splice(0, 2); // 1st item in the table is headers & 2nd item is a line break
|
||||
tr.forEach((item) => {
|
||||
var tds = item.select("td");
|
||||
var aTag = tds[0].selectFirst("a");
|
||||
var chapLink = aTag.getHref;
|
||||
|
||||
var chapTitle = aTag.text.trim().replace(`${name} `, "");
|
||||
chapTitle = chapTitle[0] == "_" ? chapTitle.substring(1) : chapTitle;
|
||||
|
||||
var uploadDate = tds[1].text.trim();
|
||||
var date = new Date(uploadDate);
|
||||
var dateUpload = date.getTime().toString();
|
||||
|
||||
chapters.push({ url: chapLink, name: chapTitle, dateUpload });
|
||||
});
|
||||
var link = baseUrl + url;
|
||||
|
||||
return {
|
||||
name,
|
||||
link,
|
||||
imageUrl,
|
||||
description,
|
||||
genre,
|
||||
status,
|
||||
author,
|
||||
artist,
|
||||
chapters,
|
||||
};
|
||||
}
|
||||
|
||||
// For manga chapter pages
|
||||
async getPageList(url) {
|
||||
var pages = [];
|
||||
var hdr = this.getHeaders();
|
||||
let match;
|
||||
var imageQuality = this.getPreference("readcomiconline_page_quality");
|
||||
|
||||
var doc = await this.request(url);
|
||||
var html = doc.html;
|
||||
|
||||
// Find host url for images
|
||||
var baseUrlOverride = "";
|
||||
const hostRegex = /return\s+baeu\s*\(\s*l\s*,\s*'([^']+?)'\s*\);?/g;
|
||||
match = hostRegex.exec(html);
|
||||
if (match.length > 0) {
|
||||
baseUrlOverride = match[1];
|
||||
if (baseUrlOverride.slice(-1) != "/") baseUrlOverride += "/";
|
||||
}
|
||||
|
||||
async getPopular(page) {
|
||||
return await this.getListPage("/ComicList/MostPopular?", page)
|
||||
const pageRegex = /pht\s*=\s*'([^']+?)';?/g;
|
||||
while ((match = pageRegex.exec(html)) !== null) {
|
||||
var encodedImageUrl = match[1];
|
||||
var decodedImageUrl = this.decodeImageUrl(
|
||||
encodedImageUrl,
|
||||
imageQuality,
|
||||
baseUrlOverride
|
||||
);
|
||||
pages.push({
|
||||
url: decodedImageUrl,
|
||||
headers: hdr,
|
||||
});
|
||||
}
|
||||
get supportsLatest() {
|
||||
throw new Error("supportsLatest not implemented");
|
||||
}
|
||||
async getLatestUpdates(page) {
|
||||
return await this.getListPage("/ComicList/LatestUpdate?", page)
|
||||
}
|
||||
async search(query, page, filters) {
|
||||
function getFilter(state) {
|
||||
var rd = ""
|
||||
state.forEach(item => {
|
||||
if (item.state) {
|
||||
rd += `${item.value},`
|
||||
}
|
||||
})
|
||||
return rd.slice(0, -1)
|
||||
}
|
||||
|
||||
var isFiltersAvailable = !filters || filters.length != 0
|
||||
var genre = isFiltersAvailable ? getFilter(filters[0].state): []
|
||||
var status = isFiltersAvailable ? filters[1].values[filters[1].state].value: ""
|
||||
var year = isFiltersAvailable ? filters[2].values[filters[2].state].value: ""
|
||||
|
||||
|
||||
var slug = `/AdvanceSearch?comicName=${query}&ig=${encodeURIComponent(genre)}&status=${status}&pubDate=${year}&`
|
||||
|
||||
return await this.getListPage(slug, page)
|
||||
return pages;
|
||||
}
|
||||
getFilterList() {
|
||||
function formateState(type_name, items, values) {
|
||||
var state = [];
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
state.push({ type_name: type_name, name: items[i], value: values[i] });
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
async getDetail(url) {
|
||||
function statusCode(status) {
|
||||
return {
|
||||
"Ongoing": 0,
|
||||
"Completed": 1,
|
||||
}[status] ?? 5;
|
||||
}
|
||||
var link = this.source.baseUrl + url
|
||||
var doc = await this.request(url)
|
||||
var filters = [];
|
||||
|
||||
var detailsSection = doc.selectFirst(".barContent")
|
||||
var name = detailsSection.selectFirst("a").text
|
||||
var imageSlug = doc.selectFirst(".rightBox").selectFirst("img").getSrc
|
||||
var imageUrl = imageSlug.includes("http") ? imageSlug : `${this.source.baseUrl}${imageSlug}`;
|
||||
var pTag = detailsSection.select("p")
|
||||
// Genre
|
||||
var items = [
|
||||
"Action",
|
||||
"Adventure",
|
||||
"Anthology",
|
||||
"Anthropomorphic",
|
||||
"Biography",
|
||||
"Children",
|
||||
"Comedy",
|
||||
"Crime",
|
||||
"Drama",
|
||||
"Family",
|
||||
"Fantasy",
|
||||
"Fighting",
|
||||
"Graphic Novels",
|
||||
"Historical",
|
||||
"Horror",
|
||||
"Leading Ladies",
|
||||
"LGBTQ",
|
||||
"Literature",
|
||||
"Manga",
|
||||
"Martial Arts",
|
||||
"Mature",
|
||||
"Military",
|
||||
"Mini-Series",
|
||||
"Movies & TV",
|
||||
"Music",
|
||||
"Mystery",
|
||||
"Mythology",
|
||||
"Personal",
|
||||
"Political",
|
||||
"Post-Apocalyptic",
|
||||
"Psychological",
|
||||
"Pulp",
|
||||
"Religious",
|
||||
"Robots",
|
||||
"Romance",
|
||||
"School Life",
|
||||
"Sci-Fi",
|
||||
"Slice of Life",
|
||||
"Sport",
|
||||
"Spy",
|
||||
"Superhero",
|
||||
"Supernatural",
|
||||
"Suspense",
|
||||
"Teen",
|
||||
"Thriller",
|
||||
"Vampires",
|
||||
"Video Games",
|
||||
"War",
|
||||
"Western",
|
||||
"Zombies",
|
||||
];
|
||||
|
||||
var description = pTag[pTag.length - 2].text
|
||||
var values = [
|
||||
"1",
|
||||
"2",
|
||||
"38",
|
||||
"46",
|
||||
"41",
|
||||
"49",
|
||||
"3",
|
||||
"17",
|
||||
"19",
|
||||
"25",
|
||||
"20",
|
||||
"31",
|
||||
"5",
|
||||
"28",
|
||||
"15",
|
||||
"35",
|
||||
"51",
|
||||
"44",
|
||||
"40",
|
||||
"4",
|
||||
"8",
|
||||
"33",
|
||||
"56",
|
||||
"47",
|
||||
"55",
|
||||
"23",
|
||||
"21",
|
||||
"48",
|
||||
"42",
|
||||
"43",
|
||||
"27",
|
||||
"39",
|
||||
"53",
|
||||
"9",
|
||||
"32",
|
||||
"52",
|
||||
"16",
|
||||
"50",
|
||||
"54",
|
||||
"30",
|
||||
"22",
|
||||
"24",
|
||||
"29",
|
||||
"57",
|
||||
"18",
|
||||
"34",
|
||||
"37",
|
||||
"26",
|
||||
"45",
|
||||
"36",
|
||||
];
|
||||
filters.push({
|
||||
type_name: "GroupFilter",
|
||||
name: "Genres",
|
||||
state: formateState("CheckBox", items, values),
|
||||
});
|
||||
|
||||
var status = 5
|
||||
var genre = []
|
||||
var author = ""
|
||||
var artist = ""
|
||||
// Status
|
||||
items = ["Any", "Ongoing", "Completed"];
|
||||
values = ["", "Ongoing", "Completed"];
|
||||
filters.push({
|
||||
type_name: "SelectFilter",
|
||||
name: "Status",
|
||||
state: 0,
|
||||
values: formateState("SelectOption", items, values),
|
||||
});
|
||||
|
||||
pTag.forEach(p => {
|
||||
var itemText = p.text.trim()
|
||||
// Years
|
||||
const currentYear = new Date().getFullYear();
|
||||
items = Array.from({ length: currentYear - 1919 }, (_, i) =>
|
||||
(1920 + i).toString()
|
||||
).reverse();
|
||||
items = ["All", ...items];
|
||||
values = ["", ...items];
|
||||
filters.push({
|
||||
type_name: "SelectFilter",
|
||||
name: "Year",
|
||||
state: 0,
|
||||
values: formateState("SelectOption", items, values),
|
||||
});
|
||||
|
||||
if (itemText.includes("Genres")) {
|
||||
genre = itemText.replace("Genres:", "").trim().split(", ")
|
||||
} else if (itemText.includes("Status")) {
|
||||
var sts = itemText.replace("Status: ", "").trim().split("\n")[0]
|
||||
status = statusCode(sts)
|
||||
} else if (itemText.includes("Writer")) {
|
||||
author = itemText.replace("Writer: ", "")
|
||||
} else if (itemText.includes("Artist")) {
|
||||
artist = itemText.replace("Artist: ", "")
|
||||
}
|
||||
return filters;
|
||||
}
|
||||
getSourcePreferences() {
|
||||
return [
|
||||
{
|
||||
key: "readcomiconline_page_quality",
|
||||
listPreference: {
|
||||
title: "Preferred image quality",
|
||||
summary: "",
|
||||
valueIndex: 2,
|
||||
entries: ["Low", "Medium", "High", "Highest"],
|
||||
entryValues: ["l", "m", "h", "vh"],
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
})
|
||||
var chapters = []
|
||||
var tr = doc.selectFirst("table").select("tr")
|
||||
tr.splice(0, 2) // 1st item in the table is headers & 2nd item is a line break
|
||||
tr.forEach(item => {
|
||||
var tds = item.select("td")
|
||||
var aTag = tds[0].selectFirst("a")
|
||||
var chapLink = aTag.getHref
|
||||
// -------- ReadComicOnline Image Decoder --------
|
||||
// Source:- https://readcomiconline.li/Scripts/rguard.min.js
|
||||
|
||||
var chapTitle = aTag.text.trim().replace(`${name} `, "")
|
||||
chapTitle = chapTitle[0] == "_" ? chapTitle.substring(1,) : chapTitle
|
||||
base64UrlDecode(input) {
|
||||
let base64 = input.replace(/-/g, "+").replace(/_/g, "/");
|
||||
|
||||
var uploadDate = tds[1].text.trim()
|
||||
var date = new Date(uploadDate);
|
||||
var dateUpload = date.getTime().toString();
|
||||
|
||||
|
||||
chapters.push({ url: chapLink, name: chapTitle, dateUpload })
|
||||
|
||||
})
|
||||
|
||||
return { name, link, imageUrl, description, genre, status, author, artist, chapters }
|
||||
while (base64.length % 4 !== 0) {
|
||||
base64 += "=";
|
||||
}
|
||||
|
||||
// For manga chapter pages
|
||||
async getPageList(url) {
|
||||
var pages = [];
|
||||
var hdr = this.getHeaders()
|
||||
let match;
|
||||
var imageQuality = this.getPreference("readcomiconline_page_quality");
|
||||
const base64abc =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
const outputBytes = [];
|
||||
|
||||
var doc = await this.request(url)
|
||||
var html = doc.html
|
||||
for (let i = 0; i < base64.length; i += 4) {
|
||||
const c1 = base64abc.indexOf(base64[i]);
|
||||
const c2 = base64abc.indexOf(base64[i + 1]);
|
||||
const c3 = base64abc.indexOf(base64[i + 2]);
|
||||
const c4 = base64abc.indexOf(base64[i + 3]);
|
||||
|
||||
// Find host url for images
|
||||
var baseUrlOverride = ""
|
||||
const hostRegex = /return\s+baeu\s*\(\s*l\s*,\s*'([^']+?)'\s*\);?/g;
|
||||
match = hostRegex.exec(html)
|
||||
if (match.length > 0) {
|
||||
baseUrlOverride = match[1]
|
||||
if (baseUrlOverride.slice(-1) != "/") baseUrlOverride += "/"
|
||||
}
|
||||
const triplet = (c1 << 18) | (c2 << 12) | ((c3 & 63) << 6) | (c4 & 63);
|
||||
|
||||
|
||||
const pageRegex = /pht\s*=\s*'([^']+?)';?/g;
|
||||
while ((match = pageRegex.exec(html)) !== null) {
|
||||
var encodedImageUrl = match[1]
|
||||
var decodedImageUrl = this.decodeImageUrl(encodedImageUrl, imageQuality, baseUrlOverride)
|
||||
pages.push({
|
||||
url: decodedImageUrl,
|
||||
headers: hdr,
|
||||
});
|
||||
|
||||
}
|
||||
return pages;
|
||||
}
|
||||
getFilterList() {
|
||||
function formateState(type_name, items, values) {
|
||||
var state = [];
|
||||
for (var i = 0; i < items.length; i++) {
|
||||
state.push({ type_name: type_name, name: items[i], value: values[i] })
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
var filters = [];
|
||||
|
||||
// Genre
|
||||
var items = [
|
||||
"Action", "Adventure", "Anthology", "Anthropomorphic", "Biography", "Children", "Comedy",
|
||||
"Crime", "Drama", "Family", "Fantasy", "Fighting", "Graphic Novels", "Historical", "Horror",
|
||||
"Leading Ladies", "LGBTQ", "Literature", "Manga", "Martial Arts", "Mature", "Military",
|
||||
"Mini-Series", "Movies & TV", "Music", "Mystery", "Mythology", "Personal", "Political",
|
||||
"Post-Apocalyptic", "Psychological", "Pulp", "Religious", "Robots", "Romance", "School Life",
|
||||
"Sci-Fi", "Slice of Life", "Sport", "Spy", "Superhero", "Supernatural", "Suspense", "Teen",
|
||||
"Thriller", "Vampires", "Video Games", "War", "Western", "Zombies"
|
||||
];
|
||||
|
||||
var values = [
|
||||
"1", "2", "38", "46", "41", "49", "3",
|
||||
"17", "19", "25", "20", "31", "5", "28", "15",
|
||||
"35", "51", "44", "40", "4", "8", "33",
|
||||
"56", "47", "55", "23", "21", "48", "42",
|
||||
"43", "27", "39", "53", "9", "32", "52",
|
||||
"16", "50", "54", "30", "22", "24", "29", "57",
|
||||
"18", "34", "37", "26", "45", "36"
|
||||
];
|
||||
filters.push({
|
||||
type_name: "GroupFilter",
|
||||
name: "Genres",
|
||||
state: formateState("CheckBox", items, values)
|
||||
})
|
||||
|
||||
// Status
|
||||
items = ["Any", "Ongoing", "Completed"];
|
||||
values = ["", "Ongoing", "Completed"];
|
||||
filters.push({
|
||||
type_name: "SelectFilter",
|
||||
name: "Status",
|
||||
state: 0,
|
||||
values: formateState("SelectOption", items, values)
|
||||
})
|
||||
|
||||
// Years
|
||||
const currentYear = new Date().getFullYear();
|
||||
items = Array.from({ length: currentYear - 1919 }, (_, i) => (1920 + i).toString()).reverse()
|
||||
items = ["All", ...items]
|
||||
values = ["", ...items]
|
||||
filters.push({
|
||||
type_name: "SelectFilter",
|
||||
name: "Year",
|
||||
state: 0,
|
||||
values: formateState("SelectOption", items, values)
|
||||
})
|
||||
|
||||
return filters;
|
||||
}
|
||||
getSourcePreferences() {
|
||||
return [
|
||||
{
|
||||
key: "readcomiconline_page_quality",
|
||||
listPreference: {
|
||||
title: 'Preferred image quality',
|
||||
summary: '',
|
||||
valueIndex: 2,
|
||||
entries: ["Low", "Medium", "High", "Highest"],
|
||||
entryValues: ["l", "m", "h", "vh"]
|
||||
}
|
||||
},
|
||||
]
|
||||
outputBytes.push((triplet >> 16) & 0xff);
|
||||
if (base64[i + 2] !== "=") outputBytes.push((triplet >> 8) & 0xff);
|
||||
if (base64[i + 3] !== "=") outputBytes.push(triplet & 0xff);
|
||||
}
|
||||
|
||||
// -------- ReadComicOnline Image Decoder --------
|
||||
// Source:- https://readcomiconline.li/Scripts/rguard.min.js
|
||||
// Convert bytes to ISO-8859-1 string
|
||||
return String.fromCharCode(...outputBytes);
|
||||
}
|
||||
|
||||
base64UrlDecode(input) {
|
||||
let base64 = input
|
||||
.replace(/-/g, "+")
|
||||
.replace(/_/g, "/");
|
||||
extractBeforeDecode(url) {
|
||||
return url.substring(15, 33) + url.substring(50);
|
||||
}
|
||||
|
||||
while (base64.length % 4 !== 0) {
|
||||
base64 += "=";
|
||||
}
|
||||
finalizeDecodedString(decoded) {
|
||||
return (
|
||||
decoded.substring(0, decoded.length - 11) +
|
||||
decoded[decoded.length - 2] +
|
||||
decoded[decoded.length - 1]
|
||||
);
|
||||
}
|
||||
|
||||
const base64abc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
const outputBytes = [];
|
||||
decoderFunction(encodedUrl) {
|
||||
var decodedUrl = this.extractBeforeDecode(encodedUrl);
|
||||
decodedUrl = this.finalizeDecodedString(decodedUrl);
|
||||
decodedUrl = decodeURIComponent(this.base64UrlDecode(decodedUrl));
|
||||
decodedUrl = decodedUrl.substring(0, 13) + decodedUrl.substring(17);
|
||||
return decodedUrl.slice(0, -2) + "=s1600";
|
||||
}
|
||||
|
||||
for (let i = 0; i < base64.length; i += 4) {
|
||||
const c1 = base64abc.indexOf(base64[i]);
|
||||
const c2 = base64abc.indexOf(base64[i + 1]);
|
||||
const c3 = base64abc.indexOf(base64[i + 2]);
|
||||
const c4 = base64abc.indexOf(base64[i + 3]);
|
||||
decodeImageUrl(encodedImageUrl, imageQuality, baseUrlOverride) {
|
||||
// Default image qualities
|
||||
var IMAGEQUALITY = [
|
||||
{ "l": "900", "m": "0", "h": "1600", "vh": "2041" },
|
||||
{ "l": "900", "m": "1600", "h": "2041", "vh": "0" },
|
||||
];
|
||||
|
||||
const triplet = (c1 << 18) | (c2 << 12) | ((c3 & 63) << 6) | (c4 & 63);
|
||||
let finalUrl;
|
||||
var qType = 0;
|
||||
// Check if the url starts with https, if not then decode the url
|
||||
if (!encodedImageUrl.startsWith("https")) {
|
||||
encodedImageUrl = encodedImageUrl
|
||||
.replace(/6UUQS__ACd__/g, "b")
|
||||
.replace(/pw_.g28x/g, "b");
|
||||
|
||||
outputBytes.push((triplet >> 16) & 0xFF);
|
||||
if (base64[i + 2] !== "=") outputBytes.push((triplet >> 8) & 0xFF);
|
||||
if (base64[i + 3] !== "=") outputBytes.push(triplet & 0xFF);
|
||||
}
|
||||
var encodedUrl = encodedImageUrl.split("=s")[0];
|
||||
var decodedUrl = this.decoderFunction(encodedUrl);
|
||||
|
||||
// Convert bytes to ISO-8859-1 string
|
||||
return String.fromCharCode(...outputBytes);
|
||||
}
|
||||
|
||||
|
||||
extractBeforeDecode(url) {
|
||||
return url.substring(15, 33) + url.substring(50);
|
||||
}
|
||||
|
||||
|
||||
finalizeDecodedString(decoded) {
|
||||
return decoded.substring(0, decoded.length - 11) + decoded[decoded.length - 2] + decoded[decoded.length - 1];
|
||||
}
|
||||
|
||||
decoderFunction(encodedUrl) {
|
||||
var decodedUrl = this.extractBeforeDecode(encodedUrl);
|
||||
decodedUrl = this.finalizeDecodedString(decodedUrl);
|
||||
decodedUrl = decodeURIComponent(this.base64UrlDecode(decodedUrl));
|
||||
decodedUrl = decodedUrl.substring(0, 13) + decodedUrl.substring(17);
|
||||
return decodedUrl.slice(0, -2) + "=s1600"
|
||||
}
|
||||
|
||||
decodeImageUrl(encodedImageUrl, imageQuality, baseUrlOverride) {
|
||||
// Default image qualities
|
||||
var IMAGEQUALITY = [
|
||||
{ "l": "900", "m": "0", "h": "1600", "vh": "2041" },
|
||||
{ "l": "900", "m": "1600", "h": "2041", "vh": "0" }
|
||||
]
|
||||
|
||||
let finalUrl;
|
||||
var qType = 0
|
||||
// Check if the url starts with https, if not then decode the url
|
||||
if (!encodedImageUrl.startsWith("https")) {
|
||||
encodedImageUrl = encodedImageUrl
|
||||
.replace(/6UUQS__ACd__/g, 'b')
|
||||
.replace(/pw_.g28x/g, "b")
|
||||
|
||||
var encodedUrl = encodedImageUrl.split("=s")[0]
|
||||
var decodedUrl = this.decoderFunction(encodedUrl);
|
||||
|
||||
var queryParams = encodedImageUrl.substring(encodedImageUrl.indexOf("?"));
|
||||
finalUrl = baseUrlOverride + decodedUrl + queryParams
|
||||
} else {
|
||||
// If the url starts with https, then just override the base url
|
||||
qType = 1
|
||||
finalUrl = baseUrlOverride + encodedImageUrl.split(".com/")[1]
|
||||
}
|
||||
return finalUrl.replace("s1600", `s${IMAGEQUALITY[qType][imageQuality]}`)
|
||||
var queryParams = encodedImageUrl.substring(encodedImageUrl.indexOf("?"));
|
||||
finalUrl = baseUrlOverride + decodedUrl + queryParams;
|
||||
} else {
|
||||
// If the url starts with https, then just override the base url
|
||||
qType = 1;
|
||||
finalUrl = baseUrlOverride + encodedImageUrl.split(".com/")[1];
|
||||
}
|
||||
return finalUrl.replace("s1600", `s${IMAGEQUALITY[qType][imageQuality]}`);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user