UNPKG

rsshub

Version:
106 lines (104 loc) 4.22 kB
import { t as config } from "./config-MQ-7ebJ_.mjs"; import "./logger-C4avouvV.mjs"; import { t as parseDate } from "./parse-date-r5WDWHno.mjs"; import "./is-worker-DESPicPc.mjs"; import { t as cache_default } from "./cache-SV6W5EPy.mjs"; import "./proxy-CjvoY5ys.mjs"; import { t as invalid_parameter_default } from "./invalid-parameter-ByDtry1B.mjs"; import { n as puppeteer_default } from "./puppeteer-9J9JS5H4.mjs"; import { n as queryToBoolean, t as fallback } from "./readable-social-CExV9fL0.mjs"; import { i as templates, n as proxyVideo, r as resolveUrl, t as getOriginAvatar } from "./utils-BG9dsAxw.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 = (embed && videoList ? templates.embed : templates.cover)({ img, videoList, duration }); media = embed && videoList && iframe ? templates.iframe({ content: media }) : media; const description = 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 };