diff --git a/docs/en/live.md b/docs/en/live.md
index 6151b0582e..3660f22ec2 100644
--- a/docs/en/live.md
+++ b/docs/en/live.md
@@ -3,3 +3,9 @@ pageClass: routes
---
# Live
+
+## V LIVE
+
+### Board
+
+
diff --git a/docs/en/social-media.md b/docs/en/social-media.md
index f636791d06..367da4b2ff 100644
--- a/docs/en/social-media.md
+++ b/docs/en/social-media.md
@@ -359,7 +359,7 @@ generates
-## User following timeline
+### User following timeline
diff --git a/lib/v2/vlive/index.js b/lib/v2/vlive/index.js
new file mode 100644
index 0000000000..3721ff43af
--- /dev/null
+++ b/lib/v2/vlive/index.js
@@ -0,0 +1,71 @@
+const got = require('@/utils/got');
+const { JSDOM } = require('jsdom');
+const { parseDate } = require('@/utils/parse-date');
+const { art } = require('@/utils/render');
+const path = require('path');
+
+const baseUrl = 'https://www.vlive.tv';
+
+module.exports = async (ctx) => {
+ const { channel, board } = ctx.params;
+ const link = `${baseUrl}/channel/${channel}/board/${board}`;
+
+ const response = await got(link);
+ const dom = new JSDOM(response.data, {
+ runScripts: 'dangerously',
+ });
+ const preloadedState = dom.window.__PRELOADED_STATE__;
+ const channelData = preloadedState.channel.channel;
+ const userCountry = preloadedState.common.userCountry;
+ const userLanguage = preloadedState.common.userLanguage;
+
+ const apiResponse = await got(`${baseUrl}/globalv-web/vam-web/post/v1.0/board-${board}/posts`, {
+ searchParams: {
+ appId: '8c6cc7b45d2568fb668be6e05b6e5a3b',
+ fields: 'attachments,author,availableActions,board{boardId,title,boardType,payRequired,includedCountries,excludedCountries},channel{channelName,channelCode},totalCommentCount,contentType,createdAt,emotionCount,excludedCountries,includedCountries,isCommentEnabled,isHiddenFromStar,lastModifierMember,notice,officialVideo,plainBody,postId,postVersion,reservation,starReactions,targetMember,thumbnail,title,url,writtenIn,sharedPosts,originPost,blindType',
+ sortType: 'LATEST',
+ limit: ctx.query.limit ? Number(ctx.query.limit) : 20,
+ gcc: userCountry,
+ locale: userLanguage,
+ },
+ headers: {
+ referer: link,
+ },
+ });
+
+ const items = apiResponse.data.data.map((item) => {
+ let description;
+ switch (item.contentType) {
+ case 'POST':
+ description = art(path.join(__dirname, 'templates/post.art'), {
+ post: item.plainBody?.replace(/\r\n/g, '
').replace(/\n/g, '
'),
+ images: item.attachments.photo,
+ });
+ break;
+ case 'VIDEO':
+ description = art(path.join(__dirname, 'templates/video.art'), {
+ link: item.url,
+ image: item.officialVideo.thumb,
+ });
+ break;
+ default:
+ throw `Unknown content type: ${item.contentType}`;
+ }
+
+ return {
+ title: item.title,
+ description,
+ link: item.url,
+ author: item.author.nickname,
+ pubDate: parseDate(item.createdAt),
+ };
+ });
+
+ ctx.state.data = {
+ title: `${channelData.channelName} Channel`,
+ description: channelData.channelDescription,
+ link,
+ image: channelData.channelProfileImage,
+ item: items,
+ };
+};
diff --git a/lib/v2/vlive/radar.js b/lib/v2/vlive/radar.js
new file mode 100644
index 0000000000..94b4c8790f
--- /dev/null
+++ b/lib/v2/vlive/radar.js
@@ -0,0 +1,13 @@
+module.exports = {
+ 'vlive.tv': {
+ _name: 'V LIVE',
+ '.': [
+ {
+ title: 'Board',
+ docs: 'https://docs.rsshub.app/en/live.html#v-live',
+ source: '/channel/:board/board/:board',
+ target: '/vlive/channel/:board/board/:board',
+ },
+ ],
+ },
+};
diff --git a/lib/v2/vlive/router.js b/lib/v2/vlive/router.js
new file mode 100644
index 0000000000..fb3c0f7ece
--- /dev/null
+++ b/lib/v2/vlive/router.js
@@ -0,0 +1,3 @@
+module.exports = (router) => {
+ router.get('/channel/:channel/board/:board', require('./index'));
+};
diff --git a/lib/v2/vlive/templates/post.art b/lib/v2/vlive/templates/post.art
new file mode 100644
index 0000000000..208ee05d01
--- /dev/null
+++ b/lib/v2/vlive/templates/post.art
@@ -0,0 +1,8 @@
+{{ if post }}
+{{@ post }}
+{{ /if }}
+{{ if images }}
+{{ each images image }}
+
+{{ /each }}
+{{ /if }}
diff --git a/lib/v2/vlive/templates/video.art b/lib/v2/vlive/templates/video.art
new file mode 100644
index 0000000000..33e880a138
--- /dev/null
+++ b/lib/v2/vlive/templates/video.art
@@ -0,0 +1,3 @@
+{{ if image }}
+
+{{ /if }}