rsshub
Version:
Make RSS Great Again!
107 lines (105 loc) • 4.29 kB
JavaScript
import "./esm-shims-CzJ_djXG.mjs";
import { t as config } from "./config-C37vj7VH.mjs";
import "./logger-Czu8UMNd.mjs";
import { t as parseDate } from "./parse-date-BrP7mxXf.mjs";
import { t as cache_default } from "./cache-Bo__VnGm.mjs";
import { t as art } from "./render-BQo6B4tL.mjs";
import "./proxy-Db7uGcYb.mjs";
import { t as invalid_parameter_default } from "./invalid-parameter-rr4AgGpp.mjs";
import { n as puppeteer_default } from "./puppeteer-DGmvuGvT.mjs";
import { n as queryToBoolean, t as fallback } from "./readable-social-DoIL4WB3.mjs";
import { i as templates, n as proxyVideo, r as resolveUrl, t as getOriginAvatar } from "./utils-CQKS3rFA.mjs";
//#region lib/routes/douyin/hashtag.ts
const route = {
path: "/hashtag/:cid/:routeParams?",
categories: ["social-media"],
example: "/douyin/hashtag/1592824105719812",
parameters: {
cid: "标签 ID,可在标签页面 URL 中找到",
routeParams: "额外参数,query string 格式,请参阅上面的表格"
},
features: {
requireConfig: false,
requirePuppeteer: true,
antiCrawler: true,
supportBT: false,
supportPodcast: false,
supportScihub: false
},
radar: [{
source: ["douyin.com/hashtag/:cid"],
target: "/hashtag/:cid"
}],
name: "标签",
maintainers: ["TonyRL"],
handler
};
async function handler(ctx) {
const cid = ctx.req.param("cid");
if (Number.isNaN(cid)) throw new invalid_parameter_default("Invalid tag ID. Tag ID should be a number.");
const routeParams = Object.fromEntries(new URLSearchParams(ctx.req.param("routeParams")));
const embed = fallback(void 0, queryToBoolean(routeParams.embed), false);
const iframe = fallback(void 0, queryToBoolean(routeParams.iframe), false);
const relay = resolveUrl(routeParams.relay, true, true);
const tagUrl = `https://www.douyin.com/hashtag/${cid}`;
const tagData = await cache_default.tryGet(`douyin:hashtag:${cid}`, async () => {
const browser = await puppeteer_default();
const page = await browser.newPage();
await page.setRequestInterception(true);
let awemeList = "";
page.on("request", (request) => {
request.resourceType() === "document" || request.resourceType() === "script" || request.resourceType() === "xhr" ? request.continue() : request.abort();
});
page.on("response", async (response) => {
if (response.request().url().includes("/v1/web/challenge/aweme")) awemeList = await response.json();
});
await page.goto(tagUrl, { waitUntil: "networkidle2" });
await page.waitForSelector("#RENDER_DATA");
const html = await page.evaluate(() => document.querySelector("#RENDER_DATA").textContent);
await browser.close();
const renderData = JSON.parse(decodeURIComponent(html));
const dataKey = Object.keys(renderData).find((key) => renderData[key].topicDetail);
renderData[dataKey].defaultData = awemeList.aweme_list;
return renderData[dataKey];
}, config.cache.routeExpire, false);
const tagInfo = tagData.topicDetail;
const tagName = tagInfo.chaName;
const userAvatar = getOriginAvatar(tagInfo.hashtagProfile);
const items = tagData.defaultData.map((post) => {
let videoList = post.video && post.video.bit_rate && post.video.bit_rate.map((bit_rate) => resolveUrl(bit_rate.play_addr.url_list[0]));
if (relay) videoList = videoList.map((item) => proxyVideo(item, relay));
let duration = post.video && post.video.duration;
duration = duration && duration / 1e3;
let img;
img = img || post.video && post.video.origin_cover && post.video.origin_cover.url_list.at(-1);
img = img && resolveUrl(img);
const desc = post.desc && post.desc.replaceAll("\n", "<br>");
let media = art(embed && videoList ? templates.embed : templates.cover, {
img,
videoList,
duration
});
media = embed && videoList && iframe ? art(templates.iframe, { content: media }) : media;
const description = art(templates.desc, {
desc,
media
});
return {
title: post.desc,
description,
link: `https://www.douyin.com/video/${post.aweme_id}`,
pubDate: parseDate(post.create_time, "X"),
category: post.text_extra.map((extra) => extra.hashtag_name),
author: post.author.nickname
};
});
return {
title: tagName,
description: `${tagInfo.viewCount} 次播放`,
image: userAvatar,
link: tagUrl,
item: items
};
}
//#endregion
export { route };