feat(route): add 酷安热榜/头条 (#6967)
This commit is contained in:
parent
e397e11fbd
commit
e492277271
|
|
@ -475,37 +475,61 @@ type 为 all 时,category 参数不支持 cost 和 free
|
|||
|
||||
## 酷安
|
||||
|
||||
### 图文 - 编辑精选
|
||||
### 图文
|
||||
|
||||
<Route author="xizeyoupan" example="/coolapk/tuwen" path="/coolapk/tuwen">
|
||||
<Route author="xizeyoupan" example="/coolapk/tuwen" path="/coolapk/tuwen/:type?" :paramsDesc="['默认为hot']">
|
||||
|
||||
::: tip
|
||||
每晚更新,更新较慢。
|
||||
:::
|
||||
| 参数名称 | 编辑精选 | 最新 |
|
||||
| -------- | -------- | ------ |
|
||||
| type | hot | latest |
|
||||
|
||||
</Route>
|
||||
|
||||
### 新鲜图文
|
||||
### 头条
|
||||
|
||||
<Route author="xizeyoupan" example="/coolapk/tuwen-xinxian" path="/coolapk/tuwen-xinxian"/>
|
||||
<Route author="xizeyoupan" example="/coolapk/toutiao" path="/coolapk/toutiao/:type?" :paramsDesc="['默认为history']">
|
||||
|
||||
### 看看号 - 图文 & 动态
|
||||
| 参数名称 | 历史头条 | 最新 |
|
||||
| -------- | -------- | ------ |
|
||||
| type | history | latest |
|
||||
|
||||
</Route>
|
||||
|
||||
### 看看号
|
||||
|
||||
<Route author="xizeyoupan" example="/coolapk/dyh/1524" path="/coolapk/dyh/:dyhId" :paramsDesc="['看看号ID']">
|
||||
|
||||
::: tip
|
||||
仅限于采集**站内订阅**的看看号的**图文及动态**内容。看看号 ID 可在看看号界面右上分享 - 复制链接得到。
|
||||
仅限于采集**站内订阅**的看看号的内容。看看号 ID 可在看看号界面右上分享 - 复制链接得到。
|
||||
:::
|
||||
|
||||
</Route>
|
||||
|
||||
### 话题 - 图文 & 动态
|
||||
### 话题
|
||||
|
||||
<Route author="xizeyoupan" example="/coolapk/huati/酷安夜话" path="/coolapk/huati/:tag" :paramsDesc="['话题名称']"/>
|
||||
|
||||
### 用户 - 图文 & 动态
|
||||
### 用户
|
||||
|
||||
<Route author="xizeyoupan" example="/coolapk/user/3177668/dynamic" path="/coolapk/user/:uid/dynamic" :paramsDesc="['uid,在个人界面右上分享-复制链接获取']"/>
|
||||
<Route author="xizeyoupan" example="/coolapk/user/3177668/dynamic" path="/coolapk/user/:uid/dynamic" :paramsDesc="['在个人界面右上分享-复制链接获取']"/>
|
||||
|
||||
### 热榜
|
||||
|
||||
<Route author="xizeyoupan" example="/coolapk/hot" path="/coolapk/hot/:type?/:period?" :paramsDesc="['默认为`jrrm`','默认为`daily`']">
|
||||
|
||||
| 参数名称 | 今日热门 | 点赞榜 | 评论榜 | 收藏榜 | 酷图榜 |
|
||||
| -------- | -------- | ------ | ------ | ------ | ------ |
|
||||
| type | jrrm | dzb | plb | scb | ktb |
|
||||
|
||||
| 参数名称 | 日榜 | 周榜 |
|
||||
| -------- | ----- | ------ |
|
||||
| period | daily | weekly |
|
||||
|
||||
::: tip
|
||||
今日热门没有周榜,酷图榜日榜的参数会变成周榜,周榜的参数会变成月榜。
|
||||
:::
|
||||
|
||||
</Route>
|
||||
|
||||
## 快递 100
|
||||
|
||||
|
|
|
|||
|
|
@ -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'));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
})
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
};
|
||||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
};
|
||||
};
|
||||
|
|
@ -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}`,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
})
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -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 = `<p>` + result.data.data.message.split('\n').join('<br>') + `</p>`;
|
||||
const picArr = item.picArr.filter((i) => i).map((i) => `<img src="${i}">`); // 若无图片,item.picArr=[""]
|
||||
return message + picArr.join('');
|
||||
});
|
||||
} else {
|
||||
const picArr = item.picArr.filter((i) => i).map((i) => `<img src="${i}">`);
|
||||
description = `<p>` + item.message + `</p>` + picArr.join('');
|
||||
if (item.entityType === 'sponsorCard') {
|
||||
return;
|
||||
}
|
||||
const $ = cheerio.load('<div class="title-filter">' + description + '</div>');
|
||||
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 = `<p>` + result.data.data.message.split('\n').join('<br>') + `</p>`;
|
||||
const picArr = item.picArr.filter((i) => i).map((i) => `<img src="${i}">`); // 若无图片,item.picArr=[""]
|
||||
return message + picArr.join('');
|
||||
});
|
||||
} else {
|
||||
const picArr = item.picArr.filter((i) => i).map((i) => `<img src="${i}">`);
|
||||
description = `<p>` + item.message + `</p>` + picArr.join('');
|
||||
}
|
||||
const $ = cheerio.load('<div class="title-filter">' + description + '</div>');
|
||||
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 += `<p>` + item.vote.message_title + ` 已选${keys.length}项</p>`;
|
||||
for (const i of item.vote.options) {
|
||||
if (keys.includes(String(i.id))) {
|
||||
description += `<p>${i.title}√</p>`;
|
||||
}
|
||||
}
|
||||
} 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 `<img src="${result.data.data.pic}"><hr>` + tags.join('');
|
||||
});
|
||||
const tags = parseTuwenFromRaw(raw);
|
||||
|
||||
return `<img src="${result.data.data.pic}"><hr>` + 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,
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue