diff --git a/docs/new-media.md b/docs/new-media.md
index ed16e82e33..737e235aba 100644
--- a/docs/new-media.md
+++ b/docs/new-media.md
@@ -1491,6 +1491,10 @@ Provides all of the Thrillist articles with the specified tag.
## UNTAG
+### 时间线
+
+
+
### 分类
diff --git a/lib/v2/utgd/maintainer.js b/lib/v2/utgd/maintainer.js
index 3a54ff4efd..3620497298 100644
--- a/lib/v2/utgd/maintainer.js
+++ b/lib/v2/utgd/maintainer.js
@@ -1,4 +1,5 @@
module.exports = {
- '/:category?': ['nczitzk'],
+ '/timeline': ['nczitzk'],
'/topic/:topic?': ['nczitzk'],
+ '/:category?': ['nczitzk'],
};
diff --git a/lib/v2/utgd/radar.js b/lib/v2/utgd/radar.js
index beb6b42747..4165e013f0 100644
--- a/lib/v2/utgd/radar.js
+++ b/lib/v2/utgd/radar.js
@@ -2,6 +2,12 @@ module.exports = {
'utgd.net': {
_name: 'UNTAG',
'.': [
+ {
+ title: '时间线',
+ docs: 'https://docs.rsshub.app/new-media.html#untag-shi-jian-xian',
+ source: ['/'],
+ target: '/utgd/timeline',
+ },
{
title: '分类',
docs: 'https://docs.rsshub.app/new-media.html#untag-fen-lei',
diff --git a/lib/v2/utgd/router.js b/lib/v2/utgd/router.js
index ce4505f48b..9973e10d53 100644
--- a/lib/v2/utgd/router.js
+++ b/lib/v2/utgd/router.js
@@ -1,4 +1,5 @@
module.exports = function (router) {
+ router.get('/timeline', require('./timeline'));
router.get('/topic/:topic?', require('./topic'));
router.get('/:category?', require('./category'));
};
diff --git a/lib/v2/utgd/timeline.js b/lib/v2/utgd/timeline.js
new file mode 100644
index 0000000000..21587f1a1d
--- /dev/null
+++ b/lib/v2/utgd/timeline.js
@@ -0,0 +1,54 @@
+const got = require('@/utils/got');
+const timezone = require('@/utils/timezone');
+const { parseDate } = require('@/utils/parse-date');
+const { art } = require('@/utils/render');
+const path = require('path');
+const md = require('markdown-it')({
+ html: true,
+});
+
+module.exports = async (ctx) => {
+ const limit = ctx.query.limit ? parseInt(ctx.query.limit) : 20;
+
+ const rootUrl = 'https://utgd.net';
+ const apiUrl = `${rootUrl}/api/v2/timeline/?page=1&page_size=${limit}`;
+
+ const response = await got({
+ method: 'get',
+ url: apiUrl,
+ });
+
+ const items = await Promise.all(
+ response.data.results.slice(0, limit).map((item) =>
+ ctx.cache.tryGet(`untag-${item.id}`, async () => {
+ const detailResponse = await got({
+ method: 'get',
+ url: `${rootUrl}/api/v2/pages/${item.id}/`,
+ searchParams: {
+ fields: 'article_content,article_category(category_name),article_tag(tag_name)',
+ },
+ });
+
+ const data = detailResponse.data;
+
+ return {
+ title: item.title,
+ link: `${rootUrl}/article/${item.id}`,
+ description: art(path.join(__dirname, 'templates/description.art'), {
+ image: item.article_image,
+ description: md.render(data.article_content),
+ }),
+ author: item.article_author_displayname,
+ pubDate: timezone(parseDate(item.article_published_time), +8),
+ category: [...data.article_category.map((c) => c.category_name), ...data.article_tag.map((t) => t.tag_name)],
+ };
+ })
+ )
+ );
+
+ ctx.state.data = {
+ title: 'UNTAG',
+ link: rootUrl,
+ item: items,
+ };
+};