diff --git a/docs/anime.md b/docs/anime.md
index 18ebf64f29..80a99d9676 100644
--- a/docs/anime.md
+++ b/docs/anime.md
@@ -399,6 +399,40 @@ Sources
+## 俺の 3D エロ動画 (oreno3d)
+
+::: tip 提示
+
+可配合其他 RSS 解析库 (如`Python`的`feedparser`库) 实现视频的更新检测以及自动下载
+
+:::
+
+### 关键词搜索
+
+
+
+| 高評価 | 急上昇 | 新着 | 人気 |
+| --------- | --- | ------ | ---------- |
+| favorites | hot | latest | popularity |
+
+
+
+### 角色搜索
+
+
+
+### 作者搜索
+
+
+
+### 标签搜索
+
+
+
+### 原作搜索
+
+
+
## 包子漫画
#### 订阅漫画
diff --git a/docs/en/anime.md b/docs/en/anime.md
index 2b50cebb8a..1120f83f91 100644
--- a/docs/en/anime.md
+++ b/docs/en/anime.md
@@ -105,3 +105,37 @@ For example:
+
+## 俺の3Dエロ動画(oreno3d)
+
+::: tip Tip
+
+You can use some RSS parsing libraries (like `feedpraser` in `Python`) to receive the video update messages and download them automatically
+
+:::
+
+### Keyword Search
+
+
+
+| favorites | hot | latest | popularity |
+| --------- | ------ | ------ | ---------- |
+| favorites | hot | latest | popularity |
+
+
+
+### Character Search
+
+
+
+### Author Search
+
+
+
+### Tags Search
+
+
+
+### Origins Search
+
+
diff --git a/lib/v2/oreno3d/get_sec_page_data.js b/lib/v2/oreno3d/get_sec_page_data.js
new file mode 100644
index 0000000000..ac023bd779
--- /dev/null
+++ b/lib/v2/oreno3d/get_sec_page_data.js
@@ -0,0 +1,69 @@
+const got = require('@/utils/got');
+const cheerio = require('cheerio');
+
+const rootUrl = 'https://oreno3d.com';
+
+async function sync_detail(link) {
+ // 主选择器
+ const sec_page_selector = "article.g-main-video-article";
+ // 分条选择器
+ const raw_pic_selector = "header > figure.video-figure > a ";
+ const video_name_selector = "header > h1.video-h1 ";
+ const author_selector = "section:nth-child(4) > a > div.video-center";
+ const origins_selector = "section:nth-child(5) > a > div.video-center";
+ const characters_selector = "section:nth-child(6) > a > div.video-center";
+ const tags_selector = "section:nth-child(7) > ul > li > a div.tag-text";// 未修复
+ const desc_selector = "section blockquote.video-information-comment";
+ const iwara_link_selector = "header > figure.video-figure > a";
+ // 下载
+ const response = await got(link);
+ const $ = cheerio.load(response.data);
+ // 创建列表
+ const tags = [];
+ const authors = [];
+ const origins = [];
+ const characters = [];
+ // 筛选
+ const raw_pic_link = rootUrl + $(raw_pic_selector).find('img').attr('src');
+ const video_name = $(video_name_selector).text();
+ // 存为列表
+ $(sec_page_selector).find(author_selector).each(function(i) {
+ authors[i] = $(this).text();
+ authors[i].replace(" ", "");// 去空格
+ authors[i].trim();// 去首尾空格
+ });
+ $(sec_page_selector).find(origins_selector).each(function(i) {
+ origins[i] = $(this).text();
+ origins[i].replace(" ", "");
+ origins[i].trim();
+ });
+ $(sec_page_selector).find(characters_selector).each(function(i) {
+ characters[i] = $(this).text();
+ characters[i].replace(" ", "");
+ characters[i].trim();
+ });
+ $(sec_page_selector).find(tags_selector).each(function(i) {
+ tags[i] = $(this).text();
+ tags[i].replace(" ", "");
+ tags[i].trim();
+ });
+ // 筛选
+ const desc = $(sec_page_selector).find(desc_selector).text();
+ const iwara_link = $(iwara_link_selector).attr('href');
+ // 打包
+ return {
+ raw_pic_link,
+ video_name,
+ authors:authors.join(" "),
+ origins:origins.join(" "),
+ characters:characters.join(" "),
+ tags:tags.join(" "),
+ desc,
+ iwara_link,
+ oreno3d_link:link
+
+ };
+}
+
+
+module.exports = sync_detail;
\ No newline at end of file
diff --git a/lib/v2/oreno3d/main.js b/lib/v2/oreno3d/main.js
new file mode 100644
index 0000000000..5f5cc23985
--- /dev/null
+++ b/lib/v2/oreno3d/main.js
@@ -0,0 +1,94 @@
+const got = require('@/utils/got');
+const { art } = require('@/utils/render');
+const path = require('path');
+const cheerio = require('cheerio');
+const get_sec_page_data = require('./get_sec_page_data');
+
+const rootUrl = 'https://oreno3d.com';
+
+const sortRename = {
+ favorites: '高評価',
+ hot: '急上昇',
+ latest: '新着',
+ popularity: '人気',
+};
+
+function get_user_url(rootUrl, ctx, sort) {
+ let userUrl = '';
+ // 判断userurl获取位置
+ if (ctx.params.keyword) {
+ const keyword = ctx.params.keyword;
+ userUrl = `${rootUrl}/search?sort=${sort}&keyword=${keyword}`;
+ } else if (ctx.params.characterid) {
+ const characterid = ctx.params.characterid;
+ userUrl = `${rootUrl}/characters/${characterid}?sort=${sort}`;
+ } else if (ctx.params.authorid) {
+ const authorid = ctx.params.authorid;
+ userUrl = `${rootUrl}/authors/${authorid}?sort=${sort}`;
+ } else if (ctx.params.tagid) {
+ const tagid = ctx.params.tagid;
+ userUrl = `${rootUrl}/tags/${tagid}?sort=${sort}`;
+ } else if (ctx.params.originid) {
+ const originid = ctx.params.originid;
+ userUrl = `${rootUrl}/origins/${originid}?sort=${sort}`;
+ }
+ return userUrl;
+}
+const selector = 'a.box';
+module.exports = async (ctx) => {
+ // 下载
+ const sort = ctx.params.sort ?? 'latest';
+ const userUrl = get_user_url(rootUrl, ctx, sort);
+ const response = await got(userUrl);
+ const $ = cheerio.load(response.data);
+ // 第一页,获取搜索主标题
+ const title = $('div.g-main-list').find('h1.main-h').text(); // 搜索标题;//第二页跳转链接
+
+ const list = $(selector);
+ const items = await Promise.all(
+ list
+ .map((_, item) => {
+ // 第一页,获取搜各视频地址
+ const link = $(item).attr('href');
+ return ctx.cache.tryGet(link, async () => {
+ // 第二页数据分析
+ const sec_data = await get_sec_page_data(link);
+ // 传递
+ const raw_pic_link = sec_data.raw_pic_link;
+ const video_name = sec_data.video_name;
+ const authors = sec_data.authors;
+ const origins = sec_data.origins;
+ const characters = sec_data.characters;
+ const tags = sec_data.tags;
+ const desc = sec_data.desc;
+ const iwara_link = sec_data.iwara_link;
+ const oreno3d_link = sec_data.oreno3d_link;
+ // 打包
+ return {
+ title: `${video_name} - ${authors}`,
+ author: authors,
+ link: oreno3d_link,
+ category: tags.split(' '),
+ description: art(path.join(__dirname, 'templates/description.art'), {
+ raw_pic_link,
+ video_name,
+ authors,
+ origins,
+ characters,
+ tags,
+ desc,
+ iwara_link,
+ oreno3d_link,
+ }),
+ };
+ });
+ })
+ .get()
+ );
+
+ ctx.state.data = {
+ title: `${title} - ${sortRename[sort]}`,
+ link: userUrl,
+ item: items,
+ };
+};
diff --git a/lib/v2/oreno3d/maintainer.js b/lib/v2/oreno3d/maintainer.js
new file mode 100644
index 0000000000..04cc6d8ba8
--- /dev/null
+++ b/lib/v2/oreno3d/maintainer.js
@@ -0,0 +1,7 @@
+module.exports = {
+ '/authors/:authorid/:sort?': ['xueli_sherryli'],
+ '/characters/:characterid/:sort?': ['xueli_sherryli'],
+ '/origins/:originid/:sort?': ['xueli_sherryli'],
+ '/search/:keyword/:sort?': ['xueli_sherryli'],
+ '/tags/:tagid/:sort?': ['xueli_sherryli'],
+};
diff --git a/lib/v2/oreno3d/radar.js b/lib/v2/oreno3d/radar.js
new file mode 100644
index 0000000000..521c500000
--- /dev/null
+++ b/lib/v2/oreno3d/radar.js
@@ -0,0 +1,52 @@
+module.exports = {
+ 'oreno3d.com': {
+ _name: '俺の3Dエロ動画',
+ '.': [
+ {
+ title: '关键词搜索',
+ docs: 'https://docs.rsshub.app/anime.htm#an-の3dエロ-dong-hua-oreno3d-guan-jian-ci-sou-suo',
+ source: ['/search'],
+ target: (_params, url) => {
+ const searchParams = new URL(url).searchParams;
+ return `/oreno3d/search/${searchParams.get('keyword')}${searchParams.has('sort') ? '/' + searchParams.get('sort') : ''}`;
+ },
+ },
+ {
+ title: '角色搜索',
+ docs: 'https://docs.rsshub.app/anime.html#an-の3dエロ-dong-hua-oreno3d-jiao-se-sou-suo',
+ source: ['/characters/:characterid'],
+ target: (params, url) => {
+ const searchParams = new URL(url).searchParams;
+ return `/oreno3d/characters/${params.characterid}${searchParams.has('sort') ? '/' + searchParams.get('sort') : ''}`;
+ },
+ },
+ {
+ title: '作者搜索',
+ docs: 'https://docs.rsshub.app/anime.html#an-の3dエロ-dong-hua-oreno3d-zuo-zhe-sou-suo',
+ source: ['/authors/:authorid'],
+ target: (params, url) => {
+ const searchParams = new URL(url).searchParams;
+ return `/oreno3d/authors/${params.authorid}${searchParams.has('sort') ? '/' + searchParams.get('sort') : ''}`;
+ },
+ },
+ {
+ title: '标签搜索',
+ docs: 'https://docs.rsshub.app/anime.html#an-の3dエロ-dong-hua-oreno3d-biao-qian-sou-suo',
+ source: ['/tags/:tagid'],
+ target: (params, url) => {
+ const searchParams = new URL(url).searchParams;
+ return `/oreno3d/tags/${params.tagid}${searchParams.has('sort') ? '/' + searchParams.get('sort') : ''}`;
+ },
+ },
+ {
+ title: '原作搜索',
+ docs: 'https://docs.rsshub.app/anime.html#an-の3dエロ-dong-hua-oreno3d-yuan-zuo-sou-suo',
+ source: ['/origins/:originid'],
+ target: (params, url) => {
+ const searchParams = new URL(url).searchParams;
+ return `/oreno3d/origins/${params.originid}${searchParams.has('sort') ? '/' + searchParams.get('sort') : ''}`;
+ },
+ },
+ ],
+ },
+};
diff --git a/lib/v2/oreno3d/router.js b/lib/v2/oreno3d/router.js
new file mode 100644
index 0000000000..ec1a39cf91
--- /dev/null
+++ b/lib/v2/oreno3d/router.js
@@ -0,0 +1,7 @@
+module.exports = function (router) {
+ router.get('/authors/:authorid/:sort?', require('./main'));
+ router.get('/characters/:characterid/:sort?', require('./main'));
+ router.get('/origins/:originid/:sort?', require('./main'));
+ router.get('/search/:keyword/:sort?', require('./main'));
+ router.get('/tags/:tagid/:sort?', require('./main'));
+};
diff --git a/lib/v2/oreno3d/templates/description.art b/lib/v2/oreno3d/templates/description.art
new file mode 100644
index 0000000000..846d7abc53
--- /dev/null
+++ b/lib/v2/oreno3d/templates/description.art
@@ -0,0 +1,13 @@
+
+
标题:{{ video_name }}
+作者:{{ authors }}
+原作:{{ origins }}
+角色:{{ characters }}
+标签:{{ tags }}
+简介:
+
+{{ desc }}
+
+iwara链接:{{ iwara_link }}
+Oreno3D链接:{{ oreno3d_link }}
+