diff --git a/docs/reading.md b/docs/reading.md
index 81f845789..c106fd85a 100644
--- a/docs/reading.md
+++ b/docs/reading.md
@@ -28,6 +28,45 @@ pageClass: routes
+## SoBooks
+
+### 首页
+
+
+
+| 分类 | 分类名 |
+| -------- | ---------------- |
+| 小说文学 | xiaoshuowenxue |
+| 历史传记 | lishizhuanji |
+| 人文社科 | renwensheke |
+| 励志成功 | lizhichenggong |
+| 经济管理 | jingjiguanli |
+| 学习教育 | xuexijiaoyu |
+| 生活时尚 | shenghuoshishang |
+| 英文原版 | yingwenyuanban |
+
+
+
+### 标签
+
+
+
+热门标签
+
+| 小说 | 文学 | 历史 | 日本 | 科普 | 管理 | 推理 | 社会 | 经济 |
+| ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ------ |
+| 传记 | 美国 | 悬疑 | 哲学 | 心理 | 商业 | 金融 | 思维 | 经典 |
+| 随笔 | 投资 | 文化 | 励志 | 科幻 | 成长 | 中国 | 英国 | 政治 |
+| 漫画 | 纪实 | 艺术 | 科学 | 生活 | 职场 | 散文 | 法国 | 互联网 |
+| 营销 | 奇幻 | 二战 | 股票 | 女性 | 德国 | 学习 | 战争 | 创业 |
+| 绘本 | 名著 | 爱情 | 军事 | 理财 | 教育 | 世界 | 人物 | 沟通 |
+
+
+
+## 归档
+
+
+
## UU 看书
### 小说更新
diff --git a/lib/router.js b/lib/router.js
index 926c7a0bf..927cdf120 100644
--- a/lib/router.js
+++ b/lib/router.js
@@ -3512,6 +3512,11 @@ router.get('/uisdc/news', require('./routes/uisdc/news'));
router.get('/uisdc/zt/:title?', require('./routes/uisdc/zt'));
router.get('/uisdc/topic/:title?/:sort?', require('./routes/uisdc/topic'));
+// SoBooks
+router.get('/sobooks/tag/:id?', require('./routes/sobooks/tag'));
+router.get('/sobooks/date/:date?', require('./routes/sobooks/date'));
+router.get('/sobooks/:category?', require('./routes/sobooks/index'));
+
// Zhimap 知识导图社区
router.get('/zhimap/:categoryUuid?/:recommend?', require('./routes/zhimap/index'));
diff --git a/lib/routes/sobooks/date.js b/lib/routes/sobooks/date.js
new file mode 100644
index 000000000..d793ab60c
--- /dev/null
+++ b/lib/routes/sobooks/date.js
@@ -0,0 +1,7 @@
+const utils = require('./utils');
+
+module.exports = async (ctx) => {
+ const date = ctx.params.date || `${new Date().getFullYear()}/${new Date().getMonth()}`;
+
+ ctx.state.data = await utils(ctx, `books/date/${date.replace('-', '/')}`);
+};
diff --git a/lib/routes/sobooks/index.js b/lib/routes/sobooks/index.js
new file mode 100644
index 000000000..19548f498
--- /dev/null
+++ b/lib/routes/sobooks/index.js
@@ -0,0 +1,7 @@
+const utils = require('./utils');
+
+module.exports = async (ctx) => {
+ const category = ctx.params.category || '';
+
+ ctx.state.data = await utils(ctx, category);
+};
diff --git a/lib/routes/sobooks/tag.js b/lib/routes/sobooks/tag.js
new file mode 100644
index 000000000..27ab3bdce
--- /dev/null
+++ b/lib/routes/sobooks/tag.js
@@ -0,0 +1,7 @@
+const utils = require('./utils');
+
+module.exports = async (ctx) => {
+ const id = ctx.params.id || '小说';
+
+ ctx.state.data = await utils(ctx, `books/tag/${id}`);
+};
diff --git a/lib/routes/sobooks/utils.js b/lib/routes/sobooks/utils.js
new file mode 100644
index 000000000..4d016a432
--- /dev/null
+++ b/lib/routes/sobooks/utils.js
@@ -0,0 +1,50 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+
+module.exports = async (ctx, currentUrl) => {
+ const rootUrl = 'https://www.sobooks.cc';
+ currentUrl = `${rootUrl}/${currentUrl}`;
+ const response = await got({
+ method: 'get',
+ url: currentUrl,
+ });
+
+ const $ = cheerio.load(response.data);
+
+ const list = $('.card-item h3 a')
+ .slice(0, 15)
+ .map((_, item) => {
+ item = $(item);
+ return {
+ title: item.text(),
+ link: item.attr('href'),
+ };
+ })
+ .get();
+
+ const items = await Promise.all(
+ list.map(
+ async (item) =>
+ await ctx.cache.tryGet(item.link, async () => {
+ const detailResponse = await got({
+ method: 'get',
+ url: item.link,
+ });
+ const content = cheerio.load(detailResponse.data);
+
+ content('.e-secret, .article-social').remove();
+
+ item.description = content('.article-content').html();
+ item.pubDate = new Date(content('.bookinfo ul li').eq(4).text().replace('时间:', '')).toUTCString();
+
+ return item;
+ })
+ )
+ );
+
+ return {
+ title: ($('.archive-header h1').text() ? $('.archive-header h1').text() + ' - ' : '') + 'SoBooks',
+ link: currentUrl,
+ item: items,
+ };
+};