UNPKG

rsshub

Version:
116 lines (113 loc) • 4.91 kB
import "./dist-Bog6z_OM.mjs"; import "./config-MQ-7ebJ_.mjs"; import "./logger-C4avouvV.mjs"; import "./ofetch-DKl_Ma9g.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 "./helpers-Bo4JQYdN.mjs"; import { t as got_default } from "./got-CO-ndVl2.mjs"; import { Fragment, jsx, jsxs } from "hono/jsx/jsx-runtime"; import { load } from "cheerio"; import { renderToString } from "hono/jsx/dom/server"; //#region lib/routes/transcriptforest/templates/description.tsx const TranscriptForestDescription = ({ audios, texts }) => /* @__PURE__ */ jsxs(Fragment, { children: [audios?.map((audio) => audio?.src ? /* @__PURE__ */ jsxs("audio", { controls: true, children: [/* @__PURE__ */ jsx("source", { src: audio.src, type: audio.type }), /* @__PURE__ */ jsx("object", { data: audio.src, children: /* @__PURE__ */ jsx("embed", { src: audio.src }) })] }) : null), texts?.map((text) => /* @__PURE__ */ jsxs(Fragment, { children: [text.startTime && text.endTime ? /* @__PURE__ */ jsxs("small", { children: [ text.startTime, " - ", text.endTime ] }) : null, /* @__PURE__ */ jsx("p", { children: text.text })] }))] }); const renderDescription = (data) => renderToString(/* @__PURE__ */ jsx(TranscriptForestDescription, { ...data })); //#endregion //#region lib/routes/transcriptforest/index.ts const bakeTimestamp = (seconds) => { const hours = Math.floor(seconds / 3600); const minutes = Math.floor(seconds % 3600 / 60); const remainingSeconds = Math.floor(seconds % 60); return `${String(hours).padStart(2, "0")}:${String(minutes).padStart(2, "0")}:${String(remainingSeconds).padStart(2, "0")}`; }; const route = { path: "/:channel?", radar: [{ source: ["www.transcriptforest.com/en/channel"], target: "" }], name: "Unknown", maintainers: ["nczitzk"], handler, url: "www.transcriptforest.com/en/channel" }; async function handler(ctx) { const channel = ctx.req.param("channel"); const limit = ctx.req.query("limit") ? Number.parseInt(ctx.req.query("limit"), 10) : 10; const rootUrl = "https://www.transcriptforest.com"; const { data: firstResponse } = await got_default(rootUrl); const data = JSON.parse(firstResponse.match(/({"props".*"scriptLoader":\[]})<\/script>/)?.[1]); const buildId = data.buildId; const defaultLocale = data.defaultLocale; const channels = data.props.pageProps.listChannel; const selected = channel ? channels.find((c) => c.channel_id === channel || c.channel_name === channel) : void 0; const apiUrl = new URL(`_next/data/${buildId}/en${selected ? `/channel/${selected.channel_id}` : ""}.json`, rootUrl).href; const currentUrl = new URL(selected ? `${defaultLocale}/channel/${selected.channel_id}` : "", rootUrl).href; const { data: response } = await got_default(apiUrl, { searchParams: { channelName: selected ? selected.channel_id : "", offset: 0 } }); let items = response.pageProps.listEpisode.data.slice(0, limit).map((item) => ({ title: item.episode_name, link: new URL(`${defaultLocale}/${item.channel_id}/${item.episode_id}`, rootUrl).href, detailUrl: new URL(`_next/data/${buildId}/${defaultLocale}/${item.channel_id}/${item.episode_id}.json`, rootUrl).href, description: renderDescription({ texts: item.episode_description.split(/\n\n/).map((text) => ({ text })) }), author: item.channel_name, guid: item.id, pubDate: parseDate(item.published_at), updated: parseDate(item.updated_at), itunes_item_image: item.episode_cover.split(/\?/)[0], itunes_duration: item.episode_duration, enclosure_url: item.source_media, enclosure_type: "audio/mpeg" })); items = await Promise.all(items.map((item) => cache_default.tryGet(item.link, async () => { const { data: detailResponse } = await got_default(item.detailUrl); const { data: textResponse } = await got_default(detailResponse.pageProps.currentEpisode.ps4_url); item.description = renderDescription({ audios: [{ src: detailResponse.pageProps.currentEpisode.media, type: "audio/mpeg" }] }) + item.description + renderDescription({ texts: textResponse.map((t) => ({ startTime: bakeTimestamp(t.startTime), endTime: bakeTimestamp(t.endTime), text: t.readOnlyText })) }); delete item.detailUrl; return item; }))); const { data: currentResponse } = await got_default(currentUrl); const $ = load(currentResponse); const title = $("title").text(); const image = $("meta[property=\"og:image\"]").prop("content"); const icon = new URL($("link[rel=\"apple-touch-icon\"]").prop("href"), rootUrl).href; const author = title.split(/\|/)[0].trim(); return { item: items, title, link: currentUrl, description: $("meta[name=\"description\"]").prop("content"), language: $("html").prop("lang"), image, icon, logo: icon, author, itunes_author: author, allowEmpty: true }; } //#endregion export { route };