diff --git a/docs/en/new-media.md b/docs/en/new-media.md index fb8c7628c2c17..ddde6afd89d25 100644 --- a/docs/en/new-media.md +++ b/docs/en/new-media.md @@ -434,6 +434,16 @@ Provides a better reading experience (full text articles) over the official one. +## Kuwait Local + +### Latest News + + + +### Categorised News + + + ## Letterboxd ### User diary diff --git a/docs/en/traditional-media.md b/docs/en/traditional-media.md index 7e7a3aab3626a..0be094d436bd7 100644 --- a/docs/en/traditional-media.md +++ b/docs/en/traditional-media.md @@ -160,6 +160,18 @@ Generates full-text feeds that the official feed doesn't provide. +## CNBC + +### Full article RSS + + + +Provides a better reading experience (full articles) over the official ones. + +Support all channels, refer to [CNBC RSS feeds](https://www.cnbc.com/rss-feeds/). + + + ## Deutsche Welle ### News diff --git a/docs/programming.md b/docs/programming.md index c510b5bc1306b..3bbe87dc03f87 100644 --- a/docs/programming.md +++ b/docs/programming.md @@ -720,7 +720,7 @@ GitHub 官方也提供了一些 RSS: ### 分类订阅 - + | 360 网络安全周报 | 活动 | 知识 | 资讯 | 招聘 | 工具 | | ---------- | -------- | --------- | ---- | --- | ---- | diff --git a/docs/traditional-media.md b/docs/traditional-media.md index 98371dc0ef48b..6a0b39e628d08 100644 --- a/docs/traditional-media.md +++ b/docs/traditional-media.md @@ -141,6 +141,18 @@ pageClass: routes +## CNBC + +### 全文 RSS + + + +通过提取文章全文,以提供比官方源更佳的阅读体验。 + +支持所有频道,频道名称见 [官方频道 RSS](https://www.cnbc.com/rss-feeds/)。 + + + ## Deutsche Welle 德国之声 ### 新闻 diff --git a/lib/v2/anquanke/category.js b/lib/v2/anquanke/category.js index cc4262e491131..be7ec7bddc3b1 100644 --- a/lib/v2/anquanke/category.js +++ b/lib/v2/anquanke/category.js @@ -1,21 +1,35 @@ const got = require('@/utils/got'); +const cheerio = require('cheerio'); const { parseDate } = require('@/utils/parse-date'); const timezone = require('@/utils/timezone'); module.exports = async (ctx) => { const api = 'https://api.anquanke.com/data/v1/posts?size=10&page=1&category='; const type = ctx.params.category; + const fulltext = ctx.params.fulltext; const host = 'https://www.anquanke.com'; const res = await got(`${api}${type}`); const dataArray = res.data.data; - const items = dataArray.map((item) => ({ - title: item.title, - description: item.desc, - pubDate: timezone(parseDate(item.date), +8), - link: `${host}/${type === 'week' ? 'week' : 'post'}/id/${item.id}`, - author: item.author.nickname, - })); + const items = await Promise.all( + dataArray.map(async (item) => { + const art_url = `${host}/${type === 'week' ? 'week' : 'post'}/id/${item.id}`; + return { + title: item.title, + description: + fulltext === 'fulltext' || fulltext === 'quanwen' + ? await ctx.cache.tryGet(art_url, async () => { + const { data: res } = await got(art_url); + const content = cheerio.load(res); + return content('#js-article').html(); + }) + : item.desc, + pubDate: timezone(parseDate(item.date), +8), + link: art_url, + author: item.author.nickname, + }; + }) + ); ctx.state.data = { title: `安全客-${dataArray[0].category_name}`, diff --git a/lib/v2/anquanke/maintainer.js b/lib/v2/anquanke/maintainer.js index e247fa46d95a2..0dc8f87b540c9 100644 --- a/lib/v2/anquanke/maintainer.js +++ b/lib/v2/anquanke/maintainer.js @@ -1,4 +1,4 @@ module.exports = { // '/vul': ['qwertyuiop6'], - '/:category': ['qwertyuiop6'], + '/:category/:fulltext?': ['qwertyuiop6'], }; diff --git a/lib/v2/anquanke/router.js b/lib/v2/anquanke/router.js index 7cc1f079a5ad4..08674bf4e3f15 100644 --- a/lib/v2/anquanke/router.js +++ b/lib/v2/anquanke/router.js @@ -1,4 +1,4 @@ module.exports = (router) => { // router.get('/vul', require('./vul')); // 404 - router.get('/:category', require('./category')); + router.get('/:category/:fulltext?', require('./category')); }; diff --git a/lib/v2/cnbc/maintainer.js b/lib/v2/cnbc/maintainer.js new file mode 100644 index 0000000000000..3507ac9104802 --- /dev/null +++ b/lib/v2/cnbc/maintainer.js @@ -0,0 +1,3 @@ +module.exports = { + '/rss/:id?': ['TonyRL'], +}; diff --git a/lib/v2/cnbc/radar.js b/lib/v2/cnbc/radar.js new file mode 100644 index 0000000000000..4bb265ec7eb79 --- /dev/null +++ b/lib/v2/cnbc/radar.js @@ -0,0 +1,21 @@ +module.exports = { + 'cnbc.com': { + _name: 'CNBC', + search: [ + { + title: '全文 RSS', + docs: 'https://docs.rsshub.app/traditional-media.html#cnbc', + source: ['/rs/search/combinedcms/view.xml'], + target: (_, url) => `/cnbc/rss/${new URL(url).searchParams.get('id')}`, + }, + ], + www: [ + { + title: '全文 RSS', + docs: 'https://docs.rsshub.app/traditional-media.html#cnbc', + source: ['/id/:id/device/rss/rss.html'], + target: '/cnbc/rss/:id', + }, + ], + }, +}; diff --git a/lib/v2/cnbc/router.js b/lib/v2/cnbc/router.js new file mode 100644 index 0000000000000..14adb726dd19f --- /dev/null +++ b/lib/v2/cnbc/router.js @@ -0,0 +1,3 @@ +module.exports = (router) => { + router.get('/rss/:id?', require('./rss')); +}; diff --git a/lib/v2/cnbc/rss.js b/lib/v2/cnbc/rss.js new file mode 100644 index 0000000000000..3ca95705fa60b --- /dev/null +++ b/lib/v2/cnbc/rss.js @@ -0,0 +1,54 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const parser = require('@/utils/rss-parser'); + +module.exports = async (ctx) => { + const { id = '100003114' } = ctx.params; + const feed = await parser.parseURL(`https://search.cnbc.com/rs/search/combinedcms/view.xml?partnerId=wrss01&id=${id}`); + + const items = await Promise.all( + feed.items + .filter((i) => !i.link.startsWith('https://www.cnbc.com/select/')) + .map((item) => + ctx.cache.tryGet(item.link, async () => { + const { data: response } = await got(item.link); + const $ = cheerio.load(response); + + delete item.content; + delete item.contentSnippet; + delete item.isoDate; + + item.description = ''; + if ($('.RenderKeyPoints-keyPoints').length) { + $('.RenderKeyPoints-keyPoints').html(); + } + if ($('.FeaturedContent-articleBody').length) { + item.description += $('.FeaturedContent-articleBody').html(); + } + if ($('.ArticleBody-articleBody').length) { + item.description += $('.ArticleBody-articleBody').html(); + } + if ($('.LiveBlogBody-articleBody').length) { + item.description += $('.LiveBlogBody-articleBody').html(); + } + if ($('.ClipPlayer-clipPlayer').length) { + item.description += $('.ClipPlayer-clipPlayer').html(); + } + + const meta = JSON.parse($('[type=application/ld+json]').last().text()); + item.author = meta.author ? (meta.author.name ? meta.author.name : meta.author.map((a) => a.name).join(', ')) : null; + item.category = meta.keywords; + + return item; + }) + ) + ); + + ctx.state.data = { + title: feed.title, + link: feed.link, + description: feed.description, + item: items, + language: feed.language, + }; +}; diff --git a/lib/v2/kuwaitlocal/index.js b/lib/v2/kuwaitlocal/index.js new file mode 100644 index 0000000000000..0184b2ca7eca0 --- /dev/null +++ b/lib/v2/kuwaitlocal/index.js @@ -0,0 +1,47 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const { parseDate } = require('@/utils/parse-date'); + +const baseUrl = 'https://kuwaitlocal.com'; + +module.exports = async (ctx) => { + const { category = 'latest' } = ctx.params; + const url = `${baseUrl}/news/${category === 'latest' ? category : `categories/${category}`}`; + + const { data: response } = await got(url); + const $ = cheerio.load(response); + const list = $('.news_list a') + .toArray() + .map((item) => { + item = $(item); + return { + title: item.text(), + link: baseUrl + item.attr('href'), + }; + }); + + const items = await Promise.all( + list.map((item) => + ctx.cache.tryGet(item.link, async () => { + const { data: response } = await got(item.link); + const $ = cheerio.load(response); + + item.pubDate = parseDate($('.date_icon').next().text()); + $('[id^=div-gpt-ad], .pad_10_0, .hide_desktop').remove(); + item.description = $('.mob_pad_view').html(); + item.category = $('.news_tags a') + .toArray() + .map((item) => $(item).text()); + return item; + }) + ) + ); + + ctx.state.data = { + title: $('head title').text().trim(), + description: $('head meta[name="description"]').attr('content').trim(), + link: url, + item: items, + language: 'en', + }; +}; diff --git a/lib/v2/kuwaitlocal/maintainer.js b/lib/v2/kuwaitlocal/maintainer.js new file mode 100644 index 0000000000000..385dc7d47a51a --- /dev/null +++ b/lib/v2/kuwaitlocal/maintainer.js @@ -0,0 +1,4 @@ +module.exports = { + '/': ['TonyRL'], + '/:category?': ['TonyRL'], +}; diff --git a/lib/v2/kuwaitlocal/radar.js b/lib/v2/kuwaitlocal/radar.js new file mode 100644 index 0000000000000..c60853ca36cca --- /dev/null +++ b/lib/v2/kuwaitlocal/radar.js @@ -0,0 +1,19 @@ +module.exports = { + 'kuwaitlocal.com': { + _name: 'Kuwait Local', + '.': [ + { + title: 'Latest News', + docs: 'https://docs.rsshub.app/en/new-media.html#kuwait-local', + source: ['/news/latest', '/news', '/'], + target: '/kuwaitlocal', + }, + { + title: 'Categorised News', + docs: 'https://docs.rsshub.app/en/new-media.html#kuwait-local', + source: ['/news/categories/:category'], + target: '/kuwaitlocal/:category', + }, + ], + }, +}; diff --git a/lib/v2/kuwaitlocal/router.js b/lib/v2/kuwaitlocal/router.js new file mode 100644 index 0000000000000..9885c36f13481 --- /dev/null +++ b/lib/v2/kuwaitlocal/router.js @@ -0,0 +1,3 @@ +module.exports = (router) => { + router.get('/:category?', require('./index')); +}; diff --git a/lib/v2/wallstreetcn/live.js b/lib/v2/wallstreetcn/live.js index 7e584ddd164e3..ee32c0c7a6651 100644 --- a/lib/v2/wallstreetcn/live.js +++ b/lib/v2/wallstreetcn/live.js @@ -1,5 +1,7 @@ const got = require('@/utils/got'); const { parseDate } = require('@/utils/parse-date'); +const { art } = require('@/utils/render'); +const path = require('path'); const titles = { global: '要闻', @@ -30,9 +32,13 @@ module.exports = async (ctx) => { .map((item) => ({ link: item.uri, title: item.title || item.content_text, - description: item.content + (item.content_more ?? ''), pubDate: parseDate(item.display_time * 1000), author: item.author?.display_name ?? '', + description: art(path.join(__dirname, 'templates/description.art'), { + description: item.content, + more: item.content_more, + images: item.images, + }), })); ctx.state.data = { diff --git a/lib/v2/wallstreetcn/templates/description.art b/lib/v2/wallstreetcn/templates/description.art new file mode 100644 index 0000000000000..ee1f9e6f22831 --- /dev/null +++ b/lib/v2/wallstreetcn/templates/description.art @@ -0,0 +1,11 @@ +{{ if description }} +{{@ description }} +{{ /if }} +{{ if more }} +{{@ more }} +{{ /if }} +{{ if images }} +{{ each images image }} + +{{ /each }} +{{ /if }} \ No newline at end of file