fix(route): 站酷发现 (#10839)

* fix(route): 站酷发现

* fix(route): zcool top & user
This commit is contained in:
Ethan Shen
2022-09-21 00:52:05 +08:00
committed by GitHub
parent 97358c18aa
commit 89ee2f92e0
15 changed files with 299 additions and 221 deletions
+53 -53
View File
@@ -1021,59 +1021,59 @@ module.exports = {
},
],
},
'zcool.com.cn': {
_name: '站酷',
www: [
{
title: '发现',
docs: 'https://docs.rsshub.app/design.html#zhan-ku',
source: '',
target: '/zcool/discover',
},
{
title: '发现 - 精选 - 全部推荐',
docs: 'https://docs.rsshub.app/design.html#zhan-ku',
source: '',
target: '/zcool/discover/all',
},
{
title: '发现 - 精选 - 首页推荐',
docs: 'https://docs.rsshub.app/design.html#zhan-ku',
source: '',
target: '/zcool/discover/home',
},
{
title: '发现 - 精选 - 编辑精选',
docs: 'https://docs.rsshub.app/design.html#zhan-ku',
source: '',
target: '/zcool/discover/home',
},
{
title: '发现 - 精选 - 文章 - 编辑精选',
docs: 'https://docs.rsshub.app/design.html#zhan-ku',
source: '',
target: '/zcool/discover/article',
},
{
title: '作品榜单',
docs: 'https://docs.rsshub.app/design.html#zhan-ku',
source: '',
target: '/zcool/top/design',
},
{
title: '文章榜单',
docs: 'https://docs.rsshub.app/design.html#zhan-ku',
source: '',
target: '/zcool/top/article',
},
{
title: '用户作品',
docs: 'https://docs.rsshub.app/design.html#zhan-ku',
source: ['/u/:id'],
target: `/zcool/user/:id`,
},
],
},
// 'zcool.com.cn': {
// _name: '站酷',
// www: [
// {
// title: '发现',
// docs: 'https://docs.rsshub.app/design.html#zhan-ku',
// source: '',
// target: '/zcool/discover',
// },
// {
// title: '发现 - 精选 - 全部推荐',
// docs: 'https://docs.rsshub.app/design.html#zhan-ku',
// source: '',
// target: '/zcool/discover/all',
// },
// {
// title: '发现 - 精选 - 首页推荐',
// docs: 'https://docs.rsshub.app/design.html#zhan-ku',
// source: '',
// target: '/zcool/discover/home',
// },
// {
// title: '发现 - 精选 - 编辑精选',
// docs: 'https://docs.rsshub.app/design.html#zhan-ku',
// source: '',
// target: '/zcool/discover/home',
// },
// {
// title: '发现 - 精选 - 文章 - 编辑精选',
// docs: 'https://docs.rsshub.app/design.html#zhan-ku',
// source: '',
// target: '/zcool/discover/article',
// },
// {
// title: '作品榜单',
// docs: 'https://docs.rsshub.app/design.html#zhan-ku',
// source: '',
// target: '/zcool/top/design',
// },
// {
// title: '文章榜单',
// docs: 'https://docs.rsshub.app/design.html#zhan-ku',
// source: '',
// target: '/zcool/top/article',
// },
// {
// title: '用户作品',
// docs: 'https://docs.rsshub.app/design.html#zhan-ku',
// source: ['/u/:id'],
// target: `/zcool/user/:id`,
// },
// ],
// },
'zhuixinfan.com': {
_name: '追新番日剧站',
'.': [
+5 -5
View File
@@ -1866,11 +1866,11 @@ router.get('/getitfree/search/:keyword?', lazyloadRouteHandler('./routes/getitfr
router.get('/10000link/news/:category?', lazyloadRouteHandler('./routes/10000link/news'));
// 站酷
router.get('/zcool/discover/:query?/:subCate?/:hasVideo?/:city?/:collage?/:recommendLevel?/:sort?', lazyloadRouteHandler('./routes/zcool/discover'));
router.get('/zcool/recommend/:query?/:subCate?/:hasVideo?/:city?/:collage?/:recommendLevel?/:sort?', lazyloadRouteHandler('./routes/zcool/discover')); // 兼容老版本
router.get('/zcool/top/:type', lazyloadRouteHandler('./routes/zcool/top'));
router.get('/zcool/top', lazyloadRouteHandler('./routes/zcool/top')); // 兼容老版本
router.get('/zcool/user/:uid', lazyloadRouteHandler('./routes/zcool/user'));
// router.get('/zcool/discover/:query?/:subCate?/:hasVideo?/:city?/:collage?/:recommendLevel?/:sort?', lazyloadRouteHandler('./routes/zcool/discover'));
// router.get('/zcool/recommend/:query?/:subCate?/:hasVideo?/:city?/:collage?/:recommendLevel?/:sort?', lazyloadRouteHandler('./routes/zcool/discover')); // 兼容老版本
// router.get('/zcool/top/:type', lazyloadRouteHandler('./routes/zcool/top'));
// 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'));
-75
View File
@@ -1,75 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
module.exports = async (ctx) => {
const type = ctx.params.type;
const url = 'https://www.zcool.com.cn/top/index.do';
const topResponse = await got({
method: 'get',
url,
headers: {
Referer: 'https://www.zcool.com.cn',
},
});
let $ = cheerio.load(topResponse.data);
const rankId = $('div.list-cycle>p>span').text();
if (type === 'article') {
const articleResponse = await got({
method: 'get',
url: 'https://www.zcool.com.cn/top/article.do?rankType=8&rankId=' + rankId,
headers: {
Referer: url,
},
});
$ = cheerio.load(articleResponse.data);
}
const list = $('div.author')
.map((i, e) => {
const element = $(e);
const title = element.find('div.title').find('a').text();
const link = element.find('div.title').find('a').attr('href');
const author = element.find('div.nick').find('a').text();
return {
title,
description: '',
link,
author,
};
})
.get();
const result = await Promise.all(
list.map(async (item) => {
const link = item.link;
const cache = await ctx.cache.get(link);
if (cache) {
return Promise.resolve(JSON.parse(cache));
}
const itemResponse = await got({
method: 'get',
url: link,
headers: {
Referer: url,
},
});
const itemElement = cheerio.load(itemResponse.data);
item.description = type !== 'article' ? itemElement('div.work-content-wrap').html() : itemElement('div.article-content-wraper').html();
ctx.cache.set(link, JSON.stringify(item));
return item;
})
);
ctx.state.data = {
title: '站酷 - 第' + rankId + '期' + (type !== 'article' ? '作品总榜' : '文章总榜'),
link: url,
item: result,
};
};
-58
View File
@@ -1,58 +0,0 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
module.exports = async (ctx) => {
let uid = ctx.params.uid;
if (isNaN(uid)) {
const user_response = await got.get(`https://${uid}.zcool.com.cn/`);
const $ = cheerio.load(user_response.data);
uid = $('[data-id]').attr('data-id');
}
const url = `https://api.zcool.com.cn/v2/api/u/${uid}`;
const response = await got.get(url);
const data = response.data.data;
const user = data.content[0].creatorObj;
const list = data.content;
const out = await Promise.all(
list.map(async (item) => {
const link = item.pageUrl;
const cache = await ctx.cache.get(link);
if (cache) {
return Promise.resolve(JSON.parse(cache));
}
const rssitem = {
title: item.title,
link,
author: item.creatorObj.username,
pubDate: new Date(item.createTime * 1),
};
try {
const item_response = await got.get(link);
const item_element = cheerio.load(item_response.data);
const item_content_wrap = item_element('.work-content-wrap');
const item_content = item_content_wrap.length !== 0 ? item_content_wrap : item_element('.work-show-box');
rssitem.description = item_content.html();
} catch (err) {
return Promise.resolve('');
}
ctx.cache.set(link, JSON.stringify(rssitem));
return Promise.resolve(rssitem);
})
);
ctx.state.data = {
title: '站酷 - ' + user.username,
image: user.avatar,
link: user.pageUrl,
item: out.filter((item) => item !== ''),
};
};
@@ -1,5 +1,8 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const { parseDate } = require('@/utils/parse-date');
const { art } = require('@/utils/render');
const path = require('path');
const locations = require('./locations');
module.exports = async (ctx) => {
@@ -41,21 +44,22 @@ module.exports = async (ctx) => {
const queries = {
cate: '0',
subCate: ctx.params.subCate || '0',
city: ctx.params.city || '0',
college: ctx.params.college || '0',
recommendLevel: ctx.params.recommendLevel || '2',
sort: ctx.params.sort || '9',
subCate: ctx.params.subCate ?? '0',
city: ctx.params.city ?? '0',
college: ctx.params.college ?? '0',
recommendLevel: ctx.params.recommendLevel ?? '2',
sort: ctx.params.sort ?? '9',
limit: ctx.query.limit ?? '25',
};
let query = ctx.params.query || '';
let query = ctx.params.query ?? '';
if (query.indexOf('=') > -1) {
for (const q of query.split('&')) {
const kv = q.split('=');
queries[kv[0]] = kv[1];
}
queries.limit = '20';
queries.limit = '25';
queries.page = '1';
} else {
switch (query) {
@@ -73,7 +77,7 @@ module.exports = async (ctx) => {
queries.recommendLevel = '2';
break;
default:
queries.cate = ctx.params.query || '0';
queries.cate = ctx.params.query ?? '0';
}
}
@@ -89,18 +93,19 @@ module.exports = async (ctx) => {
query = query.substr(0, query.length - 1);
const rootUrl = 'https://www.zcool.com.cn';
const currentUrl = `${rootUrl}/discover.json?${query}`;
const currentUrl = `${rootUrl}/p1/discover/list?${query}`;
const response = await got({
method: 'get',
url: currentUrl,
});
const list = response.data.data.data.map((item) => ({
title: item.object.title,
link: item.object.pageUrl,
pubDate: new Date(item.object.publishTime),
author: item.object.creatorObj.username,
const list = response.data.datas.map((item) => ({
title: item.content.title,
link: item.content.pageUrl,
pubDate: parseDate(item.content.publishTime),
author: item.content.creatorObj.username,
category: item.content.tags,
}));
const items = await Promise.all(
@@ -121,11 +126,18 @@ module.exports = async (ctx) => {
if (i >= videos.length) {
return;
}
content(this).append(`<video src="${videos[i].match(/source: '(https:\/\/video\.zcool\.cn\/.*)'/)[1]}" controls="controls">`);
content(this).append(
art(path.join(__dirname, 'templates/description.art'), {
video: videos[i].match(/source: '(https:\/\/video\.zcool\.cn\/.*)'/)[1],
})
);
});
}
item.description = item.link.includes('article') ? content('.work-content-wrap').html() : content('.article-content-wraper').html();
item.description = art(path.join(__dirname, 'templates/description.art'), {
description: item.link.includes('article') ? content('.articleContentWrapper').html() : content('.workShowBox').parent().html(),
});
return item;
})
@@ -133,7 +145,7 @@ module.exports = async (ctx) => {
);
ctx.state.data = {
title: `${categories[queries.cate]}${queries.subCate === '0' ? '' : ` - ${subCategories[queries.cate][queries.subCate]}`} - 站酷`,
title: `站酷 - ${categories[queries.cate]}${queries.subCate === '0' ? '' : ` - ${subCategories[queries.cate][queries.subCate]}`}`,
link: `${rootUrl}/discover?${query}`,
item: items,
};
+7
View File
@@ -0,0 +1,7 @@
module.exports = {
'/discover/:type?': ['junbaor', 'nczitzk'],
'/discover/:query?': ['nczitzk'],
'/discover/:query?/:subCate?/:hasVideo?/:city?/:college?/:recommendLevel?/:sort?': ['nczitzk'],
'/top/:type': ['mexunco'],
'/user/:uid': ['junbaor'],
};
+55
View File
@@ -0,0 +1,55 @@
module.exports = {
'zcool.com.cn': {
_name: '站酷',
www: [
{
title: '发现',
docs: 'https://docs.rsshub.app/design.html#zhan-ku',
source: ['/discover', '/'],
target: (params, url) => `/zcool/discover/${new URL(url).toString().split('?').pop()}`,
},
{
title: '发现 - 精选 - 全部推荐',
docs: 'https://docs.rsshub.app/design.html#zhan-ku',
source: '',
target: '/zcool/discover/all',
},
{
title: '发现 - 精选 - 首页推荐',
docs: 'https://docs.rsshub.app/design.html#zhan-ku',
source: '',
target: '/zcool/discover/home',
},
{
title: '发现 - 精选 - 编辑精选',
docs: 'https://docs.rsshub.app/design.html#zhan-ku',
source: '',
target: '/zcool/discover/home',
},
{
title: '发现 - 精选 - 文章 - 编辑精选',
docs: 'https://docs.rsshub.app/design.html#zhan-ku',
source: '',
target: '/zcool/discover/article',
},
{
title: '作品榜单',
docs: 'https://docs.rsshub.app/design.html#zhan-ku',
source: '',
target: '/zcool/top/design',
},
{
title: '文章榜单',
docs: 'https://docs.rsshub.app/design.html#zhan-ku',
source: '',
target: '/zcool/top/article',
},
{
title: '用户作品',
docs: 'https://docs.rsshub.app/design.html#zhan-ku',
source: ['/u/:id'],
target: `/zcool/user/:id`,
},
],
},
};
+5
View File
@@ -0,0 +1,5 @@
module.exports = function (router) {
router.get('/discover/:query?/:subCate?/:hasVideo?/:city?/:college?/:recommendLevel?/:sort?', require('./discover'));
router.get('/top/:type', require('./top'));
router.get('/user/:uid', require('./user'));
};
+8
View File
@@ -0,0 +1,8 @@
{{ if video }}
<video controls>
<source src="{{ video }}" type="video/mp4">
</video>
{{ /if }}
{{ if description }}
{{@ description }}
{{ /if }}
+11
View File
@@ -0,0 +1,11 @@
{{ if data.description }}
{{@ data.description }}
{{ /if }}
{{ if data.productImages }}
{{ each data.productImages image }}
<img src="{{ image.urlBig.includes('?x-oss-process') ? image.urlBig.split('?')[0] : image.urlBig }}">
{{ if image.description }}
{{@ image.description }}
{{ /if }}
{{ /each }}
{{ /if }}
+51
View File
@@ -0,0 +1,51 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const { parseDate } = require('@/utils/parse-date');
const { extractArticle, extractWork } = require('./utils');
const baseUrl = 'https://www.zcool.com.cn';
module.exports = async (ctx) => {
const { type } = ctx.params;
const url = `${baseUrl}/top/${type === 'design' ? 'index.do' : 'article.do?rankType=8'}`;
const { data: response } = await got(url);
const $ = cheerio.load(response);
const data = JSON.parse($('script#__NEXT_DATA__').text());
const list = data.props.pageProps.listResult.data.map((item) => ({
title: item.rankingTitle,
author: item.member.name,
category: [item.productCategoryStr, item.productSubCateStr, ...item.tags],
link: item.pageUrl,
pubDate: parseDate(item.rankingPublishTime),
}));
const items = await Promise.all(
list.map((item) =>
ctx.cache.tryGet(item.link, async () => {
const { data: response } = await got(item.link);
const $ = cheerio.load(response);
const data = JSON.parse($('script#__NEXT_DATA__').text());
item.pubDate = parseDate(data.props.pageProps.data.publishTime, 'x');
if (item.link.startsWith('https://www.zcool.com.cn/article/')) {
item.description = extractArticle(data);
} else if (item.link.startsWith('https://www.zcool.com.cn/work/')) {
item.description = extractWork(data);
}
return item;
})
)
);
ctx.state.data = {
title: data.props.pageProps.seo.title,
description: data.props.pageProps.seo.description,
link: url,
item: items,
};
};
+48
View File
@@ -0,0 +1,48 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const { parseDate } = require('@/utils/parse-date');
const { extractArticle, extractWork } = require('./utils');
module.exports = async (ctx) => {
const { uid } = ctx.params;
let pageUrl = `https://www.zcool.com.cn/u/${uid}`;
if (isNaN(uid)) {
pageUrl = `https://${uid}.zcool.com.cn`;
}
const { data: response } = await got(pageUrl);
const $ = cheerio.load(response);
const data = JSON.parse($('script#__NEXT_DATA__').text());
const workList = data.props.pageProps.workList.map((item) => ({
title: item.title,
link: item.pageUrl,
pubDate: parseDate(item.publishTime, 'x'),
category: [item.objectTypeStr, item.cateStr, item.subCateStr, ...item.tags],
}));
const items = await Promise.all(
workList.map((item) =>
ctx.cache.tryGet(item.link, async () => {
const { data: response } = await got(item.link);
const $ = cheerio.load(response);
const data = JSON.parse($('script#__NEXT_DATA__').text());
if (item.link.startsWith('https://www.zcool.com.cn/article/')) {
item.description = extractArticle(data);
} else if (item.link.startsWith('https://www.zcool.com.cn/work/')) {
item.description = extractWork(data);
}
return item;
})
)
);
ctx.state.data = {
title: data.props.pageProps.seo.title,
description: data.props.pageProps.seo.description,
image: data.props.pageProps.userInfo.avatar.includes('?x-oss-process') ? data.props.pageProps.userInfo.avatar.split('?')[0] : data.props.pageProps.userInfo.avatar,
link: pageUrl,
item: items,
};
};
+14
View File
@@ -0,0 +1,14 @@
const { art } = require('@/utils/render');
const path = require('path');
const extractArticle = (data) => data.props.pageProps.data.summary + data.props.pageProps.data.memo;
const extractWork = (data) =>
art(path.join(__dirname, 'templates/work.art'), {
data: data.props.pageProps.data,
});
module.exports = {
extractArticle,
extractWork,
};