diff --git a/docs/en/picture.md b/docs/en/picture.md
index f41db2004294e8..370d579c7ef835 100644
--- a/docs/en/picture.md
+++ b/docs/en/picture.md
@@ -54,6 +54,32 @@ pageClass: routes
+## Elite Babes
+
+### Home
+
+
+
+| Home | Hot | Popular | Recent |
+| ---- | --- | ------- | ------ |
+| | hot | popular | recent |
+
+
+
+### Videos
+
+
+
+| Popular | Recent |
+| ------- | ------ |
+| popular | recent |
+
+
+
+### Search
+
+
+
## GoComics Comic Strips
diff --git a/docs/picture.md b/docs/picture.md
index bef5516e4ef224..f4e124c8bc3dd9 100644
--- a/docs/picture.md
+++ b/docs/picture.md
@@ -78,6 +78,32 @@ pageClass: routes
+## Elite Babes
+
+### Home
+
+
+
+| Home | Hot | Popular | Recent |
+| ---- | --- | ------- | ------ |
+| | hot | popular | recent |
+
+
+
+### Videos
+
+
+
+| Popular | Recent |
+| ------- | ------ |
+| popular | recent |
+
+
+
+### Search
+
+
+
## Fantia
### 搜索
diff --git a/lib/router.js b/lib/router.js
index 666bd588965c9d..5cc4b92af5f8ce 100644
--- a/lib/router.js
+++ b/lib/router.js
@@ -3978,6 +3978,11 @@ router.get('/iyiou', require('./routes/iyiou'));
// 香港商报
router.get('/hkcd/pdf', require('./routes/hkcd/pdf'));
+// Elite Babes
+router.get('/elitebabes/videos/:sort?', require('./routes/elitebabes/videos'));
+router.get('/elitebabes/search/:keyword?', require('./routes/elitebabes/search'));
+router.get('/elitebabes/:category?', require('./routes/elitebabes/index'));
+
// Trakt.tv
router.get('/trakt/collection/:username/:type?', require('./routes/trakt/collection'));
diff --git a/lib/routes/elitebabes/index.js b/lib/routes/elitebabes/index.js
new file mode 100644
index 00000000000000..83118a3dd7d56b
--- /dev/null
+++ b/lib/routes/elitebabes/index.js
@@ -0,0 +1,30 @@
+const utils = require('./utils');
+
+const categories = {
+ hot: {
+ url: 'trending',
+ title: 'Hot',
+ },
+ popular: {
+ url: 'most-viewed',
+ title: 'Popular',
+ },
+ recent: {
+ url: 'latest-updates',
+ title: 'Recent',
+ },
+};
+
+module.exports = async (ctx) => {
+ const category = ctx.params.category || '';
+ const title = `${category ? `${categories[category].title} - ` : ''}Elite Babes`;
+
+ 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/elitebabes/search.js b/lib/routes/elitebabes/search.js
new file mode 100644
index 00000000000000..7f782b795a9291
--- /dev/null
+++ b/lib/routes/elitebabes/search.js
@@ -0,0 +1,15 @@
+const utils = require('./utils');
+
+module.exports = async (ctx) => {
+ const keyword = ctx.params.keyword || '';
+ const title = `${keyword ? `Search ${keyword} - ` : ''}Elite Babes`;
+
+ 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/elitebabes/utils.js b/lib/routes/elitebabes/utils.js
new file mode 100644
index 00000000000000..0e00b88099608e
--- /dev/null
+++ b/lib/routes/elitebabes/utils.js
@@ -0,0 +1,89 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+
+const rootUrl = 'https://www.elitebabes.com';
+
+const fetch = async (cache, currentUrl) => {
+ const response = await got({
+ method: 'get',
+ url: currentUrl,
+ });
+
+ const $ = cheerio.load(response.data);
+
+ $('.clip-a, .displayblock').remove();
+
+ const list = $('.gallery-a li')
+ .slice(0, 50)
+ .map((_, item) => {
+ item = $(item).children('a').eq(0);
+ const image = item.find('img').eq(0);
+
+ return {
+ link: item.attr('href'),
+ title: item.attr('title') || image.attr('alt'),
+ itunes_item_image: image.attr('src').replace('_200', '_400'),
+ pubDate: (item.next()[0] ? new Date(item.next().text()) : 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);
+
+ content('input, .link-btn, .m-pagination').remove();
+ content('.mobile-hide, .wide-hide').remove();
+
+ if (item.link.indexOf(`${rootUrl}/model/`) === 0) {
+ item.author = content('.fn').text();
+ item.description = content('#content').html();
+ return item;
+ }
+
+ const authors = [];
+ 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('.link-btn h2 a').each(function () {
+ authors.push(content(this).text());
+ });
+
+ item.author = authors.join(', ');
+
+ content('.list-justified2 li a').each(function () {
+ item.description += ``;
+ });
+
+ return item;
+ } catch (e) {
+ return Promise.resolve('');
+ }
+ })
+ )
+ );
+
+ return items;
+};
+
+module.exports = {
+ rootUrl,
+ fetch,
+};
diff --git a/lib/routes/elitebabes/videos.js b/lib/routes/elitebabes/videos.js
new file mode 100644
index 00000000000000..a5d14d59d92218
--- /dev/null
+++ b/lib/routes/elitebabes/videos.js
@@ -0,0 +1,26 @@
+const utils = require('./utils');
+
+const sorts = {
+ popular: {
+ url: '',
+ title: 'Popular',
+ },
+ recent: {
+ url: 'latest',
+ title: 'Recent',
+ },
+};
+
+module.exports = async (ctx) => {
+ const sort = ctx.params.sort || '';
+ const title = `${sort ? sorts[sort].title : 'Popular'} videos - Elite Babes`;
+
+ const currentUrl = `${utils.rootUrl}/videos${sort ? `?sort=${sorts[sort].url}` : ''}`;
+
+ ctx.state.data = {
+ title,
+ link: currentUrl,
+ itunes_author: title,
+ item: await utils.fetch(ctx.cache, currentUrl),
+ };
+};