feat(route): add LVV2 (#9200)
* feat(route): add LVV2 * fix(route): add timezone and remove title encoded in link * fix(route): fix regex
This commit is contained in:
parent
430148d1b9
commit
c4c6b3cf83
|
|
@ -719,6 +719,36 @@ Edition
|
|||
|
||||
</Route>
|
||||
|
||||
## LVV2
|
||||
|
||||
### 频道
|
||||
|
||||
<Route author="Fatpandac" example="/lvv2/news/sort-score" path="/news/:channel/:sort?" :paramsDesc="['频道,见下表', '排序方式,仅得分和24小时榜可选填该参数,见下表']">
|
||||
|
||||
| 热门 | 最新 | 得分 | 24 小时榜 |
|
||||
| :------: | :------: | :--------: | :-----------: |
|
||||
| sort-hot | sort-new | sort-score | sort-realtime |
|
||||
|
||||
| 排序方式 | 一小时内 | 一天内 | 一个周内 | 一个月内 |
|
||||
| :--: | :----: | :---: | :----: | :-----: |
|
||||
| | t-hour | t-day | t-week | t-month |
|
||||
|
||||
</Route>
|
||||
|
||||
### 24 小时点击排行 Top 10
|
||||
|
||||
<Route author="Fatpandac" example="/lvv2/top/sort-score" path="/top/:channel/:sort?" :paramsDesc="['频道,见下表', '排序方式,仅得分和24小时榜可选填该参数,见下表']">
|
||||
|
||||
| 热门 | 最新 | 得分 | 24 小时榜 |
|
||||
| :------: | :------: | :--------: | :-----------: |
|
||||
| sort-hot | sort-new | sort-score | sort-realtime |
|
||||
|
||||
| 排序方式 | 一小时内 | 一天内 | 一个周内 | 一个月内 |
|
||||
| :--: | :----: | :---: | :----: | :-----: |
|
||||
| | t-hour | t-day | t-week | t-month |
|
||||
|
||||
</Route>
|
||||
|
||||
## MakeUseOf
|
||||
|
||||
<Route author="nczitzk" example="/makeuseof" path="/makeuseof/:category?" :paramsDesc="['分类,默认为 Trending']"/>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
module.exports = {
|
||||
'/news/:channel/:sort?': ['Fatpandac'],
|
||||
'/top/:channel/:sort?': ['Fatpandac'],
|
||||
};
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const timezone = require('@/utils/timezone');
|
||||
const { art } = require('@/utils/render');
|
||||
const path = require('path');
|
||||
|
||||
const rootUrl = 'https://lvv2.com';
|
||||
|
||||
const titleMap = {
|
||||
'sort-realtime': {
|
||||
't-month': '24小时榜 一月内',
|
||||
't-week': '24小时榜 一周内',
|
||||
't-day': '24小时榜 一天内',
|
||||
't-hour': '24小时榜 一小时内',
|
||||
},
|
||||
'sort-hot': '热门',
|
||||
'sort-new': '最新',
|
||||
'sort-score': {
|
||||
't-month': '得分 一月内',
|
||||
't-week': '得分 一周内',
|
||||
't-day': '得分 一天内',
|
||||
't-hour': '得分 一小时内',
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const channel = ctx.params.channel;
|
||||
const sort = (channel === 'sort-realtime' || channel === 'sort-score') && !ctx.params.sort ? 't-week' : ctx.params.sort;
|
||||
const url = `${rootUrl}/${channel}/${sort}`;
|
||||
|
||||
const response = await got(url);
|
||||
const $ = cheerio.load(response.data);
|
||||
const list = $('div.spacer > div')
|
||||
.map((_, item) => ({
|
||||
title: $(item).find('h3 > a.title').text().trim(),
|
||||
author: $(item).find('a.author').text().trim(),
|
||||
link: new URL($(item).find('h3.title > a.title').attr('href'), rootUrl).href.replace(/(https:\/\/lvv2\.com.*?)\/title.*/, '$1'),
|
||||
pubDate: timezone(parseDate($(item).find('a.dateline > time').attr('datetime')), +8),
|
||||
}))
|
||||
.filter((_, item) => item.title !== '')
|
||||
.get();
|
||||
|
||||
const items = await Promise.all(
|
||||
list.map((item) =>
|
||||
ctx.cache.tryGet(item.link, async () => {
|
||||
if (item.link.indexOf('instant.lvv2.com') !== -1) {
|
||||
item.description = await ctx.cache.tryGet(item.link, async () => {
|
||||
const articleResponse = await got(item.link);
|
||||
const article = cheerio.load(articleResponse.data);
|
||||
|
||||
const description = article('#_tl_editor')
|
||||
.html()
|
||||
.replace(/src=['|"]data.*?['|"]/g, '')
|
||||
.replace(/(<img.*?)data-src(.*?>)/g, '$1src$2');
|
||||
|
||||
return description;
|
||||
});
|
||||
} else {
|
||||
item.description = art(path.join(__dirname, 'templates/outlink.art'), {
|
||||
outlink: item.link,
|
||||
});
|
||||
}
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
ctx.state.data = {
|
||||
title: `lvv2 - ${sort ? titleMap[channel][sort] : titleMap[channel]}`,
|
||||
link: url,
|
||||
item: items,
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
module.exports = {
|
||||
'lvv2.com': {
|
||||
_name: 'LVV2',
|
||||
'.': [
|
||||
{
|
||||
title: '热门',
|
||||
docs: 'https://docs.rsshub.app/new-media.html#lvv2',
|
||||
source: ['/sort-hot'],
|
||||
target: '/lvv2/news/sort-hot',
|
||||
},
|
||||
{
|
||||
title: '最新',
|
||||
docs: 'https://docs.rsshub.app/new-media.html#lvv2',
|
||||
source: ['/sort-new'],
|
||||
target: '/lvv2/news/sort-new',
|
||||
},
|
||||
{
|
||||
title: '得分',
|
||||
docs: 'https://docs.rsshub.app/new-media.html#lvv2',
|
||||
source: ['/sort-score', '/sort-score/:sort'],
|
||||
target: (params) => {
|
||||
if (!params.sort) {
|
||||
return '/lvv2/news/sort-score';
|
||||
} else {
|
||||
return `/lvv2/news/sort-score/${params.sort}`;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '24小时榜',
|
||||
docs: 'https://docs.rsshub.app/new-media.html#lvv2',
|
||||
source: ['/sort-realtime', '/sort-realtime/:sort'],
|
||||
target: (params) => {
|
||||
if (!params.sort) {
|
||||
return '/lvv2/news/sort-realtime';
|
||||
} else {
|
||||
return `/lvv2/news/sort-realtime/${params.sort}`;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '热门 24小时 Top 10',
|
||||
docs: 'https://docs.rsshub.app/new-media.html#lvv2',
|
||||
source: ['/', '/sort-hot'],
|
||||
target: '/lvv2/top/sort-hot',
|
||||
},
|
||||
{
|
||||
title: '最新 24小时 Top 10',
|
||||
docs: 'https://docs.rsshub.app/new-media.html#lvv2',
|
||||
source: ['/sort-new'],
|
||||
target: '/lvv2/top/sort-new',
|
||||
},
|
||||
{
|
||||
title: '得分 24小时 Top 10',
|
||||
docs: 'https://docs.rsshub.app/new-media.html#lvv2',
|
||||
source: ['/sort-score', '/sort-score/:sort'],
|
||||
target: (params) => {
|
||||
if (!params.sort) {
|
||||
return '/lvv2/top/sort-score';
|
||||
} else {
|
||||
return `/lvv2/top/sort-score/${params.sort}`;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '24小时榜 24小时 Top 10',
|
||||
docs: 'https://docs.rsshub.app/new-media.html#lvv2',
|
||||
source: ['/sort-realtime', '/sort-realtime/:sort'],
|
||||
target: (params) => {
|
||||
if (!params.sort) {
|
||||
return '/lvv2/top/sort-realtime';
|
||||
} else {
|
||||
return `/lvv2/top/sort-realtime/${params.sort}`;
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
module.exports = function (router) {
|
||||
router.get('/news/:channel/:sort?', require('./news'));
|
||||
router.get('/top/:channel/:sort?', require('./top'));
|
||||
};
|
||||
|
|
@ -0,0 +1 @@
|
|||
<a href='{{ outlink }}' target="_blank">文章链接</a>
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const timezone = require('@/utils/timezone');
|
||||
const { art } = require('@/utils/render');
|
||||
const path = require('path');
|
||||
|
||||
const rootUrl = 'https://lvv2.com';
|
||||
|
||||
const titleMap = {
|
||||
'sort-realtime': {
|
||||
't-month': '24小时榜 一月内',
|
||||
't-week': '24小时榜 一周内',
|
||||
't-day': '24小时榜 一天内',
|
||||
't-hour': '24小时榜 一小时内',
|
||||
},
|
||||
'sort-hot': '热门',
|
||||
'sort-new': '最新',
|
||||
'sort-score': {
|
||||
't-month': '得分 一月内',
|
||||
't-week': '得分 一周内',
|
||||
't-day': '得分 一天内',
|
||||
't-hour': '得分 一小时内',
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const channel = ctx.params.channel;
|
||||
const sort = (channel === 'sort-realtime' || channel === 'sort-score') && !ctx.params.sort ? 't-week' : ctx.params.sort;
|
||||
const url = `${rootUrl}/${channel}/${sort}`;
|
||||
|
||||
const response = await got(url);
|
||||
const $ = cheerio.load(response.data);
|
||||
const list = $('#top-content-news > div')
|
||||
.map((_, item) => ({
|
||||
title: $(item).find('div.md > a').text(),
|
||||
link: new URL($(item).find('div.md > a').attr('href'), rootUrl).href.replace(/(https:\/\/lvv2\.com.*?)\/title.*/, '$1'),
|
||||
}))
|
||||
.get();
|
||||
|
||||
const items = await Promise.all(
|
||||
list.map((item) =>
|
||||
ctx.cache.tryGet(item.link, async () => {
|
||||
const detailResponse = await got.get(item.link);
|
||||
const content = cheerio.load(detailResponse.data);
|
||||
|
||||
item.pubDate = timezone(parseDate(content('time').attr('datetime')), +8);
|
||||
item.author = content('a.author').text();
|
||||
const link = content('h2.title > a.title').attr('href');
|
||||
if (link.indexOf('instant.lvv2.com') !== -1) {
|
||||
item.description = await ctx.cache.tryGet(link, async () => {
|
||||
const articleResponse = await got(link);
|
||||
const article = cheerio.load(articleResponse.data);
|
||||
|
||||
const description = article('#_tl_editor')
|
||||
.html()
|
||||
.replace(/(<img.*?)data-src(.*?>)/g, '$1src$2');
|
||||
|
||||
return description;
|
||||
});
|
||||
} else {
|
||||
item.description = art(path.join(__dirname, 'templates/outlink.art'), {
|
||||
outlink: link,
|
||||
});
|
||||
}
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
ctx.state.data = {
|
||||
title: `lvv2 - ${sort ? titleMap[channel][sort] : titleMap[channel]} 24小时点击 Top 10`,
|
||||
link: url,
|
||||
item: items,
|
||||
};
|
||||
};
|
||||
Loading…
Reference in New Issue