rsshub
Version:
Make RSS Great Again!
135 lines (132 loc) • 4.61 kB
JavaScript
import { n as init_esm_shims, t as __dirname } from "./esm-shims-CzJ_djXG.mjs";
import "./config-C37vj7VH.mjs";
import "./dist-BInvbO1W.mjs";
import "./logger-Czu8UMNd.mjs";
import "./ofetch-BIyrKU3Y.mjs";
import { t as parseDate } from "./parse-date-BrP7mxXf.mjs";
import { t as cache_default } from "./cache-Bo__VnGm.mjs";
import "./helpers-DxBp0Pty.mjs";
import { t as art } from "./render-BQo6B4tL.mjs";
import { t as got_default } from "./got-KxxWdaxq.mjs";
import path from "node:path";
import CryptoJS from "crypto-js";
//#region lib/routes/creative-comic/utils.ts
init_esm_shims();
const apiHost = "https://api.creative-comic.tw";
const device = "web_desktop";
const DEFAULT_TOKEN = "freeforccc2020reading";
const getBook = (bookId, uuid) => got_default(`${apiHost}/book/${bookId}/info`, { headers: {
device,
uuid
} });
const getChapter = (id, uuid) => got_default(`${apiHost}/book/chapter/${id}`, { headers: {
device,
uuid
} });
const getChapters = (bookId, uuid) => got_default(`${apiHost}/book/${bookId}/chapter`, { headers: {
device,
uuid
} });
const getImgEncrypted = async (pageId, quality) => {
const { data: res } = await got_default(`https://storage.googleapis.com/ccc-www/fs/chapter_content/encrypt/${pageId}/${quality}`, {
headers: { device },
responseType: "buffer"
});
return Buffer.from(res).toString("base64");
};
const getImgKey = (pageId, uuid) => got_default(`${apiHost}/book/chapter/image/${pageId}`, { headers: {
device,
uuid
} });
const getUuid = (tryGet) => tryGet("creative-comic:uuid", async () => {
const { data } = await got_default(`${apiHost}/guest`, { headers: { device } });
return data.data;
});
const decrypt = (encrypted, secrets) => CryptoJS.AES.decrypt(encrypted, CryptoJS.enc.Hex.parse(secrets.key), {
iv: CryptoJS.enc.Hex.parse(secrets.iv),
mode: CryptoJS.mode.CBC,
padding: CryptoJS.pad.Pkcs7
}).toString(CryptoJS.enc.Utf8);
const token2Key = (token) => {
const t = CryptoJS.SHA512(token).toString();
return {
key: t.slice(0, 64),
iv: t.slice(30, 62)
};
};
const getRealKey = (imgKey, token = DEFAULT_TOKEN) => {
const realKey = decrypt(imgKey, token2Key(token)).split(":");
return {
key: realKey[0],
iv: realKey[1]
};
};
//#endregion
//#region lib/routes/creative-comic/book.ts
const route = {
path: "/book/:id/:coverOnly?/:quality?",
categories: ["anime"],
example: "/creative-comic/book/117",
parameters: {
id: "漫畫 ID,可在 URL 中找到",
coverOnly: "僅獲取封面,非 `true` 時將獲取**全部**頁面,預設 `true`",
quality: "閱讀品質,標準畫質 `1`,高畫質 `2`,預設 `1`"
},
features: {
requireConfig: false,
requirePuppeteer: false,
antiCrawler: false,
supportBT: false,
supportPodcast: false,
supportScihub: false
},
radar: [{
source: ["creative-comic.tw/book/:id/*"],
target: "/:id"
}],
name: "漫畫",
maintainers: ["TonyRL"],
handler
};
async function handler(ctx) {
const { id, coverOnly = "true", quality = "1" } = ctx.req.param();
const uuid = await getUuid(cache_default.tryGet);
const { data: { data: book } } = await getBook(id, uuid);
const { data: { data: chapters } } = await getChapters(id, uuid);
const items = await Promise.all(chapters.chapters.toSorted((a, b) => b.idx - a.idx).slice(0, ctx.req.query("limit") ? Number.parseInt(ctx.req.query("limit"), 10) : 3).map(async (c) => {
let pages;
if (coverOnly !== "true" && coverOnly !== "1") {
const { data: { data: chapter } } = await getChapter(c.id, uuid);
if (chapter.chapter.free_day === null || chapter.chapter.free_day === 0) pages = await Promise.all(chapter.chapter.proportion.map(async (p) => {
let { data: imgKey } = await getImgKey(p.id, uuid);
imgKey = imgKey.data.key;
const realKey = getRealKey(imgKey);
const encrypted = await getImgEncrypted(p.id, quality);
return cache_default.tryGet(`${apiHost}/fs/chapter_content/encrypt/${p.id}/${quality}`, () => decrypt(encrypted, realKey));
}));
}
return {
title: c.vol_name,
description: art(path.join(__dirname, "templates/chapter-a1c569be.art"), {
chapter: c,
pages,
cover: c.image1
}),
pubDate: parseDate(c.online_at),
updated: parseDate(c.updated_at),
link: `https://www.creative-comic.tw/reader_comic/${c.id}`,
author: book.author.map((author) => author.name).join(", "),
category: book.tags.map((tag) => tag.name)
};
}));
return {
title: `${book.name} | CCC創作集`,
description: `${book.brief} ${book.description}`,
link: book.share_link,
image: book.image1,
item: items,
language: "zh-hant"
};
}
//#endregion
export { route };