diff --git a/docs/traditional-media.md b/docs/traditional-media.md index 5a8af46b9a..8b89581e7c 100644 --- a/docs/traditional-media.md +++ b/docs/traditional-media.md @@ -714,9 +714,111 @@ IT・科学 tech_science ## 第一财经 -### 直播区 +### 最新 - + + +### 头条 + + + +### VIP 频道 + + + +### 新闻 + + + +| Id | 名称 | +| ---------------------- | ------- | +| gushi | A 股 | +| kechuangban | 科创板 | +| hongguan | 大政 | +| jinrong | 金融 | +| quanqiushichang | 海外市场 | +| gongsi | 产经 | +| shijie | 全球 | +| kechuang | 科技 | +| quyu | 区域 | +| comment | 评论 | +| dafengwenhua | 商业人文 | +| books | 阅读周刊 | +| loushi | 地产 | +| automobile | 汽车 | +| china_financial_herald | 对话陆家嘴 | +| fashion | 时尚 | +| ad | 商业资讯 | +| info | 资讯 | +| jzfxb | 价值风向标 | +| shuducaijing | 数读财经 | +| shujujiepan | 数据解盘 | +| shudushenghuo | 数读生活 | +| cbndata | CBNData | +| dtcj | DT 财经 | +| xfsz | 消费数知 | + +### 关注 + + + +::: tip 提示 + +全部主题词见 [此处](https://www.yicai.com/feed/alltheme) + +::: + + + +### 视听 + + + +| Id | 名称 | +| -------------------- | -------------- | +| youliao | 有料 | +| appshipin | 此刻 | +| yicaisudi | 速递 | +| caishang | 财商 | +| shiji | 史记 | +| jinrigushi | 今日股市 | +| tangulunjin | 谈股论金 | +| gongsiyuhangye | 公司与行业 | +| cjyxx | 财经夜行线 | +| 6thtradingday | 第六交易日 | +| cjfw | 财经风味 | +| chuangshidai | 创时代 | +| weilaiyaoqinghan | 未来邀请函 | +| tounaofengbao | 头脑风暴 | +| zhongguojingyingzhe | 中国经营者 | +| shichanglingjuli | 市场零距离 | +| huanqiucaijing | 环球财经视界 | +| zgjcqyjglsxftl | 中国杰出企业家管理思想访谈录 | +| jiemacaishang | 解码财商 | +| sxpl | 首席评论 | +| zhongguojingjiluntan | 中国经济论坛 | +| opinionleader | 意见领袖 | +| xinjinrong | 解码新金融 | +| diyidichan | 第一地产 | +| zhichedaren | 智车达人 | +| chuangtoufengyun | 创投风云 | +| chunxiangrensheng | 醇享人生 | +| diyishengyin | 第一声音 | +| sanliangboqianjin | 财智双全 | +| weilaiyaoqinghan | 未来邀请函 | +| zjdy | 主角 ▪ 大医 | +| leye | 乐业之城 | +| sanrenxing | 价值三人行 | +| yuandongli | 中国源动力 | +| pioneerzone | 直击引领区 | + +### 正在 + + + +### 一财号 + + ## 东方网 diff --git a/lib/router.js b/lib/router.js index f04d80ad7c..3da1d79a99 100644 --- a/lib/router.js +++ b/lib/router.js @@ -1872,7 +1872,7 @@ router.get('/zcool/top', lazyloadRouteHandler('./routes/zcool/top')); // 兼容 router.get('/zcool/user/:uid', lazyloadRouteHandler('./routes/zcool/user')); // 第一财经 -router.get('/yicai/brief', lazyloadRouteHandler('./routes/yicai/brief.js')); +// router.get('/yicai/brief', lazyloadRouteHandler('./routes/yicai/brief.js')); // 一兜糖 router.get('/yidoutang/index', lazyloadRouteHandler('./routes/yidoutang/index.js')); diff --git a/lib/routes/yicai/brief.js b/lib/routes/yicai/brief.js deleted file mode 100644 index deba8af668..0000000000 --- a/lib/routes/yicai/brief.js +++ /dev/null @@ -1,34 +0,0 @@ -const date = require('@/utils/date'); -const got = require('@/utils/got'); - -module.exports = async (ctx) => { - const baseUrl = 'https://www.yicai.com'; - const url = `${baseUrl}/api/ajax/getbrieflist`; - const query = { - pagesize: 30, - type: 0, - page: 0, - }; - const response = await got(url, { - query, - }); - - const resList = response.data; - const item = resList.map((obj) => { - const { datekey, istop, url, newcontent, hm, indexTitle } = obj; - const dateStr = `${datekey.replace(/\./g, '-')} ${hm}`; - return { - title: indexTitle.length === newcontent.length ? indexTitle : `${indexTitle}...`, - description: [istop ? '置顶:' : '', newcontent].filter((str) => !!str).join('
'), - pubDate: date(dateStr, +8), - link: `${baseUrl}${url}`, - }; - }); - - ctx.state.data = { - title: `第一财经 - 直播区`, - description: `第一财经 - 直播区`, - link: `${baseUrl}/brief`, - item, - }; -}; diff --git a/lib/v2/yicai/author.js b/lib/v2/yicai/author.js new file mode 100644 index 0000000000..2f123e4eeb --- /dev/null +++ b/lib/v2/yicai/author.js @@ -0,0 +1,26 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); + +const { rootUrl, ProcessItems } = require('./utils'); + +module.exports = async (ctx) => { + const id = ctx.params.id ?? '100005663'; + + const currentUrl = `${rootUrl}/author/${id}.html`; + const apiUrl = `${rootUrl}/api/ajax/getlistbysid?id=${id}&page=1&pagesize=${ctx.query.limit ?? 30}`; + + const response = await got({ + method: 'get', + url: currentUrl, + }); + + const $ = cheerio.load(response.data); + + const items = await ProcessItems(apiUrl, ctx.cache.tryGet); + + ctx.state.data = { + title: `第一财经一财号 - ${$('title').text()}`, + link: currentUrl, + item: items, + }; +}; diff --git a/lib/v2/yicai/brief.js b/lib/v2/yicai/brief.js new file mode 100644 index 0000000000..eeb1b6b1a7 --- /dev/null +++ b/lib/v2/yicai/brief.js @@ -0,0 +1,28 @@ +const got = require('@/utils/got'); +const timezone = require('@/utils/timezone'); +const { parseDate } = require('@/utils/parse-date'); + +const { rootUrl } = require('./utils'); + +module.exports = async (ctx) => { + const currentUrl = `${rootUrl}/brief`; + const apiUrl = `${rootUrl}/api/ajax/getbrieflist?type=0&page=1&pagesize=${ctx.query.limit ?? 50}`; + + const response = await got({ + method: 'get', + url: apiUrl, + }); + + const items = response.data.map((item) => ({ + title: item.indexTitle, + link: `${rootUrl}${item.url}`, + description: item.newcontent, + pubDate: timezone(parseDate(`${item.datekey} ${item.hm}`, 'YYYY.MM.DD HH:mm'), +8), + })); + + ctx.state.data = { + title: '第一财经 - 正在', + link: currentUrl, + item: items, + }; +}; diff --git a/lib/v2/yicai/feed.js b/lib/v2/yicai/feed.js new file mode 100644 index 0000000000..04bafe8e97 --- /dev/null +++ b/lib/v2/yicai/feed.js @@ -0,0 +1,26 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); + +const { rootUrl, ProcessItems } = require('./utils'); + +module.exports = async (ctx) => { + const id = ctx.params.id ?? '669'; + + const currentUrl = `${rootUrl}/feed/${id}`; + const apiUrl = `${rootUrl}/api/ajax/getlistbytid?id=${id}&page=0&pagesize=${ctx.query.limit ?? 30}`; + + const response = await got({ + method: 'get', + url: currentUrl, + }); + + const $ = cheerio.load(response.data); + + const items = await ProcessItems(apiUrl, ctx.cache.tryGet); + + ctx.state.data = { + title: `第一财经主题 - ${$('title').text()}`, + link: currentUrl, + item: items, + }; +}; diff --git a/lib/v2/yicai/headline.js b/lib/v2/yicai/headline.js new file mode 100644 index 0000000000..a04e29937b --- /dev/null +++ b/lib/v2/yicai/headline.js @@ -0,0 +1,13 @@ +const { rootUrl, ProcessItems } = require('./utils'); + +module.exports = async (ctx) => { + const apiUrl = `${rootUrl}/api/ajax/getlistbycid?cid=48&type=1&page=1&pagesize=${ctx.query.limit ?? 30}`; + + const items = await ProcessItems(apiUrl, ctx.cache.tryGet); + + ctx.state.data = { + title: '第一财经 - 头条', + link: rootUrl, + item: items, + }; +}; diff --git a/lib/v2/yicai/latest.js b/lib/v2/yicai/latest.js new file mode 100644 index 0000000000..a01d4cb393 --- /dev/null +++ b/lib/v2/yicai/latest.js @@ -0,0 +1,13 @@ +const { rootUrl, ProcessItems } = require('./utils'); + +module.exports = async (ctx) => { + const apiUrl = `${rootUrl}/api/ajax/getlatest?page=1&pagesize=${ctx.query.limit ?? 30}`; + + const items = await ProcessItems(apiUrl, ctx.cache.tryGet); + + ctx.state.data = { + title: '第一财经 - 最新', + link: rootUrl, + item: items, + }; +}; diff --git a/lib/v2/yicai/maintainer.js b/lib/v2/yicai/maintainer.js new file mode 100644 index 0000000000..00afadad51 --- /dev/null +++ b/lib/v2/yicai/maintainer.js @@ -0,0 +1,10 @@ +module.exports = { + '/author/:id?': ['nczitzk'], + '/brief': ['sanmmm', 'nczitzk'], + '/feed/:id?': ['nczitzk'], + '/headline': ['nczitzk'], + '/latest': ['nczitzk'], + '/news/:id?': ['nczitzk'], + '/video/:id?': ['nczitzk'], + '/vip/:id?': ['nczitzk'], +}; diff --git a/lib/v2/yicai/news.js b/lib/v2/yicai/news.js new file mode 100644 index 0000000000..1d51554b39 --- /dev/null +++ b/lib/v2/yicai/news.js @@ -0,0 +1,39 @@ +const got = require('@/utils/got'); + +const { rootUrl, ProcessItems } = require('./utils'); + +module.exports = async (ctx) => { + const id = ctx.params.id ?? ''; + + let channel; + if (id) { + const navUrl = `${rootUrl}/api/ajax/getnavs`; + + const response = await got({ + method: 'get', + url: navUrl, + }); + + for (const c of response.data.header.news) { + if (c.EnglishName === id || c.ChannelID === id) { + channel = { + id: c.ChannelID, + name: c.ChannelName, + slug: c.EnglishName, + }; + break; + } + } + } + + const currentUrl = `${rootUrl}/news${id ? `/${channel.slug}` : ''}`; + const apiUrl = `${rootUrl}/api/ajax/${id ? `getlistbycid?cid=${channel.id}` : 'getjuhelist?action=news'}&page=1&pagesize=${ctx.query.limit ?? 30}`; + + const items = await ProcessItems(apiUrl, ctx.cache.tryGet); + + ctx.state.data = { + title: `第一财经 - ${channel?.name ?? '新闻'}`, + link: currentUrl, + item: items, + }; +}; diff --git a/lib/v2/yicai/radar.js b/lib/v2/yicai/radar.js new file mode 100644 index 0000000000..a9341cdc0f --- /dev/null +++ b/lib/v2/yicai/radar.js @@ -0,0 +1,55 @@ +module.exports = { + 'yicai.com': { + _name: '第一财经', + '.': [ + { + title: '最新', + docs: 'https://docs.rsshub.app/traditional-media.html#di-yi-cai-jing-zui-xin', + source: ['/'], + target: '/yicai/latest', + }, + { + title: '头条', + docs: 'https://docs.rsshub.app/traditional-media.html#di-yi-cai-jing-tou-tiao', + source: ['/'], + target: '/yicai/headline', + }, + { + title: 'VIP 频道', + docs: 'https://docs.rsshub.app/traditional-media.html#di-yi-cai-jing-vip-pin-dao', + source: ['/vip/product/:id', '/'], + target: '/yicai/vip/:id', + }, + { + title: '新闻', + docs: 'https://docs.rsshub.app/traditional-media.html#di-yi-cai-jing-xin-wen', + source: ['/news/:id', '/news'], + target: '/yicai/news/:id', + }, + { + title: '关注', + docs: 'https://docs.rsshub.app/traditional-media.html#di-yi-cai-jing-guan-zhu', + source: ['/feed/:id', '/feed'], + target: '/yicai/feed/:id', + }, + { + title: '视听', + docs: 'https://docs.rsshub.app/traditional-media.html#di-yi-cai-jing-shi-ting', + source: ['/video/:id', '/video'], + target: '/yicai/video/:id', + }, + { + title: '正在', + docs: 'https://docs.rsshub.app/traditional-media.html#di-yi-cai-jing-zheng-zai', + source: ['/brief'], + target: '/yicai/brief', + }, + { + title: '一财号', + docs: 'https://docs.rsshub.app/traditional-media.html#di-yi-cai-jing-yi-cai-hao', + source: ['/author/:id', '/author'], + target: '/yicai/author/:id', + }, + ], + }, +}; diff --git a/lib/v2/yicai/router.js b/lib/v2/yicai/router.js new file mode 100644 index 0000000000..eb10737d5a --- /dev/null +++ b/lib/v2/yicai/router.js @@ -0,0 +1,10 @@ +module.exports = function (router) { + router.get('/author/:id?', require('./author')); + router.get('/brief', require('./brief')); + router.get('/feed/:id?', require('./feed')); + router.get('/headline', require('./headline')); + router.get('/latest', require('./latest')); + router.get('/news/:id?', require('./news')); + router.get('/video/:id?', require('./video')); + router.get('/vip/:id?', require('./vip')); +}; diff --git a/lib/v2/yicai/templates/description.art b/lib/v2/yicai/templates/description.art new file mode 100644 index 0000000000..790b2de1f6 --- /dev/null +++ b/lib/v2/yicai/templates/description.art @@ -0,0 +1,11 @@ +{{ if thumb }} + +{{ /if }} +{{ if video }} + +{{ /if }} +{{ if description }} +

