diff --git a/docs/new-media.md b/docs/new-media.md
index 98f0cc7e2..791a94bb6 100644
--- a/docs/new-media.md
+++ b/docs/new-media.md
@@ -719,6 +719,36 @@ Edition
+## LVV2
+
+### 频道
+
+
+
+| 热门 | 最新 | 得分 | 24 小时榜 |
+| :------: | :------: | :--------: | :-----------: |
+| sort-hot | sort-new | sort-score | sort-realtime |
+
+| 排序方式 | 一小时内 | 一天内 | 一个周内 | 一个月内 |
+| :--: | :----: | :---: | :----: | :-----: |
+| | t-hour | t-day | t-week | t-month |
+
+
+
+### 24 小时点击排行 Top 10
+
+
+
+| 热门 | 最新 | 得分 | 24 小时榜 |
+| :------: | :------: | :--------: | :-----------: |
+| sort-hot | sort-new | sort-score | sort-realtime |
+
+| 排序方式 | 一小时内 | 一天内 | 一个周内 | 一个月内 |
+| :--: | :----: | :---: | :----: | :-----: |
+| | t-hour | t-day | t-week | t-month |
+
+
+
## MakeUseOf
diff --git a/lib/v2/lvv2/maintainer.js b/lib/v2/lvv2/maintainer.js
new file mode 100644
index 000000000..3b7dd702e
--- /dev/null
+++ b/lib/v2/lvv2/maintainer.js
@@ -0,0 +1,4 @@
+module.exports = {
+ '/news/:channel/:sort?': ['Fatpandac'],
+ '/top/:channel/:sort?': ['Fatpandac'],
+};
diff --git a/lib/v2/lvv2/news.js b/lib/v2/lvv2/news.js
new file mode 100644
index 000000000..ef6e2aba8
--- /dev/null
+++ b/lib/v2/lvv2/news.js
@@ -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(/()/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,
+ };
+};
diff --git a/lib/v2/lvv2/radar.js b/lib/v2/lvv2/radar.js
new file mode 100644
index 000000000..d4be95817
--- /dev/null
+++ b/lib/v2/lvv2/radar.js
@@ -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}`;
+ }
+ },
+ },
+ ],
+ },
+};
diff --git a/lib/v2/lvv2/router.js b/lib/v2/lvv2/router.js
new file mode 100644
index 000000000..870b12a43
--- /dev/null
+++ b/lib/v2/lvv2/router.js
@@ -0,0 +1,4 @@
+module.exports = function (router) {
+ router.get('/news/:channel/:sort?', require('./news'));
+ router.get('/top/:channel/:sort?', require('./top'));
+};
diff --git a/lib/v2/lvv2/templates/outlink.art b/lib/v2/lvv2/templates/outlink.art
new file mode 100644
index 000000000..e89a59ec1
--- /dev/null
+++ b/lib/v2/lvv2/templates/outlink.art
@@ -0,0 +1 @@
+文章链接
diff --git a/lib/v2/lvv2/top.js b/lib/v2/lvv2/top.js
new file mode 100644
index 000000000..5df85527b
--- /dev/null
+++ b/lib/v2/lvv2/top.js
@@ -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(/()/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,
+ };
+};