UNPKG

rsshub

Version:
121 lines (118 loc) 4.26 kB
import { n as init_esm_shims, t as __dirname } from "./esm-shims-CzJ_djXG.mjs"; import { t as config } from "./config-C37vj7VH.mjs"; import { t as ViewType } from "./types-D84BRIt4.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 md5 } from "./md5-C8GRvctM.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"; //#region lib/routes/tingtingfm/utils.ts init_esm_shims(); const SALT = "1Ftjv0bfpVmqbE38"; const getClientVal = (length) => { let result = ""; const randomChar = () => { const random = Math.floor(62 * Math.random()); if (random < 10) return random; else if (random < 36) return String.fromCharCode(random + 55); else return String.fromCharCode(random + 61); }; while (result.length < length) result += randomChar(); return `h5_${result}`; }; const sign = (params) => { const searchParams = new URLSearchParams(params); searchParams.sort(); return md5(`${searchParams.toString()}_${SALT}`); }; //#endregion //#region lib/routes/tingtingfm/program.ts const route = { path: "/program/:programId", categories: ["multimedia"], view: ViewType.Audios, example: "/tingtingfm/program/M7VJv6Jj4R", parameters: { programId: "节目 ID,可以在 URL 中找到" }, features: { requireConfig: false, requirePuppeteer: false, antiCrawler: false, supportBT: false, supportPodcast: true, supportScihub: false }, radar: [{ source: ["mobile.tingtingfm.com/v3/program/:programId"] }], name: "节目", maintainers: ["TonyRL"], handler }; async function handler(ctx) { const programId = ctx.req.param("programId"); const apiBaseUrl = "https://api-v3.tingtingfm.com"; const mobileBaseUrl = "https://mobile.tingtingfm.com"; const params = { version: "h5_5.16", client: getClientVal(30), h_program_id: programId }; const radioInfo = await cache_default.tryGet(`tingtingfm:program:${programId}`, async () => { const { data: response } = await got_default.post(`${apiBaseUrl}//broadcast/get_program_v3_8`, { searchParams: { ...params, api_sign: sign(params) } }); if (response.errno !== 0) throw new Error(response.error); return response.data.info; }); const latestAudio = await cache_default.tryGet(`tingtingfm:audio_list:${programId}`, async () => { const { data: response } = await got_default.post(`${apiBaseUrl}//broadcast/get_program_audio_list`, { searchParams: { ...params, api_sign: sign(params) } }); if (response.errno !== 0) throw new Error(response.error); return response.data[0]; }, config.cache.routeExpire, false); const { radioCover, list } = await cache_default.tryGet(`tingtingfm:play_audio:${programId}`, async () => { const playAudioParams = { ...Object.fromEntries(Object.entries(params).filter(([key]) => key !== "h_program_id")), type: "", sort: "-1", audio_id: latestAudio.h_audio_id }; const { data: response } = await got_default.post(`${apiBaseUrl}//albumaudio/play_audio`, { searchParams: { ...playAudioParams, api_sign: sign(playAudioParams) } }); if (response.errno !== 0) throw new Error(response.error); return { radioCover: response.data.info.radio_cover, list: response.data.list }; }, config.cache.routeExpire, false); const items = list.map((audio) => ({ title: audio.title, link: `${mobileBaseUrl}/v3/vod/2/${audio.h_audio_id}`, description: art(path.join(__dirname, "templates/audio-a76b0dc2.art"), { url: audio.play_url }), pubDate: parseDate(audio.add_time, "X"), itunes_item_image: radioCover, itunes_duration: audio.duration, enclosure_url: audio.play_url, enclosure_type: "audio/x-m4a" })); return { title: `${radioInfo.title} - ${radioInfo.belong_radio}${radioInfo.belong_fm}`, description: radioInfo.description, link: `${mobileBaseUrl}/v3/program/${programId}`, image: radioInfo.cover.split("?x-oss")[0], itunes_author: radioInfo.anchor.join(", "), itunes_category: radioInfo.category, itunes_explicit: false, item: items }; } //#endregion export { route };