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:
Fatpandac 2022-02-26 08:28:36 +08:00 committed by GitHub
parent 430148d1b9
commit c4c6b3cf83
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 270 additions and 0 deletions

View File

@ -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']"/>

View File

@ -0,0 +1,4 @@
module.exports = {
'/news/:channel/:sort?': ['Fatpandac'],
'/top/:channel/:sort?': ['Fatpandac'],
};

75
lib/v2/lvv2/news.js Normal file
View File

@ -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,
};
};

79
lib/v2/lvv2/radar.js Normal file
View File

@ -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}`;
}
},
},
],
},
};

4
lib/v2/lvv2/router.js Normal file
View File

@ -0,0 +1,4 @@
module.exports = function (router) {
router.get('/news/:channel/:sort?', require('./news'));
router.get('/top/:channel/:sort?', require('./top'));
};

View File

@ -0,0 +1 @@
<a href='{{ outlink }}' target="_blank">文章链接</a>

77
lib/v2/lvv2/top.js Normal file
View File

@ -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,
};
};