{{ description }}

+{{ /if }} \ No newline at end of file diff --git a/lib/v2/yicai/utils.js b/lib/v2/yicai/utils.js new file mode 100644 index 0000000000..970e15bbab --- /dev/null +++ b/lib/v2/yicai/utils.js @@ -0,0 +1,51 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const timezone = require('@/utils/timezone'); +const { parseDate } = require('@/utils/parse-date'); +const { art } = require('@/utils/render'); +const path = require('path'); + +const rootUrl = 'https://www.yicai.com'; + +module.exports = { + rootUrl, + ProcessItems: async (apiUrl, tryGet) => { + const response = await got({ + method: 'get', + url: apiUrl, + }); + + const items = response.data.map((item) => ({ + title: item.NewsTitle, + link: /^http/.test(item.url) ? item.url : `${rootUrl}${item.AppID === 0 ? `/vip` : ''}${item.url}`, + author: item.NewsAuthor || item.NewsSource || item.CreaterName, + pubDate: timezone(parseDate(item.CreateDate), +8), + category: [item.ChannelName], + description: art(path.join(__dirname, 'templates/description.art'), { + thumb: item.originPic, + video: item.VideoUrl, + description: item.NewsNotes, + }), + })); + + return await Promise.all( + items.map((item) => + tryGet(item.link, async () => { + const detailResponse = await got({ + method: 'get', + url: item.link, + }); + + const content = cheerio.load(detailResponse.data); + + content('h1').remove(); + content('.u-btn6, .m-smallshare, .topic-hot').remove(); + + item.description += content('.multiText, #multi-text, .txt').html() ?? ''; + + return item; + }) + ) + ); + }, +}; diff --git a/lib/v2/yicai/video.js b/lib/v2/yicai/video.js new file mode 100644 index 0000000000..af738f25c6 --- /dev/null +++ b/lib/v2/yicai/video.js @@ -0,0 +1,39 @@ +const got = require('@/utils/got'); + +const { rootUrl, ProcessItems } = require('./utils'); + +module.exports = async (ctx) => { + const id = ctx.params.id ?? ''; + + let channel; + if (id) { + const navUrl = `${rootUrl}/api/ajax/getnavs`; + + const response = await got({ + method: 'get', + url: navUrl, + }); + + for (const c of response.data.header.video) { + if (c.EnglishName === id || c.ChannelID === id) { + channel = { + id: c.ChannelID, + name: c.ChannelName, + slug: c.EnglishName, + }; + break; + } + } + } + + const currentUrl = `${rootUrl}/video${id ? `/${channel.slug}` : ''}`; + const apiUrl = `${rootUrl}/api/ajax/${id ? `getlistbycid?cid=${channel.id}` : 'getjuhelist?action=video'}&page=1&pagesize=${ctx.query.limit ?? 30}`; + + const items = await ProcessItems(apiUrl, ctx.cache.tryGet); + + ctx.state.data = { + title: `第一财经 - ${channel?.name ?? '视听'}`, + link: currentUrl, + item: items, + }; +}; diff --git a/lib/v2/yicai/vip.js b/lib/v2/yicai/vip.js new file mode 100644 index 0000000000..8a49754ada --- /dev/null +++ b/lib/v2/yicai/vip.js @@ -0,0 +1,26 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); + +const { rootUrl, ProcessItems } = require('./utils'); + +module.exports = async (ctx) => { + const id = ctx.params.id ?? '428'; + + const currentUrl = `${rootUrl}/vip/product/${id}`; + const apiUrl = `${rootUrl}/api/ajax/getlistbypid?id=${id}&type=3&page=1&pagesize=${ctx.query.limit ?? 30}`; + + const response = await got({ + method: 'get', + url: currentUrl, + }); + + const $ = cheerio.load(response.data); + + const items = await ProcessItems(apiUrl, ctx.cache.tryGet); + + ctx.state.data = { + title: `第一财经VIP频道 - ${$('title').text()}`, + link: currentUrl, + item: items, + }; +};