diff --git a/docs/multimedia.md b/docs/multimedia.md
index 71b967e43..a4a7db3b8 100644
--- a/docs/multimedia.md
+++ b/docs/multimedia.md
@@ -704,9 +704,28 @@ pageClass: routes
-## subHD.tv - 最新字幕
+## Sub HD
+
+### 字幕
+
+
+
+| 最新字幕 | 热门字幕 | 剧集字幕 | 电影字幕 |
+| -------- | -------- | -------- | -------- |
+| new | top | tv | movie |
+
+
+
+### 字幕组
+
+
+
+| YYeTs 字幕组 | F.I.X 字幕侠 | 深影字幕组 | 擦枪字幕组 | 哒哒字幕组 | 迪幻字幕组 | 伊甸园字幕组 | H-SGDK 字幕组 | 蓝血字幕组 | GA 字幕组 | CC 标准电影字幕组 | NEW 字幕组 | Orange 字幕组 | 圣城家园 SCG 字幕组 | 纪录片之家字幕组 |
+| ------------ | ------------ | ---------- | ---------- | ---------- | ---------- | ------------ | ------------- | ---------- | --------- | ----------------- | ---------- | ------------- | ------------------- | ---------------- |
+| 14 | 28 | 2 | 118 | 132 | 20 | 1 | 18 | 71 | 11 | 75 | 130 | 66 | 19 | 10 |
+
+
-
## Trakt.tv
### 用户收藏
diff --git a/lib/router.js b/lib/router.js
index 14a7d53f9..06247be8f 100644
--- a/lib/router.js
+++ b/lib/router.js
@@ -1236,7 +1236,7 @@ router.get('/zimuzu/top/:range/:type', lazyloadRouteHandler('./routes/zimuzu/top
router.get('/zimuku/:type?', lazyloadRouteHandler('./routes/zimuku/index'));
// SubHD.tv
-router.get('/subhd/newest', lazyloadRouteHandler('./routes/subhd/newest'));
+// router.get('/subhd/newest', lazyloadRouteHandler('./routes/subhd/newest'));
// 虎嗅
router.get('/huxiu/tag/:id', lazyloadRouteHandler('./routes/huxiu/tag'));
diff --git a/lib/routes/subhd/newest.js b/lib/routes/subhd/newest.js
deleted file mode 100644
index 3f60fa4dc..000000000
--- a/lib/routes/subhd/newest.js
+++ /dev/null
@@ -1,29 +0,0 @@
-const got = require('@/utils/got');
-const cheerio = require('cheerio');
-
-module.exports = async (ctx) => {
- const response = await got({
- method: 'get',
- url: `https://subhd.tv/sub/new`,
- });
- const $ = cheerio.load(response.data);
-
- const item = $('.col-sm-9 div.position-relative')
- .map((index, ele) => {
- const link = $('table a.text-dark', ele).attr('href');
- const cover = $(ele).prev().find('a').html();
- return {
- title: $('table a.text-dark', ele).text(),
- link: `https://subhd.tv${link}`,
- author: $('.rounded-sm a', ele).text(),
- description: cover + $(ele).html(),
- };
- })
- .get();
-
- ctx.state.data = {
- title: `SubHD.tv - 最新字幕`,
- link: `https://subhd.tv/sub/new`,
- item,
- };
-};
diff --git a/lib/v2/subhd/index.js b/lib/v2/subhd/index.js
new file mode 100644
index 000000000..e0f3dd11c
--- /dev/null
+++ b/lib/v2/subhd/index.js
@@ -0,0 +1,79 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+const timezone = require('@/utils/timezone');
+const { parseDate } = require('@/utils/parse-date');
+
+const config = {
+ sub: {
+ title: '字幕',
+ category: 'new',
+ },
+ zu: {
+ title: '字幕组',
+ category: '14',
+ },
+ newest: {
+ category: 'for backwards compatibility',
+ },
+};
+
+module.exports = async (ctx) => {
+ const type = ctx.params.type ?? 'sub';
+ const category = ctx.params.category ?? config[type].category;
+
+ const rootUrl = 'https://subhd.tv';
+ const currentUrl = `${rootUrl}/${type === 'newest' ? 'sub/new' : `${type}/${category}${type === 'zu' ? '/l' : ''}`}`;
+
+ const response = await got({
+ method: 'get',
+ url: currentUrl,
+ });
+
+ const $ = cheerio.load(response.data);
+
+ $('.align-middle').each(function () {
+ $(this).removeClass('link-dark');
+ });
+
+ let items = $('.link-dark')
+ .toArray()
+ .map((item) => {
+ item = $(item);
+
+ const pubDate = item.parent().parent().find('.align-text-top').last().text();
+ const today = `${new Date().getFullYear()}-${new Date().getMonth()}-${new Date().getDate()}`;
+
+ return {
+ link: `${rootUrl}${item.attr('href')}`,
+ author: item.parent().parent().find('.text-dark').last().text(),
+ pubDate: timezone(parseDate(pubDate.indexOf('-') > -1 ? pubDate : `${today} ${pubDate}`), +8),
+ title: `${item.parent().parent().find('.align-middle').text()} ${item.text().replace(/ - SubHD/, '')}`,
+ };
+ });
+
+ items = await Promise.all(
+ items.map((item) =>
+ ctx.cache.tryGet(item.link, async () => {
+ const detailResponse = await got({
+ method: 'get',
+ url: item.link,
+ });
+
+ const content = cheerio.load(detailResponse.data);
+
+ content('.rounded-circle').remove();
+ content('.view-text').last().remove();
+
+ item.description = content('.view-text').html() + content('.bg-white').first().html();
+
+ return item;
+ })
+ )
+ );
+
+ ctx.state.data = {
+ title: $('title').text(),
+ link: currentUrl,
+ item: items,
+ };
+};
diff --git a/lib/v2/subhd/maintainer.js b/lib/v2/subhd/maintainer.js
new file mode 100644
index 000000000..1c2e5656c
--- /dev/null
+++ b/lib/v2/subhd/maintainer.js
@@ -0,0 +1,4 @@
+module.exports = {
+ '/sub/:category?': ['nczitzk'],
+ '/zu/:category?': ['nczitzk'],
+};
diff --git a/lib/v2/subhd/radar.js b/lib/v2/subhd/radar.js
new file mode 100644
index 000000000..05d72670f
--- /dev/null
+++ b/lib/v2/subhd/radar.js
@@ -0,0 +1,19 @@
+module.exports = {
+ 'subhd.tv': {
+ _name: 'Sub HD',
+ '.': [
+ {
+ title: '字幕',
+ docs: 'https://docs.rsshub.app/multimedia.html#subhd-zi-mu',
+ source: ['/sub/:category', '/'],
+ target: '/subhd/sub/:category?',
+ },
+ {
+ title: '字幕组',
+ docs: 'https://docs.rsshub.app/multimedia.html#subhd-zi-mu-zu',
+ source: ['/zu/:category', '/'],
+ target: '/subhd/zu/:category?',
+ },
+ ],
+ },
+};
diff --git a/lib/v2/subhd/router.js b/lib/v2/subhd/router.js
new file mode 100644
index 000000000..f6aadf778
--- /dev/null
+++ b/lib/v2/subhd/router.js
@@ -0,0 +1,3 @@
+module.exports = function (router) {
+ router.get('/:type?/:category?', require('./index'));
+};