mirror of
https://github.com/venera-app/venera-configs.git
synced 2025-09-27 16:37:23 +00:00
copy_manga: Avoid loading chapters too quickly
* Update copy_manga.js 修复loadEp逻辑,防止访问过快风控 * format --------- Co-authored-by: nyne <me@nyne.dev>
This commit is contained in:
117
copy_manga.js
117
copy_manga.js
@@ -4,7 +4,7 @@ class CopyManga extends ComicSource {
|
|||||||
|
|
||||||
key = "copy_manga"
|
key = "copy_manga"
|
||||||
|
|
||||||
version = "1.0.4"
|
version = "1.0.5"
|
||||||
|
|
||||||
minAppVersion = "1.0.0"
|
minAppVersion = "1.0.0"
|
||||||
|
|
||||||
@@ -220,9 +220,9 @@ class CopyManga extends ComicSource {
|
|||||||
load: async (category, param, options, page) => {
|
load: async (category, param, options, page) => {
|
||||||
let category_url;
|
let category_url;
|
||||||
// 分类-排行
|
// 分类-排行
|
||||||
if (category === "排行" || param === "ranking"){
|
if (category === "排行" || param === "ranking") {
|
||||||
category_url = `https://api.copymanga.tv/api/v3/ranks?limit=21&offset=${(page - 1) * 21}&_update=true&type=1&audience_type=${options[0]}&date_type=${options[1]}`
|
category_url = `https://api.copymanga.tv/api/v3/ranks?limit=21&offset=${(page - 1) * 21}&_update=true&type=1&audience_type=${options[0]}&date_type=${options[1]}`
|
||||||
}else{
|
} else {
|
||||||
// 分类-主题
|
// 分类-主题
|
||||||
if (category !== undefined && category !== null) {
|
if (category !== undefined && category !== null) {
|
||||||
// 若传入category,则转化为对应param
|
// 若传入category,则转化为对应param
|
||||||
@@ -248,7 +248,7 @@ class CopyManga extends ComicSource {
|
|||||||
let sort = null
|
let sort = null
|
||||||
let popular = 0
|
let popular = 0
|
||||||
let rise_sort = 0;
|
let rise_sort = 0;
|
||||||
if (comic["sort"] !== null && comic["sort"] !== undefined){
|
if (comic["sort"] !== null && comic["sort"] !== undefined) {
|
||||||
sort = comic["sort"]
|
sort = comic["sort"]
|
||||||
rise_sort = comic["rise_sort"]
|
rise_sort = comic["rise_sort"]
|
||||||
popular = comic["popular"]
|
popular = comic["popular"]
|
||||||
@@ -269,19 +269,19 @@ class CopyManga extends ComicSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//如果是漫画排名,则描述为 排名(+升降箭头)+作者+人气
|
//如果是漫画排名,则描述为 排名(+升降箭头)+作者+人气
|
||||||
if(sort !== null){
|
if (sort !== null) {
|
||||||
return {
|
return {
|
||||||
id: comic["path_word"],
|
id: comic["path_word"],
|
||||||
title: comic["name"],
|
title: comic["name"],
|
||||||
subTitle: author,
|
subTitle: author,
|
||||||
cover: comic["cover"],
|
cover: comic["cover"],
|
||||||
tags: tags,
|
tags: tags,
|
||||||
description:`${sort} ${rise_sort > 0 ? '▲' : rise_sort < 0 ? '▽' : '-'}\n` +
|
description: `${sort} ${rise_sort > 0 ? '▲' : rise_sort < 0 ? '▽' : '-'}\n` +
|
||||||
`${author_num > 1 ? `${author} 等${author_num}位` : author}\n` +
|
`${author_num > 1 ? `${author} 等${author_num}位` : author}\n` +
|
||||||
`🔥${(popular / 10000).toFixed(1)}W`
|
`🔥${(popular / 10000).toFixed(1)}W`
|
||||||
}
|
}
|
||||||
//正常情况的描述为更新时间
|
//正常情况的描述为更新时间
|
||||||
}else{
|
} else {
|
||||||
return {
|
return {
|
||||||
id: comic["path_word"],
|
id: comic["path_word"],
|
||||||
title: comic["name"],
|
title: comic["name"],
|
||||||
@@ -347,23 +347,24 @@ class CopyManga extends ComicSource {
|
|||||||
if (keyword.startsWith("作者:")) {
|
if (keyword.startsWith("作者:")) {
|
||||||
author = keyword.substring("作者:".length).trim();
|
author = keyword.substring("作者:".length).trim();
|
||||||
}
|
}
|
||||||
|
let res;
|
||||||
// 通过onClickTag传入时有"作者:"前缀,处理这种情况
|
// 通过onClickTag传入时有"作者:"前缀,处理这种情况
|
||||||
if (author && author in this.author_path_word_dict){
|
if (author && author in this.author_path_word_dict) {
|
||||||
let path_word = encodeURIComponent(this.author_path_word_dict[author]);
|
let path_word = encodeURIComponent(this.author_path_word_dict[author]);
|
||||||
var res = await Network.get(
|
res = await Network.get(
|
||||||
`https://api.copymanga.tv/api/v3/comics?limit=21&offset=${(page - 1) * 21}&ordering=-datetime_updated&author=${path_word}&platform=3`,
|
`https://api.copymanga.tv/api/v3/comics?limit=21&offset=${(page - 1) * 21}&ordering=-datetime_updated&author=${path_word}&platform=3`,
|
||||||
this.headers
|
this.headers
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// 一般的搜索情况
|
// 一般的搜索情况
|
||||||
else{
|
else {
|
||||||
let q_type = "";
|
let q_type = "";
|
||||||
if(options && options[0]){
|
if (options && options[0]) {
|
||||||
q_type = options[0];
|
q_type = options[0];
|
||||||
}
|
}
|
||||||
keyword = encodeURIComponent(keyword)
|
keyword = encodeURIComponent(keyword)
|
||||||
let search_url = this.loadSetting('search_api') == "webAPI" ? "https://www.copymanga.tv/api/kb/web/searchbc/comics" : "https://api.copymanga.tv/api/v3/search/comic"
|
let search_url = this.loadSetting('search_api') === "webAPI" ? "https://www.copymanga.tv/api/kb/web/searchbc/comics" : "https://api.copymanga.tv/api/v3/search/comic"
|
||||||
var res = await Network.get(
|
res = await Network.get(
|
||||||
`${search_url}?limit=21&offset=${(page - 1) * 21}&q=${keyword}&q_type=${q_type}&platform=3`,
|
`${search_url}?limit=21&offset=${(page - 1) * 21}&q=${keyword}&q_type=${q_type}&platform=3`,
|
||||||
this.headers
|
this.headers
|
||||||
)
|
)
|
||||||
@@ -495,8 +496,8 @@ class CopyManga extends ComicSource {
|
|||||||
|
|
||||||
comic = {
|
comic = {
|
||||||
loadInfo: async (id) => {
|
loadInfo: async (id) => {
|
||||||
async function getChapters(id) {
|
let getChapters = async (id) => {
|
||||||
var res = await Network.get(
|
let res = await Network.get(
|
||||||
`https://api.copymanga.tv/api/v3/comic/${id}/group/default/chapters?limit=500&offset=0&platform=3`,
|
`https://api.copymanga.tv/api/v3/comic/${id}/group/default/chapters?limit=500&offset=0&platform=3`,
|
||||||
this.headers
|
this.headers
|
||||||
);
|
);
|
||||||
@@ -533,7 +534,7 @@ class CopyManga extends ComicSource {
|
|||||||
return eps;
|
return eps;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getFavoriteStatus(id) {
|
let getFavoriteStatus = async (id) => {
|
||||||
let res = await Network.get(`https://api.copymanga.tv/api/v3/comic2/${id}/query?platform=3`, this.headers);
|
let res = await Network.get(`https://api.copymanga.tv/api/v3/comic2/${id}/query?platform=3`, this.headers);
|
||||||
if (res.status !== 200) {
|
if (res.status !== 200) {
|
||||||
throw `Invalid status code: ${res.status}`;
|
throw `Invalid status code: ${res.status}`;
|
||||||
@@ -564,7 +565,7 @@ class CopyManga extends ComicSource {
|
|||||||
this.author_path_word_dict = {};
|
this.author_path_word_dict = {};
|
||||||
}
|
}
|
||||||
// 储存author对应的path_word
|
// 储存author对应的path_word
|
||||||
comicData.author.forEach(e=>(this.author_path_word_dict[e.name] = e.path_word));
|
comicData.author.forEach(e => (this.author_path_word_dict[e.name] = e.path_word));
|
||||||
let tags = comicData.theme.map(e => e?.name).filter(name => name !== undefined && name !== null);
|
let tags = comicData.theme.map(e => e?.name).filter(name => name !== undefined && name !== null);
|
||||||
let updateTime = comicData.datetime_updated ? comicData.datetime_updated : "";
|
let updateTime = comicData.datetime_updated ? comicData.datetime_updated : "";
|
||||||
let description = comicData.brief;
|
let description = comicData.brief;
|
||||||
@@ -585,34 +586,76 @@ class CopyManga extends ComicSource {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
loadEp: async (comicId, epId) => {
|
loadEp: async (comicId, epId) => {
|
||||||
let res = await Network.get(
|
let attempt = 0;
|
||||||
|
const maxAttempts = 5;
|
||||||
|
let res;
|
||||||
|
let data;
|
||||||
|
|
||||||
|
while (attempt < maxAttempts) {
|
||||||
|
try {
|
||||||
|
res = await Network.get(
|
||||||
`https://api.copymanga.tv/api/v3/comic/${comicId}/chapter2/${epId}?platform=3`,
|
`https://api.copymanga.tv/api/v3/comic/${comicId}/chapter2/${epId}?platform=3`,
|
||||||
this.headers
|
this.headers
|
||||||
);
|
);
|
||||||
|
|
||||||
if (res.status !== 200){
|
if (res.status === 210) {
|
||||||
|
// 210 indicates too frequent access, extract wait time
|
||||||
|
let waitTime = 40000; // Default wait time 40s
|
||||||
|
try {
|
||||||
|
let responseBody = JSON.parse(res.body);
|
||||||
|
if (
|
||||||
|
responseBody.message &&
|
||||||
|
responseBody.message.includes("Expected available in")
|
||||||
|
) {
|
||||||
|
let match = responseBody.message.match(/(\d+)\s*seconds/);
|
||||||
|
if (match && match[1]) {
|
||||||
|
waitTime = parseInt(match[1]) * 1000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(
|
||||||
|
"Unable to parse wait time, using default wait time 40s"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
console.log(`Chapter${epId} access too frequent, waiting ${waitTime / 1000}s`);
|
||||||
|
await new Promise((resolve) => setTimeout(resolve, waitTime));
|
||||||
|
throw "Retry";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.status !== 200) {
|
||||||
throw `Invalid status code: ${res.status}`;
|
throw `Invalid status code: ${res.status}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = JSON.parse(res.body);
|
data = JSON.parse(res.body);
|
||||||
|
// console.log(data.results.chapter);
|
||||||
|
// Handle image link sorting
|
||||||
|
let imagesUrls = data.results.chapter.contents.map((e) => e.url);
|
||||||
|
let orders = data.results.chapter.words;
|
||||||
|
|
||||||
let imagesUrls = data.results.chapter.contents.map(e => e.url)
|
let images = new Array(imagesUrls.length).fill(""); // Initialize an array with the same length as imagesUrls
|
||||||
|
|
||||||
let orders = data.results.chapter.words
|
// Arrange images according to orders
|
||||||
|
for (let i = 0; i < imagesUrls.length; i++) {
|
||||||
let images = imagesUrls.map(e => "")
|
images[orders[i]] = imagesUrls[i];
|
||||||
|
|
||||||
for(let i=0; i < imagesUrls.length; i++){
|
|
||||||
images[orders[i]] = imagesUrls[i]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
images: images
|
images: images,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
if (error !== "Retry") {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
attempt++;
|
||||||
|
if (attempt >= maxAttempts) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
loadComments: async (comicId, subId, page, replyTo) => {
|
loadComments: async (comicId, subId, page, replyTo) => {
|
||||||
let url = `https://api.copymanga.tv/api/v3/comments?comic_id=${subId}&limit=20&offset=${(page-1)*20}`;
|
let url = `https://api.copymanga.tv/api/v3/comments?comic_id=${subId}&limit=20&offset=${(page - 1) * 20}`;
|
||||||
if(replyTo){
|
if (replyTo) {
|
||||||
url = url + `&reply_id=${replyTo}&_update=true`;
|
url = url + `&reply_id=${replyTo}&_update=true`;
|
||||||
}
|
}
|
||||||
let res = await Network.get(
|
let res = await Network.get(
|
||||||
@@ -620,7 +663,7 @@ class CopyManga extends ComicSource {
|
|||||||
this.headers,
|
this.headers,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (res.status !== 200){
|
if (res.status !== 200) {
|
||||||
throw `Invalid status code: ${res.status}`;
|
throw `Invalid status code: ${res.status}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -644,10 +687,10 @@ class CopyManga extends ComicSource {
|
|||||||
},
|
},
|
||||||
sendComment: async (comicId, subId, content, replyTo) => {
|
sendComment: async (comicId, subId, content, replyTo) => {
|
||||||
let token = this.loadData("token");
|
let token = this.loadData("token");
|
||||||
if(!token){
|
if (!token) {
|
||||||
throw "未登录"
|
throw "未登录"
|
||||||
}
|
}
|
||||||
if(!replyTo){
|
if (!replyTo) {
|
||||||
replyTo = '';
|
replyTo = '';
|
||||||
}
|
}
|
||||||
let res = await Network.post(
|
let res = await Network.post(
|
||||||
@@ -659,19 +702,19 @@ class CopyManga extends ComicSource {
|
|||||||
`comic_id=${subId}&comment=${encodeURIComponent(content)}&reply_id=${replyTo}`,
|
`comic_id=${subId}&comment=${encodeURIComponent(content)}&reply_id=${replyTo}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (res.status === 401){
|
if (res.status === 401) {
|
||||||
error(`Login expired`);
|
error(`Login expired`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res.status !== 200){
|
if (res.status !== 200) {
|
||||||
throw `Invalid status code: ${res.status}`;
|
throw `Invalid status code: ${res.status}`;
|
||||||
} else {
|
} else {
|
||||||
return "ok"
|
return "ok"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onClickTag: (namespace, tag) => {
|
onClickTag: (namespace, tag) => {
|
||||||
if(namespace == "标签"){
|
if (namespace === "标签") {
|
||||||
return {
|
return {
|
||||||
// 'search' or 'category'
|
// 'search' or 'category'
|
||||||
action: 'category',
|
action: 'category',
|
||||||
@@ -680,7 +723,7 @@ class CopyManga extends ComicSource {
|
|||||||
param: null,
|
param: null,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(namespace == "作者"){
|
if (namespace === "作者") {
|
||||||
return {
|
return {
|
||||||
// 'search' or 'category'
|
// 'search' or 'category'
|
||||||
action: 'search',
|
action: 'search',
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
"name": "拷贝漫画",
|
"name": "拷贝漫画",
|
||||||
"fileName": "copy_manga.js",
|
"fileName": "copy_manga.js",
|
||||||
"key": "copy_manga",
|
"key": "copy_manga",
|
||||||
"version": "1.0.4"
|
"version": "1.0.5"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Komiic",
|
"name": "Komiic",
|
||||||
|
Reference in New Issue
Block a user