feat: 品玩 (#2764)

* fix docs

* feat: 字幕库

* feat: hpoi info

* fix hpoi 情报 文案

* feat: 品玩

* fix: hpoi info category

* fix: add referer

* fix format


Co-authored-by: DIYgod <diy.d.god@gmail.com>
This commit is contained in:
sanmmmm
2019-08-06 13:15:56 +08:00
committed by DIYgod
parent 755518551f
commit 00c6d90cb4
7 changed files with 263 additions and 0 deletions

View File

@@ -729,6 +729,36 @@ type 为 all 时category 参数不支持 cost 和 free
<Route author="qiwihui" example="/paidai/news" path="/paidao/news" /> <Route author="qiwihui" example="/paidai/news" path="/paidao/news" />
## 品玩
### 实时要闻
<Route author="sanmmm" example="/pingwest/status" path="/pingwest/status"/>
### 话题动态
<Route author="sanmmm" path="/pingwest/tag/:tag/:type" example="/pingwest/tag/ChinaJoy/1" :paramsDesc="['话题名或话题id, 可从话题页url中得到', '内容类型']">
内容类型
| 最新 | 最热 |
| ---- | ---- |
| 1 | 2 |
</Route>
### 用户
<Route author="sanmmm" path="/pingwest/user/:uid/:type?" example="/pingwest/user/7781550877/article" :paramsDesc="['用户id, 可从用户主页中得到', '内容类型, 默认为`article`']">
内容类型
| 文章 | 动态 |
| ------- | ----- |
| article | state |
</Route>
## 且听风吟福利 ## 且听风吟福利
### 分类 ### 分类

View File

@@ -1618,6 +1618,11 @@ router.get('/mofcom/article/:suffix', require('./routes/mofcom/article'));
// 字幕库 // 字幕库
router.get('/zimuku/:type?', require('./routes/zimuku/index')); router.get('/zimuku/:type?', require('./routes/zimuku/index'));
// 品玩
router.get('/pingwest/status', require('./routes/pingwest/status'));
router.get('/pingwest/tag/:tag/:type', require('./routes/pingwest/tag'));
router.get('/pingwest/user/:uid/:type?', require('./routes/pingwest/user'));
// Hanime // Hanime
router.get('/hanime/video', require('./routes/hanime/video')); router.get('/hanime/video', require('./routes/hanime/video'));

View File

@@ -38,6 +38,7 @@ module.exports = async (ctx) => {
return { return {
title: infoTitle, title: infoTitle,
link, link,
category: infoType,
description: [`类型:${typeName}`, infoTitle, `更新内容: ${infoType}`, `<img src=""${imgUrl}/>`].join('<br/>'), description: [`类型:${typeName}`, infoTitle, `更新内容: ${infoType}`, `<img src=""${imgUrl}/>`].join('<br/>'),
}; };
}) })

View File

@@ -0,0 +1,43 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
module.exports = async (ctx) => {
const baseUrl = 'https://www.pingwest.com';
const url = `${baseUrl}/api/state/list`;
const response = await got(url, {
query: {
page: 1,
},
headers: {
Referer: baseUrl,
},
});
const $ = cheerio.load(response.data.data.list);
const items = $('section.item')
.map((_, ele) => {
const timestamp = ele.attribs['data-t'];
const $item = cheerio.load(ele);
const rightNode = $item('.news-info');
const tag = rightNode.find('.item-tag-list').text();
const title = rightNode.find('.title').text();
const link = rightNode
.find('a')
.last()
.attr('href');
const description = rightNode.text();
return {
title: title || tag,
link: link.startsWith('http') ? link : `https:${link}`,
description,
pubDate: new Date(timestamp * 1000).toUTCString(),
};
})
.get();
ctx.state.data = {
title: '品玩 - 实时要闻',
description: '品玩 - 实时要闻',
link: `${baseUrl}/status`,
item: items,
};
};

View File

