diff --git a/docs/multimedia.md b/docs/multimedia.md
index b99dacbbea..c1e7ee1cda 100644
--- a/docs/multimedia.md
+++ b/docs/multimedia.md
@@ -202,6 +202,12 @@ pageClass: routes
+## 柠檬 私房歌 (ningmeng.name)
+
+### 私房歌
+
+
+
## 色花堂中文论坛
### 原创 BT 电影
diff --git a/lib/router.js b/lib/router.js
index 5016255703..01f170cc98 100644
--- a/lib/router.js
+++ b/lib/router.js
@@ -1316,6 +1316,9 @@ router.get('/dsndsht23', require('./routes/dsndsht23/index'));
// MaxNews - DotA 2
router.get('/maxnews/dota2', require('./routes/maxnews/dota2'));
+// 柠檬 - 私房歌
+router.get('/ningmeng/song', require('./routes/ningmeng/song'));
+
// 数英网最新文章
router.get('/digitaling/index', require('./routes/digitaling/index'));
diff --git a/lib/routes/ningmeng/song.js b/lib/routes/ningmeng/song.js
new file mode 100644
index 0000000000..6eef99c47e
--- /dev/null
+++ b/lib/routes/ningmeng/song.js
@@ -0,0 +1,77 @@
+const axios = require('@/utils/axios');
+const cheerio = require('cheerio');
+
+const sourceTimezoneOffset = -8;
+module.exports = async (ctx) => {
+ const url = 'http://www.ningmeng.name/archives/category/%E7%A7%81%E6%88%BF%E6%AD%8C';
+ const res = await axios.get(url);
+ const $$ = cheerio.load(res.data);
+ const postUrls = $$('.site-main .posts-wrapper .grid-item a.u-permalink')
+ .slice(0, 3)
+ .map((i, el) => $$(el).attr('href'))
+ .get();
+
+ const postItemGroups = await Promise.all(
+ postUrls.map(async (postUrl) => {
+ const cache = await ctx.cache.get(postUrl);
+ if (cache) {
+ return JSON.parse(cache);
+ }
+
+ const postRes = await axios.get(postUrl);
+ const $ = cheerio.load(postRes.data);
+
+ let time = $('.iconfont.icon-shijian + span.count').text();
+ time = time ? new Date(time) : new Date();
+ time.setTime(time.getTime() + (sourceTimezoneOffset - time.getTimezoneOffset() / 60) * 60 * 60 * 1000);
+ const pubDate = time.toUTCString();
+
+ const content = $('.entry-content');
+
+ const mp3s = content.find('.karma-by-kadar__simple-player');
+ const mp3Urls = mp3s.map((i, el) => $(el).attr('data-src')).get();
+
+ const images = content.find('img');
+ const imageUrls = images.map((i, el) => $(el).attr('src')).get();
+
+ const playerTextRe = /\n*play_circle_filledpause_circle_filledvolume_downvolume_upvolume_off\n*/g;
+ const songSplitterRe = /—+.+—+/g;
+ const texts = content
+ .text()
+ .replace(songSplitterRe, '')
+ .split(playerTextRe)
+ .map((p) => p.trim().split(/\n+/));
+
+ const out = mp3Urls.map((mp3Url, i) => {
+ const ss = mp3Url.split('/');
+ const filename = ss[ss.length - 1].split('.')[0];
+ const [title, artist] = filename.split('-');
+ const description = [`
`, `
${texts[i][0]}
`, `${texts[i][1]}
`].join();
+
+ return {
+ title: unescape(title).trim(),
+ author: unescape(artist).trim(),
+ link: mp3Url,
+ guid: mp3Url,
+ description,
+ pubDate,
+ };
+ });
+
+ ctx.cache.set(postUrl, JSON.stringify(out));
+
+ return out;
+ })
+ );
+
+ let items = [];
+ postItemGroups.forEach((group) => {
+ items = items.concat(group);
+ });
+
+ ctx.state.data = {
+ title: '柠檬私房歌',
+ link: 'http://www.ningmeng.name',
+ item: items,
+ };
+};