From e4922772717df08d8971274faad7dac81b01d5f7 Mon Sep 17 00:00:00 2001 From: Xizeyoupan <44920131+xizeyoupan@users.noreply.github.com> Date: Sun, 7 Mar 2021 18:07:46 +0800 Subject: [PATCH] =?UTF-8?q?feat(route):=20add=20=E9=85=B7=E5=AE=89?= =?UTF-8?q?=E7=83=AD=E6=A6=9C/=E5=A4=B4=E6=9D=A1=20(#6967)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/other.md | 48 ++++++++--- lib/router.js | 4 +- lib/routes/coolapk/dyh.js | 9 +-- lib/routes/coolapk/hot.js | 99 +++++++++++++++++++++++ lib/routes/coolapk/huati.js | 13 +-- lib/routes/coolapk/toutiao.js | 31 ++++++++ lib/routes/coolapk/tuwen.js | 5 +- lib/routes/coolapk/userDynamic.js | 11 +-- lib/routes/coolapk/utils.js | 127 ++++++++++++++++++------------ 9 files changed, 252 insertions(+), 95 deletions(-) create mode 100644 lib/routes/coolapk/hot.js create mode 100644 lib/routes/coolapk/toutiao.js diff --git a/docs/other.md b/docs/other.md index f4f8c3839..d866ef1fd 100644 --- a/docs/other.md +++ b/docs/other.md @@ -475,37 +475,61 @@ type 为 all 时,category 参数不支持 cost 和 free ## 酷安 -### 图文 - 编辑精选 +### 图文 - + -::: tip -每晚更新,更新较慢。 -::: +| 参数名称 | 编辑精选 | 最新 | +| -------- | -------- | ------ | +| type | hot | latest | -### 新鲜图文 +### 头条 - + -### 看看号 - 图文 & 动态 +| 参数名称 | 历史头条 | 最新 | +| -------- | -------- | ------ | +| type | history | latest | + + + +### 看看号 ::: tip -仅限于采集**站内订阅**的看看号的**图文及动态**内容。看看号 ID 可在看看号界面右上分享 - 复制链接得到。 +仅限于采集**站内订阅**的看看号的内容。看看号 ID 可在看看号界面右上分享 - 复制链接得到。 ::: -### 话题 - 图文 & 动态 +### 话题 -### 用户 - 图文 & 动态 +### 用户 - + + +### 热榜 + + + +| 参数名称 | 今日热门 | 点赞榜 | 评论榜 | 收藏榜 | 酷图榜 | +| -------- | -------- | ------ | ------ | ------ | ------ | +| type | jrrm | dzb | plb | scb | ktb | + +| 参数名称 | 日榜 | 周榜 | +| -------- | ----- | ------ | +| period | daily | weekly | + +::: tip +今日热门没有周榜,酷图榜日榜的参数会变成周榜,周榜的参数会变成月榜。 +::: + + ## 快递 100 diff --git a/lib/router.js b/lib/router.js index 2751d1258..2eba18a30 100644 --- a/lib/router.js +++ b/lib/router.js @@ -2027,11 +2027,13 @@ router.get('/hinatazaka46/blog', require('./routes/hinatazaka46/blog')); router.get('/sakurazaka46/blog', require('./routes/sakurazaka46/blog')); // 酷安 -router.get('/coolapk/tuwen', require('./routes/coolapk/tuwen')); +router.get('/coolapk/tuwen/:type?', require('./routes/coolapk/tuwen')); router.get('/coolapk/tuwen-xinxian', require('./routes/coolapk/tuwen')); +router.get('/coolapk/toutiao/:type?', require('./routes/coolapk/toutiao')); router.get('/coolapk/huati/:tag', require('./routes/coolapk/huati')); router.get('/coolapk/user/:uid/dynamic', require('./routes/coolapk/userDynamic')); router.get('/coolapk/dyh/:dyhId', require('./routes/coolapk/dyh')); +router.get('/coolapk/hot/:type?/:period?', require('./routes/coolapk/hot')); // 模型网 router.get('/moxingnet', require('./routes/moxingnet')); diff --git a/lib/routes/coolapk/dyh.js b/lib/routes/coolapk/dyh.js index e8419f484..b7abd90af 100644 --- a/lib/routes/coolapk/dyh.js +++ b/lib/routes/coolapk/dyh.js @@ -24,14 +24,7 @@ module.exports = async (ctx) => { targetTitle = item.targetRow.title; } - if (item.type === 12) { - // 图文内容 - return utils.parseTuwen(item, ctx); - } else if (String(item.type) in utils.dynamicTpye) { - return utils.parseDongtai(item, ctx); - } else { - return null; - } + return utils.parseDynamic(item, ctx); }) ); diff --git a/lib/routes/coolapk/hot.js b/lib/routes/coolapk/hot.js new file mode 100644 index 000000000..3a566d19c --- /dev/null +++ b/lib/routes/coolapk/hot.js @@ -0,0 +1,99 @@ +const got = require('@/utils/got'); +const utils = require('./utils'); +const getLinkAndTitle = (type, period) => { + const baseURL = 'https://api.coolapk.com/v6/page/dataList?url='; + let link; + const res = {}; + const types = { + jrrm: { + title: '今日热门', + url: baseURL + '%2Ffeed%2FstatList%3FcacheExpires%3D300%26statType%3Dday%26sortField%3Ddetailnum%26title%3D%E4%BB%8A%E6%97%A5%E7%83%AD%E9%97%A8&title=%E4%BB%8A%E6%97%A5%E7%83%AD%E9%97%A8&subTitle=&page=1', + }, + + dzb: { + title: '点赞榜', + sortField: 'likenum', + }, + + scb: { + title: '收藏榜', + sortField: 'favnum', + }, + plb: { + title: '评论榜', + sortField: 'replynum', + }, + ktb: { + title: '酷图榜', + sortField: 'likenum', + }, + }; + + const periods = { + daily: { + description: '日榜', + statType: 'day', + }, + weekly: { + description: '周榜', + statType: '7days', + }, + }; + + if (type === 'jrrm') { + res.link = types.jrrm.url; + res.title = types.jrrm.title; + return res; + } else if (type === 'ktb') { + const trans = { + daily: { + description: '周榜', + statDays: '7days', + }, + weekly: { + description: '月榜', + statDays: '30days', + }, + }; + link = `#/feed/coolPictureList?statDays=` + trans[period].statDays + `&listType=statFavNum&buildCard=1&title=` + trans[period].description + `&page=1`; + res.title = '酷图榜-' + trans[period].description; + } else { + link = `#/feed/statList?statType=` + periods[period].statType + `&sortField=` + types[type].sortField + `&title=` + periods[period].description + `&page=1`; + res.title = types[type].title + `-` + periods[period].description; + } + res.link = baseURL + encodeURIComponent(link); + return res; +}; + +module.exports = async (ctx) => { + const type = ctx.params.type || 'jrrm'; + const period = ctx.params.period || 'daily'; + const { link, title } = getLinkAndTitle(type, period); + const r = await got({ + method: 'get', + url: link, + headers: utils.getHeaders(), + }); + const data = r.data.data; + const t = []; + for (const i of data) { + if (i.entityType === 'card') { + for (const k of i.entities) { + t.push(k); + } + } else { + t.push(i); + } + } + + let out = await Promise.all(t.map(async (item) => utils.parseDynamic(item, ctx))); + + out = out.filter((i) => i); + + ctx.state.data = { + title: title, + link: 'https://www.coolapk.com/', + description: `热榜-` + title, + item: out, + }; +}; diff --git a/lib/routes/coolapk/huati.js b/lib/routes/coolapk/huati.js index 804b46cb9..e7f10d566 100644 --- a/lib/routes/coolapk/huati.js +++ b/lib/routes/coolapk/huati.js @@ -11,18 +11,7 @@ module.exports = async (ctx) => { }); const data = response.data.data; - let out = await Promise.all( - data.map(async (item) => { - if (item.type === 12) { - // 图文内容 - return utils.parseTuwen(item, ctx); - } else if (String(item.type) in utils.dynamicTpye) { - return utils.parseDongtai(item, ctx); - } else { - return null; - } - }) - ); + let out = await Promise.all(data.map(async (item) => utils.parseDynamic(item, ctx))); out = out.filter((i) => i); // 去除空值 if (out.length === 0) { diff --git a/lib/routes/coolapk/toutiao.js b/lib/routes/coolapk/toutiao.js new file mode 100644 index 000000000..86a86b1cb --- /dev/null +++ b/lib/routes/coolapk/toutiao.js @@ -0,0 +1,31 @@ +const got = require('@/utils/got'); +const utils = require('./utils'); + +module.exports = async (ctx) => { + const type = ctx.params.type || 'history'; + const urls = { + history: { + url: 'https://api.coolapk.com/v6/page/dataList?url=%23%2ffeed%2fheadlineV8List%3ftype%3d0%2c5%2c9%2c8%2c12%2c10%2c11%2c13%26title%3d%e5%8e%86%e5%8f%b2%e5%a4%b4%e6%9d%a1%26page%3d1', + title: '历史头条', + }, + latest: { + url: 'https://api.coolapk.com/v6/page/dataList?url=%23%2ffeed%2fdigestList%3ftype%3d0%2c5%2c12%2c10%2c11%2c13%2c8%2c9%26title%3d%e6%9c%80%e6%96%b0%e5%8a%a8%e6%80%81%26page%3d1', + title: '最新动态', + }, + }; + const response = await got({ + method: 'get', + url: urls[type].url, + headers: utils.getHeaders(), + }); + const data = response.data.data; + + const out = await Promise.all(data.map(async (item) => utils.parseDynamic(item, ctx))); + + ctx.state.data = { + title: urls[type].title, + link: 'https://www.coolapk.com/', + description: urls[type].title, + item: out, + }; +}; diff --git a/lib/routes/coolapk/tuwen.js b/lib/routes/coolapk/tuwen.js index 61e9dbd67..93db3175b 100644 --- a/lib/routes/coolapk/tuwen.js +++ b/lib/routes/coolapk/tuwen.js @@ -2,8 +2,9 @@ const got = require('@/utils/got'); const utils = require('./utils'); module.exports = async (ctx) => { + const type = ctx.params.type || 'hot'; let full_url, feedTitle; - if (ctx.originalUrl.startsWith(`/coolapk/tuwen-xinxian`)) { + if (ctx.originalUrl.startsWith(`/coolapk/tuwen-xinxian`) || type === 'latest') { // 实时 full_url = utils.base_url + @@ -21,7 +22,7 @@ module.exports = async (ctx) => { }); const data = response.data.data; - const out = await Promise.all(data.map(async (item) => utils.parseTuwen(item, ctx))); + const out = await Promise.all(data.map(async (item) => utils.parseDynamic(item, ctx))); ctx.state.data = { title: `${feedTitle}`, diff --git a/lib/routes/coolapk/userDynamic.js b/lib/routes/coolapk/userDynamic.js index 221642f8f..61dc0ca18 100644 --- a/lib/routes/coolapk/userDynamic.js +++ b/lib/routes/coolapk/userDynamic.js @@ -3,7 +3,7 @@ const utils = require('./utils'); module.exports = async (ctx) => { const uid = ctx.params.uid; - const full_url = utils.base_url + `/v6/user/feedList?uid=${uid}&page=1&showAnonymous=0`; + const full_url = utils.base_url + `/v6/user/feedList?uid=${uid}&page=1&showAnonymous=0&isIncludeTop=1&showDoing=1`; let username; const response = await got({ method: 'get', @@ -20,14 +20,7 @@ module.exports = async (ctx) => { username = item.username; } - if (item.type === 12) { - // 图文内容 - return utils.parseTuwen(item, ctx); - } else if (String(item.type) in utils.dynamicTpye) { - return utils.parseDongtai(item, ctx); - } else { - return null; - } + return utils.parseDynamic(item, ctx); }) ); diff --git a/lib/routes/coolapk/utils.js b/lib/routes/coolapk/utils.js index 9e38e0b00..710598c1c 100644 --- a/lib/routes/coolapk/utils.js +++ b/lib/routes/coolapk/utils.js @@ -2,7 +2,7 @@ const md5 = require('@/utils/md5'); const cheerio = require('cheerio'); const got = require('@/utils/got'); -const dynamicTpye = { 0: '基本动态', 9: '评论', 20: '交易动态' }; +const dynamicTpye = { 0: '基本动态', 8: '酷图', 9: '评论', 10: '提问', 11: '回答', 12: '图文', 15: '二手', 17: '观点', 20: '交易动态' }; const getRandomDEVICE_ID = () => { let id = [8, 4, 4, 4, 12]; @@ -29,9 +29,10 @@ const getHeaders = () => ({ 'X-App-Token': get_app_token(), 'X-Sdk-Int': '29', 'X-Sdk-Locale': 'zh-CN', - 'X-App-Version': '10.4', - 'X-App-Code': '2007081', - 'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 10; Redmi K30 5G MIUI/V12.0.3.0.QGICMXM) (#Build; Redmi; Redmi K30 5G; QKQ1.191222.002 test-keys; 10) +CoolMarket/10.4-2007081', + 'X-App-Version': '11.0', + 'X-Api-Version': '11', + 'X-App-Code': '2101202', + 'User-Agent': 'Dalvik/2.1.0 (Linux; U; Android 10; Redmi K30 5G MIUI/V12.0.3.0.QGICMXM) (#Build; Redmi; Redmi K30 5G; QKQ1.191222.002 test-keys; 10) +CoolMarket/11.0-2101202', }); const parseTuwenFromRaw = (raw) => @@ -48,64 +49,89 @@ const parseTuwenFromRaw = (raw) => } }); -const parseDongtai = async (item, ctx) => { - const author = item.username; +const parseDynamic = async (item, ctx) => { const pubdate = new Date(item.lastupdate * 1000).toUTCString(); - const itemUrl = item.shareUrl.split('?')[0]; - let description; - if (item.issummary) { - // 需要爬内容 - description = await ctx.cache.tryGet(itemUrl, async () => { - const result = await got({ - method: 'get', - url: itemUrl, - headers: getHeaders(), - }); - const message = `

` + result.data.data.message.split('\n').join('
') + `

`; - const picArr = item.picArr.filter((i) => i).map((i) => ``); // 若无图片,item.picArr=[""] - return message + picArr.join(''); - }); - } else { - const picArr = item.picArr.filter((i) => i).map((i) => ``); - description = `

` + item.message + `

` + picArr.join(''); + if (item.entityType === 'sponsorCard') { + return; } - const $ = cheerio.load('
' + description + '
'); - const title = $('.title-filter').text().slice(0, 30).trim() + '...'; - return { - title: title, - description: description, - pubDate: pubdate, - link: itemUrl, - author: author, - }; -}; + const itemUrl = item.shareUrl.split('?')[0]; + let description, title; + const type = parseInt(item.type); + switch (type) { + case 0: + case 8: + case 9: + case 10: + case 11: + case 15: + case 17: + case 20: { + // //////////////////////////////////////////// 基本内容 //////////////////////////////////////////// + if (item.issummary) { + // 需要爬内容 + description = await ctx.cache.tryGet(itemUrl, async () => { + const result = await got({ + method: 'get', + url: itemUrl, + headers: getHeaders(), + }); + const message = `

` + result.data.data.message.split('\n').join('
') + `

`; + const picArr = item.picArr.filter((i) => i).map((i) => ``); // 若无图片,item.picArr=[""] + return message + picArr.join(''); + }); + } else { + const picArr = item.picArr.filter((i) => i).map((i) => ``); + description = `

` + item.message + `

` + picArr.join(''); + } + const $ = cheerio.load('
' + description + '
'); + title = $('.title-filter').text().slice(0, 30).trim() + '...'; -const parseTuwen = async (item, ctx) => { - const title = item.title; - const pubdate = new Date(item.lastupdate * 1000).toUTCString(); - const author = item.username; + // //////////////////////////////////////////// 基本内容结束 //////////////////////////////////////////// - const description = await ctx.cache.tryGet(item.shareUrl, async () => { - const result = await got({ - method: 'get', - url: item.shareUrl, - headers: getHeaders(), - }); + if (type === 17) { + const keys = item.extra_key.split(','); + description += `

` + item.vote.message_title + ` 已选${keys.length}项

`; + for (const i of item.vote.options) { + if (keys.includes(String(i.id))) { + description += `

${i.title}√

`; + } + } + } else if (type === 10 || type === 11) { + title = `${item.message_title} 更多:` + title; + } - const raw = JSON.parse(result.data.data.message_raw_output); + break; + } + case 12: { + title = item.title; + description = await ctx.cache.tryGet(itemUrl, async () => { + const result = await got({ + method: 'get', + url: itemUrl, + headers: getHeaders(), + }); - const tags = parseTuwenFromRaw(raw); + const raw = JSON.parse(result.data.data.message_raw_output); - return `
` + tags.join(''); - }); + const tags = parseTuwenFromRaw(raw); + + return `
` + tags.join(''); + }); + break; + } + default: + // console.log(item.type); + // console.log(item); + break; + } return { title: title, description: description, pubDate: pubdate, link: item.shareUrl, - guid: item.shareUrl.split('?')[0], - author: author, + guid: itemUrl, + author: item.username, }; }; @@ -113,7 +139,6 @@ module.exports = { get_app_token, base_url, getHeaders, - parseTuwen, - parseDongtai, + parseDynamic, dynamicTpye, };