diff --git a/docs/other.md b/docs/other.md
index 8525cd66d4..89e75c56d3 100644
--- a/docs/other.md
+++ b/docs/other.md
@@ -74,6 +74,12 @@ pageClass: routes
+## 单向空间
+
+### 单读
+
+
+
## DHL
### DHL 国际快递包裹追踪
diff --git a/lib/router.js b/lib/router.js
index 064c3762bd..c96bec2262 100644
--- a/lib/router.js
+++ b/lib/router.js
@@ -1632,4 +1632,7 @@ router.get('/hanime/video', require('./routes/hanime/video'));
router.get('/gouhuo/news/:category', require('./routes/gouhuo'));
router.get('/gouhuo/strategy', require('./routes/gouhuo/strategy'));
+// 单向空间
+router.get('/owspace/read', require('./routes/owspace/read'));
+
module.exports = router;
diff --git a/lib/routes/owspace/read.js b/lib/routes/owspace/read.js
new file mode 100644
index 0000000000..cfe406a60d
--- /dev/null
+++ b/lib/routes/owspace/read.js
@@ -0,0 +1,92 @@
+const got = require('@/utils/got');
+const md5 = require('@/utils/md5');
+const qs = require('querystring');
+const cheerio = require('cheerio');
+
+const secret = 'fk4iy@98(*Y98fh-^o)re+wg=';
+const signQuery = (query) => {
+ query.sign = md5(['apiname=', query.a, 'device_id=', query.device_id, 'time=', query.time, secret].join(''));
+};
+
+const generateFullText = async (item) => {
+ const fullTextResponse = await got.get(item.html5);
+ const $ = cheerio.load(fullTextResponse.data);
+
+ const content = $('#singleArticle');
+ const describe = $('.articleTit>.describe');
+
+ let intro = '';
+
+ if (item.thumbnail) {
+ intro += `

`;
+ }
+
+ if (item.excerpt) {
+ intro += '' + item.excerpt + '
';
+ }
+
+ if (describe.length > 0) {
+ intro += '' + describe.html() + '
';
+ }
+
+ content.find('.articleTit').remove();
+
+ return intro + content.html();
+};
+
+module.exports = async (ctx) => {
+ const queryData = {
+ c: 'api2',
+ a: 'getList',
+ p: '1',
+ model: '0',
+ client: 'android',
+ version: '1.6.3',
+ time: Math.round(Date.now() / 1000),
+ device_id: 'null',
+ show_sdv: '0',
+ };
+
+ signQuery(queryData);
+ const response = await got({
+ method: 'get',
+ url: 'http://static.owspace.com/',
+ query: qs.stringify(queryData),
+ headers: {
+ 'User-Agent': 'com.onewaystreet.weread/14',
+ },
+ });
+
+ if (!response.data.status || response.data.status !== 'ok') {
+ throw response.data.msg ? 'api error: ' + response.data.msg : 'api error';
+ }
+
+ const itemArray = await Promise.all(
+ response.data.datas
+ .filter((item) => item.model !== 5)
+ .map(async (item) => {
+ const url = item.html5;
+ const cache = await ctx.cache.get(url);
+ if (cache) {
+ return Promise.resolve(JSON.parse(cache));
+ }
+
+ const result = {
+ title: item.title.replace('\r\n', ''),
+ link: item.html5,
+ description: await generateFullText(item),
+ pubDate: new Date(Number(item.create_time) * 1000).toUTCString(),
+ author: item.author,
+ };
+
+ ctx.cache.set(url, JSON.stringify(result));
+ return Promise.resolve(result);
+ })
+ );
+
+ ctx.state.data = {
+ title: '单读',
+ link: 'http://www.owspace.com/read.html',
+ item: itemArray,
+ };
+};