diff --git a/docs/en/picture.md b/docs/en/picture.md
index 370d579c7e..1c29173078 100644
--- a/docs/en/picture.md
+++ b/docs/en/picture.md
@@ -36,6 +36,22 @@ pageClass: routes
+## BabeHub
+
+### Category
+
+
+
+| Home | Most Viewed | Picture Archive | Video Archive |
+| - | - | - | - |
+| | most-viewed | picture | video |
+
+
+
+### Search
+
+
+
## Bing Wallpaper
### Daily Wallpaper
diff --git a/docs/picture.md b/docs/picture.md
index f4e124c8bc..0a1b043790 100644
--- a/docs/picture.md
+++ b/docs/picture.md
@@ -46,6 +46,22 @@ pageClass: routes
+## BabeHub
+
+### 分类
+
+
+
+| Home | Most Viewed | Picture Archive | Video Archive |
+| ---- | ----------- | --------------- | ------------- |
+| | most-viewed | picture | video |
+
+
+
+### 搜索关键字
+
+
+
## Bing 壁纸
### 每日壁纸
diff --git a/lib/router.js b/lib/router.js
index d5182b6786..c7614f8eec 100644
--- a/lib/router.js
+++ b/lib/router.js
@@ -3936,6 +3936,10 @@ router.get('/tianyancha/hot', require('./routes/tianyancha/hot'));
// King Arthur
router.get('/kingarthur/:type', require('./routes/kingarthur/index'));
+// BabeHub
+router.get('/babehub/search/:keyword?', require('./routes/babehub/search'));
+router.get('/babehub/:category?', require('./routes/babehub/index'));
+
// 深圳新闻网
router.get('/sznews/ranking', require('./routes/sznews/ranking'));
diff --git a/lib/routes/babehub/index.js b/lib/routes/babehub/index.js
new file mode 100644
index 0000000000..d145a3f441
--- /dev/null
+++ b/lib/routes/babehub/index.js
@@ -0,0 +1,30 @@
+const utils = require('./utils');
+
+const categories = {
+ 'most-viewed': {
+ url: 'most-viewed',
+ title: 'Most Viewed',
+ },
+ picture: {
+ url: 'picture-archive',
+ title: 'Pictures',
+ },
+ video: {
+ url: 'video-archive',
+ title: 'Videos',
+ },
+};
+
+module.exports = async (ctx) => {
+ const category = ctx.params.category || '';
+ const title = `${category ? `${categories[category].title} - ` : ''}BabeHub`;
+
+ const currentUrl = `${utils.rootUrl}/${category ? categories[category].url : ''}`;
+
+ ctx.state.data = {
+ title,
+ link: currentUrl,
+ itunes_author: title,
+ item: await utils.fetch(ctx.cache, currentUrl),
+ };
+};
diff --git a/lib/routes/babehub/search.js b/lib/routes/babehub/search.js
new file mode 100644
index 0000000000..335c30c5f5
--- /dev/null
+++ b/lib/routes/babehub/search.js
@@ -0,0 +1,15 @@
+const utils = require('./utils');
+
+module.exports = async (ctx) => {
+ const keyword = ctx.params.keyword || '';
+ const title = `${keyword ? `Search ${keyword} - ` : ''}BabeHub`;
+
+ const currentUrl = `${utils.rootUrl}/${keyword ? `?s=${keyword}` : ''}`;
+
+ ctx.state.data = {
+ title,
+ link: currentUrl,
+ itunes_author: title,
+ item: await utils.fetch(ctx.cache, currentUrl),
+ };
+};
diff --git a/lib/routes/babehub/utils.js b/lib/routes/babehub/utils.js
new file mode 100644
index 0000000000..99c49a7889
--- /dev/null
+++ b/lib/routes/babehub/utils.js
@@ -0,0 +1,72 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+
+const rootUrl = 'https://www.babehub.com';
+
+const fetch = async (cache, currentUrl) => {
+ const response = await got({
+ method: 'get',
+ url: currentUrl,
+ });
+
+ const $ = cheerio.load(response.data);
+
+ const list = $('.gallery-d li')
+ .slice(0, 50)
+ .map((_, item) => {
+ item = $(item).children('a').eq(0);
+ const image = item.find('img').eq(0);
+ const date = item.find('.date').text();
+
+ return {
+ link: item.attr('href'),
+ title: item.attr('title') || image.attr('alt'),
+ itunes_item_image: image.attr('src'),
+ pubDate: (date ? new Date(date.replace(/st|nd|rd|th/g, '')) : new Date()).toUTCString(),
+ };
+ })
+ .get();
+
+ const items = await Promise.all(
+ list.map(
+ async (item) =>
+ await cache.tryGet(item.link, async () => {
+ try {
+ const detailResponse = await got({
+ method: 'get',
+ url: item.link,
+ });
+ const content = cheerio.load(detailResponse.data);
+
+ const video = content('video');
+
+ item.description = '';
+
+ if (video.length > 0) {
+ const poster = detailResponse.data.match(/posterImage: "(.*)",/);
+ item.itunes_item_image = (poster ? poster[1] : video.attr('poster')) || item.itunes_item_image;
+
+ item.enclosure_type = 'video/mp4';
+ item.enclosure_url = video.children('source').attr('src');
+ item.description = `
`;
+ }
+
+ content('.gallery-e li a').each(function () {
+ item.description += `
`;
+ });
+
+ return item;
+ } catch (e) {
+ return Promise.resolve('');
+ }
+ })
+ )
+ );
+
+ return items;
+};
+
+module.exports = {
+ rootUrl,
+ fetch,
+};