diff --git a/docs/finance.md b/docs/finance.md index f591ecc4d8..a748f43123 100644 --- a/docs/finance.md +++ b/docs/finance.md @@ -289,9 +289,9 @@ pageClass: routes -### 基金净值更新 +### 蛋卷基金净值更新 - + ### 组合最新调仓信息 @@ -311,6 +311,10 @@ pageClass: routes +### 热帖 + + + ## 有知有行 ### 有知文章 diff --git a/docs/social-media.md b/docs/social-media.md index 8bdd4078f9..7c2d8579e4 100644 --- a/docs/social-media.md +++ b/docs/social-media.md @@ -1257,10 +1257,6 @@ rule -### 热帖 - - - ## 悟空问答 ### 用户动态 diff --git a/lib/router.js b/lib/router.js index ac80e289a3..0b5afe58a9 100644 --- a/lib/router.js +++ b/lib/router.js @@ -377,15 +377,15 @@ router.get('/egsea/flash', lazyloadRouteHandler('./routes/egsea/flash')); // 选股宝 router.get('/xuangubao/subject/:subject_id', lazyloadRouteHandler('./routes/xuangubao/subject')); -// 雪球 -router.get('/xueqiu/user/:id/:type?', lazyloadRouteHandler('./routes/xueqiu/user')); -router.get('/xueqiu/favorite/:id', lazyloadRouteHandler('./routes/xueqiu/favorite')); -router.get('/xueqiu/user_stock/:id', lazyloadRouteHandler('./routes/xueqiu/user_stock')); -router.get('/xueqiu/fund/:id', lazyloadRouteHandler('./routes/xueqiu/fund')); -router.get('/xueqiu/stock_info/:id/:type?', lazyloadRouteHandler('./routes/xueqiu/stock_info')); -router.get('/xueqiu/snb/:id', lazyloadRouteHandler('./routes/xueqiu/snb')); -router.get('/xueqiu/hots', lazyloadRouteHandler('./routes/xueqiu/hots')); -router.get('/xueqiu/stock_comments/:id/:titleLength?', lazyloadRouteHandler('./routes/xueqiu/stock_comments')); +// 雪球 migrated to v2 +// router.get('/xueqiu/user/:id/:type?', lazyloadRouteHandler('./routes/xueqiu/user')); +// router.get('/xueqiu/favorite/:id', lazyloadRouteHandler('./routes/xueqiu/favorite')); +// router.get('/xueqiu/user_stock/:id', lazyloadRouteHandler('./routes/xueqiu/user_stock')); +// router.get('/xueqiu/fund/:id', lazyloadRouteHandler('./routes/xueqiu/fund')); +// router.get('/xueqiu/stock_info/:id/:type?', lazyloadRouteHandler('./routes/xueqiu/stock_info')); +// router.get('/xueqiu/snb/:id', lazyloadRouteHandler('./routes/xueqiu/snb')); +// router.get('/xueqiu/hots', lazyloadRouteHandler('./routes/xueqiu/hots')); +// router.get('/xueqiu/stock_comments/:id/:titleLength?', lazyloadRouteHandler('./routes/xueqiu/stock_comments')); // Greasy Fork router.get('/greasyfork/:language/:domain?', lazyloadRouteHandler('./routes/greasyfork/scripts')); diff --git a/lib/routes/xueqiu/fund.js b/lib/routes/xueqiu/fund.js deleted file mode 100644 index a7c4f1428b..0000000000 --- a/lib/routes/xueqiu/fund.js +++ /dev/null @@ -1,71 +0,0 @@ -const got = require('@/utils/got'); -const cheerio = require('cheerio'); - -module.exports = async (ctx) => { - const guid = `xueqiu/fund ${ctx.params.id}`; - const cache = await ctx.cache.get(guid); - - if (cache) { - return Promise.resolve(JSON.parse(cache)); - } else { - const url = `https://xueqiu.com/S/F${ctx.params.id}`; - - let fundName = await got({ - method: 'get', - url, - headers: { - Referer: 'https://xueqiu.com/', - }, - }); - - const $ = cheerio.load(fundName.data); - fundName = $('.stock-name').text(); - const fundNameShort = fundName.slice(0, -10); - - const response = await got({ - method: 'get', - url: `https://fund.xueqiu.com/dj/open/fund/growth/${ctx.params.id}?day=7`, - headers: { - Referer: url, - }, - }); - - const data = response.data.data.fund_nav_growth.pop(); - const yesterday = response.data.data.fund_nav_growth.pop(); - - let description = `${fundNameShort}
最新净值 ${data.nav}
今日`; - let title = `${fundNameShort} ${data.date.substring(5)} `; - - const value = (parseFloat(data.nav) - parseFloat(yesterday.nav)).toFixed(4); - - if (value > 0) { - description += '涨幅'; - title += `📈 ${data.percentage}%`; - } else if (value < 0) { - description += '跌幅'; - title += `📉 ${data.percentage}%`; - } else if (value === '0.0000') { - description += '无波动'; - title += '持平'; - } - - description += ` ${data.percentage}%(¥${value})`; - - const single = { - title, - description, - pubDate: new Date().toUTCString(), - guid: `${guid} ${data.date}`, - link: url, - }; - - ctx.state.data = { - title: fundName, - link: url, - description: `${fundName} 净值更新`, - item: [single], - }; - - ctx.cache.set(guid, JSON.stringify(ctx.state.data)); - } -}; diff --git a/lib/routes/xueqiu/favorite.js b/lib/v2/xueqiu/favorite.js similarity index 91% rename from lib/routes/xueqiu/favorite.js rename to lib/v2/xueqiu/favorite.js index 971952e771..cea30a7883 100644 --- a/lib/routes/xueqiu/favorite.js +++ b/lib/v2/xueqiu/favorite.js @@ -1,5 +1,6 @@ const got = require('@/utils/got'); const queryString = require('query-string'); +const { parseDate } = require('@/utils/parse-date'); module.exports = async (ctx) => { const id = ctx.params.id; @@ -30,7 +31,7 @@ module.exports = async (ctx) => { item: data.map((item) => ({ title: item.title, description: item.description, - pubDate: new Date(item.created_at).toUTCString(), + pubDate: parseDate(item.created_at), link: `https://xueqiu.com${item.target}`, })), }; diff --git a/lib/v2/xueqiu/fund.js b/lib/v2/xueqiu/fund.js new file mode 100644 index 0000000000..9ed12ac172 --- /dev/null +++ b/lib/v2/xueqiu/fund.js @@ -0,0 +1,50 @@ +const got = require('@/utils/got'); +const { parseDate } = require('@/utils/parse-date'); +const timezone = require('@/utils/timezone'); + +module.exports = async (ctx) => { + const guid = ctx.params.id; + const appUrl = `https://danjuanapp.com/funding/${guid}`; + const url = `https://danjuanapp.com/djapi/fund/${guid}`; + const response = await got({ + method: 'get', + url, + headers: { + Referer: appUrl, + }, + }); + const fd_full_name = response.data.data.fd_full_name; + const fd_name = response.data.data.fd_name; + const fd_code = response.data.data.fd_code; + const unit_nav = response.data.data.fund_derived.unit_nav; + const nav_grtd = response.data.data.fund_derived.nav_grtd; + const end_date = response.data.data.fund_derived.end_date; + + let description = `基金代码 ${fd_code}
今日净值(${end_date}) ¥${unit_nav} `; + let title = fd_full_name; + + if (nav_grtd > 0) { + description += `
日涨跌 ${nav_grtd}%`; + title += `📈 ${nav_grtd}%`; + } else if (nav_grtd < 0) { + description += `
日跌跌 ${nav_grtd}%`; + title += `📉 ${nav_grtd}%`; + } else if (nav_grtd === '0.0000') { + description += '无波动'; + title += '持平'; + } + + const single = { + title, + description, + pubDate: timezone(parseDate(end_date), +8), + link: appUrl, + }; + + ctx.state.data = { + title: fd_name, + link: appUrl, + description, + item: [single], + }; +}; diff --git a/lib/routes/xueqiu/hots.js b/lib/v2/xueqiu/hots.js similarity index 92% rename from lib/routes/xueqiu/hots.js rename to lib/v2/xueqiu/hots.js index 421afc2486..7f0f62c834 100644 --- a/lib/routes/xueqiu/hots.js +++ b/lib/v2/xueqiu/hots.js @@ -1,5 +1,6 @@ const got = require('@/utils/got'); const queryString = require('query-string'); +const { parseDate } = require('@/utils/parse-date'); module.exports = async (ctx) => { const res1 = await got({ @@ -35,7 +36,7 @@ module.exports = async (ctx) => { return { title: item.title ? item.title : description.replace(/<[^>]+>/g, ''), description: item.text, - pubDate: new Date(item.created_at).toUTCString(), + pubDate: parseDate(item.created_at), link: `https://xueqiu.com${item.target}`, author: item.user.screen_name, }; diff --git a/lib/v2/xueqiu/radar.js b/lib/v2/xueqiu/radar.js new file mode 100644 index 0000000000..a689a826db --- /dev/null +++ b/lib/v2/xueqiu/radar.js @@ -0,0 +1,60 @@ +module.exports = { + 'danjuanapp.com': { + _name: '雪球', + '.': [ + { + title: '蛋卷基金净值更新', + docs: 'https://docs.rsshub.app/finance.html#xue-qiu', + source: ['/funding/:id'], + target: '/xueqiu/funding/:id', + }, + ], + }, + 'xueqiu.com': { + _name: '雪球', + '.': [ + { + title: '用户动态', + docs: 'https://docs.rsshub.app/finance.html#xue-qiu', + source: ['/u/:id'], + target: '/xueqiu/user/:id', + }, + { + title: '用户收藏动态', + docs: 'https://docs.rsshub.app/finance.html#xue-qiu', + source: ['/u/:id'], + target: '/xueqiu/favorite/:id', + }, + { + title: '用户自选动态', + docs: 'https://docs.rsshub.app/finance.html#xue-qiu', + source: ['/u/:id'], + target: '/xueqiu/user_stock/:id', + }, + { + title: '组合最新调仓信息', + docs: 'https://docs.rsshub.app/finance.html#xue-qiu', + source: ['/p/:id'], + target: '/xueqiu/snb/:id', + }, + { + title: '股票信息', + docs: 'https://docs.rsshub.app/finance.html#xue-qiu', + source: ['/S/:id'], + target: '/xueqiu/stock_info/:id', + }, + { + title: '股票评论', + docs: 'https://docs.rsshub.app/finance.html#xue-qiu', + source: ['/S/:id'], + target: '/xueqiu/stock_comments/:id', + }, + { + title: '热帖', + docs: 'https://docs.rsshub.app/finance.html#xue-qiu', + source: ['/'], + target: '/xueqiu/hots', + }, + ], + }, +}; diff --git a/lib/v2/xueqiu/router.js b/lib/v2/xueqiu/router.js new file mode 100644 index 0000000000..314c4d3da8 --- /dev/null +++ b/lib/v2/xueqiu/router.js @@ -0,0 +1,10 @@ +module.exports = (router) => { + router.get('/favorite/:id', require('./favorite')); + router.get('/fund/:id', require('./fund')); + router.get('/hots', require('./hots')); + router.get('/snb/:id', require('./snb')); + router.get('/stock_comments/:id/:titleLength?', require('./stock_comments')); + router.get('/stock_info/:id/:type?', require('./stock_info')); + router.get('/user/:id/:type?', require('./user')); + router.get('/user_stock/:id', require('./user_stock')); +}; diff --git a/lib/routes/xueqiu/snb.js b/lib/v2/xueqiu/snb.js similarity index 93% rename from lib/routes/xueqiu/snb.js rename to lib/v2/xueqiu/snb.js index c675c10c65..d75f98d07c 100644 --- a/lib/routes/xueqiu/snb.js +++ b/lib/v2/xueqiu/snb.js @@ -1,4 +1,5 @@ const got = require('@/utils/got'); +const { parseDate } = require('@/utils/parse-date'); module.exports = async (ctx) => { const id = ctx.params.id; @@ -28,7 +29,7 @@ module.exports = async (ctx) => { const single = { title, description, - pubDate: new Date(time).toUTCString(), + pubDate: parseDate(time), link: url, guid: `xueqiu::snb::${id}::${time}`, }; diff --git a/lib/routes/xueqiu/stock_comments.js b/lib/v2/xueqiu/stock_comments.js similarity index 71% rename from lib/routes/xueqiu/stock_comments.js rename to lib/v2/xueqiu/stock_comments.js index f30cb99a95..381eb6b71f 100644 --- a/lib/routes/xueqiu/stock_comments.js +++ b/lib/v2/xueqiu/stock_comments.js @@ -1,28 +1,12 @@ const got = require('@/utils/got'); const cheerio = require('cheerio'); -const template = require('art-template'); +const { art } = require('@/utils/render'); +const path = require('path'); const { parseDate } = require('@/utils/parse-date'); -const description_template = ` - -
{{item.user.screen_name}}:
-
-
-{{item.text}} -
-{{if item.retweeted_status}} -
-{{item.retweeted_status.text}} -{{else}} -
-{{/if}} -
- ----来源于:{{item.source}} -
`; - module.exports = async (ctx) => { const id = ctx.params.id; - const titleLength = ctx.params.titleLength || 30; + const titleLength = ctx.params.titleLength ? parseInt(ctx.params.titleLength) : 30; const res = await got({ method: 'get', @@ -49,7 +33,7 @@ module.exports = async (ctx) => { if (item.quote_cards) { link = item.quote_cards[0].target_url; } - const description = template.render(description_template, { item }); + const description = art(path.join(__dirname, 'templates/comments_description.art'), { item }); return { title: item.title !== '' ? item.title : item.text.replace(/<[^>]+>/g, '').slice(0, titleLength), description, diff --git a/lib/routes/xueqiu/stock_info.js b/lib/v2/xueqiu/stock_info.js similarity index 95% rename from lib/routes/xueqiu/stock_info.js rename to lib/v2/xueqiu/stock_info.js index b358da56e8..a7a6cbf390 100644 --- a/lib/routes/xueqiu/stock_info.js +++ b/lib/v2/xueqiu/stock_info.js @@ -1,6 +1,7 @@ const got = require('@/utils/got'); const cheerio = require('cheerio'); const queryString = require('query-string'); +const { parseDate } = require('@/utils/parse-date'); module.exports = async (ctx) => { const id = ctx.params.id; @@ -63,7 +64,7 @@ module.exports = async (ctx) => { return { title: item.title !== '' ? item.title : item.description.replace(/<[^>]+>/g, ''), description: item.description, - pubDate: new Date(item.created_at).toUTCString(), + pubDate: parseDate(item.created_at), link, }; }), diff --git a/lib/v2/xueqiu/templates/comments_description.art b/lib/v2/xueqiu/templates/comments_description.art new file mode 100644 index 0000000000..69352716c3 --- /dev/null +++ b/lib/v2/xueqiu/templates/comments_description.art @@ -0,0 +1,10 @@ +
{{ item.user.screen_name }}:
+
+{{@ item.text }} +
+{{ if item.retweeted_status }} +
{{@ item.retweeted_status.text }} +{{ else }} +
+{{ /if }} +
----来源于:{{ item.source }}
diff --git a/lib/routes/xueqiu/user.js b/lib/v2/xueqiu/user.js similarity index 94% rename from lib/routes/xueqiu/user.js rename to lib/v2/xueqiu/user.js index 2b791ce5a6..cbff540c8b 100644 --- a/lib/routes/xueqiu/user.js +++ b/lib/v2/xueqiu/user.js @@ -1,5 +1,6 @@ const got = require('@/utils/got'); const queryString = require('query-string'); +const { parseDate } = require('@/utils/parse-date'); module.exports = async (ctx) => { const id = ctx.params.id; @@ -44,7 +45,7 @@ module.exports = async (ctx) => { return { title: item.title ? item.title : description.replace(/<[^>]+>/g, ''), description, - pubDate: new Date(item.created_at).toUTCString(), + pubDate: parseDate(item.created_at), link: `https://xueqiu.com${item.target}`, }; }), diff --git a/lib/routes/xueqiu/user_stock.js b/lib/v2/xueqiu/user_stock.js similarity index 84% rename from lib/routes/xueqiu/user_stock.js rename to lib/v2/xueqiu/user_stock.js index 4b5809d3e1..4024d84848 100644 --- a/lib/routes/xueqiu/user_stock.js +++ b/lib/v2/xueqiu/user_stock.js @@ -1,5 +1,6 @@ const got = require('@/utils/got'); const queryString = require('query-string'); +const { parseDate } = require('@/utils/parse-date'); module.exports = async (ctx) => { const id = ctx.params.id; @@ -39,8 +40,8 @@ module.exports = async (ctx) => { description: `@${screen_name} 的雪球自选动态`, item: data.map((item) => ({ title: `@${screen_name} 关注了股票 ${item.name}`, - description: `@${screen_name} 在${new Date(item.created).toLocaleString()} 关注了 ${item.name}(${item.exchange}:${item.symbol})。`, - pubDate: new Date(item.created).toUTCString(), + description: `@${screen_name} 在${parseDate(item.created).toLocaleString()} 关注了 ${item.name}(${item.exchange}:${item.symbol})。`, + pubDate: parseDate(item.created), link: `https://xueqiu.com/s/${item.symbol}`, })), };