UNPKG

rsshub

Version:
84 lines (82 loc) 3.67 kB
import "./esm-shims-CzJ_djXG.mjs"; import { t as config } from "./config-C37vj7VH.mjs"; import "./dist-BInvbO1W.mjs"; import "./logger-Czu8UMNd.mjs"; import { t as ofetch_default } from "./ofetch-BIyrKU3Y.mjs"; import { t as parseDate } from "./parse-date-BrP7mxXf.mjs"; import { t as cache_default } from "./cache-Bo__VnGm.mjs"; import { load } from "cheerio"; //#region lib/routes/apple/podcast.ts const route = { path: "/podcast/:id/:region?", categories: ["multimedia"], example: "/apple/podcast/id1559695855/cn", parameters: { id: "播客id,可以在 Apple 播客app 内分享的播客的 URL 中找到", region: "地區代碼,例如 cn、us、jp,預設為 cn" }, features: { requireConfig: false, requirePuppeteer: false, antiCrawler: false, supportBT: false, supportPodcast: false, supportScihub: false }, radar: [{ source: ["podcasts.apple.com/:region/podcast/:showName/:id", "podcasts.apple.com/:region/podcast/:id"] }], name: "播客", maintainers: ["Acring"], handler, url: "www.apple.com/apple-podcasts/" }; async function handler(ctx) { const { id, region } = ctx.req.param(); const numericId = id.match(/id(\d+)/)?.[1]; const baseUrl = "https://podcasts.apple.com"; const $ = load(await ofetch_default(`${baseUrl}/${region || `cn`}/podcast/${id}`)); const header = JSON.parse($("#serialized-server-data").text())[0].data.shelves.find((item) => item.contentType === "showHeaderRegular").items[0]; const bearerToken = await cache_default.tryGet("apple:podcast:bearer", async () => { const moduleAddress = new URL($("head script[type=\"module\"]").attr("src"), baseUrl).href; return (await ofetch_default(moduleAddress, { parseResponse: (txt) => txt })).match(/="(eyJhbGci.*?)",/)[1]; }, config.cache.contentExpire, false); const episodeReponse = await ofetch_default(`https://amp-api.podcasts.apple.com/v1/catalog/us/podcasts/${numericId}/episodes`, { query: { "extend[podcast-channels]": "editorialArtwork,subscriptionArtwork,subscriptionOffers", include: "channel", limit: 25, with: "entitlements", l: "en-US" }, headers: { Authorization: `Bearer ${bearerToken}`, Origin: baseUrl } }); const episodes = episodeReponse.data.map(({ attributes: item }) => { const offer = item.offers[0]; return { title: item.name, enclosure_url: item.assetUrl || offer.hlsUrl, enclosure_type: item.assetUrl ? "audio/mp4" : "application/vnd.apple.mpegurl", itunes_duration: (item.durationInMilliseconds || offer.durationInMilliseconds) / 1e3, link: item.url, pubDate: parseDate(item.releaseDateTime), description: item.description.standard.replaceAll("\n", "<br>"), author: item.artistName, itunes_item_image: item.artwork.url.replace(/\{w\}x\{h\}(?:\{c\}|bb)\.\{f\}/, "3000x3000bb.webp"), category: item.genreNames }; }); const channel = episodeReponse.data.find((d) => d.type === "podcast-episodes").relationships.channel.data.find((d) => d.type === "podcast-channels")?.attributes; return { title: channel?.name ?? header.title, link: channel?.url ?? header.contextAction.podcastOffer.storeUrl, itunes_author: header.contextAction.podcastOffer.author, item: episodes, description: (header.description || channel?.description.standard)?.replaceAll("\n", " "), image: ((channel?.logoArtwork || channel?.subscriptionArtwork)?.url || header.contextAction.podcastOffer.artwork.template).replace(/\{w\}x\{h\}(?:\{c\}|bb)\.\{f\}/, "3000x3000bb.webp"), itunes_category: header.metadata.find((d) => Object.hasOwn(d, "category")).category?.title || header.metadata.find((d) => Object.hasOwn(d, "category")).category }; } //#endregion export { route };