UNPKG

rsshub

Version:
102 lines (93 loc) 3.91 kB
import { Route } from '@/types'; import ofetch from '@/utils/ofetch'; import { load } from 'cheerio'; import { parseDate } from '@/utils/parse-date'; import cache from '@/utils/cache'; import path from 'node:path'; import { art } from '@/utils/render'; const render = (data) => art(path.join(__dirname, 'templates/article.art'), data); export const route: Route = { path: '/topic/:topic/:language?', categories: ['traditional-media'], example: '/vice/topic/politics/en', parameters: { topic: 'Can be found in the URL', language: 'defaults to `en`, use the website to discover other codes', }, radar: [ { source: ['www.vice.com/:language/topic/:topic'], target: '/topic/:topic/:language', }, ], name: 'Topic', maintainers: ['K33k0'], handler, url: 'vice.com/', }; async function handler(ctx) { const { language = 'en', topic } = ctx.req.param(); const response = await ofetch(`https://www.vice.com/${language}/topic/${topic}`); const $ = load(response); const nextData = JSON.parse($('script#__NEXT_DATA__').text()); const list = nextData.props.pageProps.listPageData.articles.map((item) => ({ title: item.title, link: `https://vice.com${item.url}`, pubDate: parseDate(item.publish_date, 'x'), author: item.contributions.map((c) => c.contributor.full_name).join(', '), description: item.dek, category: [...new Set([item.primary_topic.name, ...item.topics.map((t) => t.name)])], })); const items = await Promise.all( list.map((item) => cache.tryGet(item.link, async () => { const response = await ofetch(item.link); const $ = load(response); const articleNextData = JSON.parse($('script#__NEXT_DATA__').text()).props.pageProps.data.articles[0]; const bodyComponent = JSON.parse(articleNextData.body_components_json); item.description = render({ image: { url: articleNextData.thumbnail_url, alt: articleNextData.caption, caption: articleNextData.caption, credit: articleNextData.credit, }, }) + bodyComponent .map((component) => { switch (component.role) { case 'body': return render({ body: { html: component.html } }); case 'heading2': return render({ heading2: { html: component.html } }); case 'image': return render({ image: { url: component.URL, alt: component.alt, caption: component.caption, }, }); case 'oembed': case 'tweet': case 'youtube': return render({ oembed: { html: component.oembed.html } }); default: return ''; } }) .join(''); return item; }) ) ); return { // channel title title: `VICE | ${topic} articles`, // channel link link: `https://vice.com/${language}/topic/${topic}`, // each feed item item: items, }; }