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 }}

+