@@ -0,0 +1,50 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const utils = require('./utils');
module.exports = async (ctx) => {
const { tag, type } = ctx.params;
const baseUrl = 'https://www.pingwest.com';
const tagUrl = `${baseUrl}/tag/${tag}`;
const tagId = await ctx.cache.tryGet(`pingwest-tag-${tag}`, async () => {
const res = await got(encodeURI(tagUrl), {
headers: {
Referer: baseUrl,
},
});
const $ = cheerio.load(res.data);
const tagId = $('.tag-detail').attr('data-id');
return tagId;
});
const url = `${baseUrl}/api/tag_article_list`;
const response = await got(url, {
query: {
page: 1,
id: tagId,
type,
},
headers: {
Referer: baseUrl,
},
});
const $ = cheerio.load(response.data.data.list);
const items = $('.item')
.map((_, ele) => {
const className = ele.attribs.class;
if (className.includes('state')) {
return utils.statusListParser(cheerio.load(ele))[0];
}
if (className.includes('wire')) {
return utils.wireListParser(cheerio.load(ele))[0];
}
return utils.articleListParser(cheerio.load(ele))[0];
})
.get();
ctx.state.data = {
title: `品玩 - ${tag}`,
description: `品玩 - ${tag}`,
link: tagUrl,
item: items,
};
};

View File

@@ -0,0 +1,55 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const utils = require('./utils');
module.exports = async (ctx) => {
const { uid, type = 'article' } = ctx.params;
const baseUrl = 'https://www.pingwest.com';
const aimUrl = `${baseUrl}/user/${uid}/${type}`;
const { userName, realUid } = await ctx.cache.tryGet(`pingwest-user-info-${uid}`, async () => {
const res = await got(aimUrl, {
headers: {
Referer: baseUrl,
},
});
const $ = cheerio.load(res.data);
const userInfoNode = $('#J_userId');
return {
userName: userInfoNode.text(),
realUid: userInfoNode.attr('data-user-id'),
};
});
const url = `${baseUrl}/api/user_data`;
const response = await got(url, {
query: {
page: 1,
user_id: realUid,
tab: type,
},
headers: {
Referer: baseUrl,
},
});
const $ = cheerio.load(response.data.data.list);
let item = [];
switch (type) {
case 'article':
item = utils.articleListParser($);
break;
case 'state':
item = utils.statusListParser($);
break;
}
const typeToLabel = {
article: '文章',
state: '动态',
};
ctx.state.data = {
title: `品玩 - ${userName} - ${typeToLabel[type]}`,
description: `品玩 - ${userName} - ${typeToLabel[type]}`,
link: aimUrl,
item,
};
};

View File

@@ -0,0 +1,79 @@
const cheerio = require('cheerio');
const statusListParser = ($) => {
const items = $('.item')
.map((_, ele) => {
const timestamp = ele.attribs.pt;
const $item = cheerio.load(ele);
const mainNode = $item('.news-detail');
const imgsStr = mainNode
.find('img')
.map((_, ele) => `<img src="${ele.attribs.src}"/>`)
.get()
.join('<br/>');
const link = mainNode
.find('.content a')
.first()
.attr('href');
const content = mainNode
.text()
.trim()
.replace(/展开全文$/, '');
return {
title: content,
link: link.startsWith('http') ? link : `https:${link}`,
description: [content, imgsStr].filter((s) => !!s).join('<br/>'),
pubDate: new Date(timestamp * 1000).toUTCString(),
};
})
.get();
return items;
};
const articleListParser = ($) => {
const items = $('.item')
.map((_, ele) => {
const $item = cheerio.load(ele);
const timestamp = ele.attribs.pt;
const imgUrl = $item('.news-img img').attr('src');
const titleNode = $item('.title').first();
const title = titleNode.text();
const link = titleNode.find('a').attr('href');
const description = $item('.desc').text();
const author = $item('.author a').text();
return {
title,
link: link.startsWith('http') ? link : `https:${link}`,
description: [description, `<img src="${imgUrl}"/>`].join('<br/>'),
author,
pubDate: new Date(timestamp * 1000).toUTCString(),
};
})
.get();
return items;
};
const wireListParser = ($) => {
const items = $('.item')
.map((_, ele) => {
const $item = cheerio.load(ele);
const timestamp = ele.attribs.pt;
const titleNode = $item('.text').first();
const title = titleNode.text();
const link = titleNode.find('a').attr('href');
return {
title,
link: link.startsWith('http') ? link : `https:${link}`,
description: title,
pubDate: new Date(timestamp * 1000).toUTCString(),
};
})
.get();
return items;
};
module.exports = {
articleListParser,
statusListParser,
wireListParser,
};