feat(route): add wallhaven (#9021)

* Feat(route): add wallhaven

* Fix(route): merge #9022

* Fix(docs): Update docs/en/picture.md

Co-authored-by: Tony <TonyRL@users.noreply.github.com>

* Fix(docs): Update docs/picture.md

Co-authored-by: Tony <TonyRL@users.noreply.github.com>

Co-authored-by: Tony <TonyRL@users.noreply.github.com>
This commit is contained in:
Fatpandac 2022-02-08 20:21:15 +08:00 committed by GitHub
parent 7bcb65ea25
commit 64f26bdda7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 188 additions and 0 deletions

View File

@ -196,6 +196,42 @@ For example:
<RouteEn author="MegrezZhu" example="/tits-guru/category/bikini" path="/tits-guru/category/:type" :paramsDesc="['Category, see [here](https://tits-guru.com/categories) for details']"/>
## wallhaven
::: tip Tip
When parameter **Need Details** is set to `true` `yes` `t` `y`, RSS will add the title, uploader, upload time, and category information of each image, which can support the filtering function of RSS reader.
However, the number of requests to the site increases a lot when it is turned on, which causes the site to return `Response code 429 (Too Many Requests)`. So you need to specify a smaller `limit` parameter, i.e. add `?limit=<the number of posts for a request>` after the route, here is an example.
For example [Latest Wallpapers](https://wallhaven.cc/latest), the route turning on **Need Details** is [/wallhaven/latest/true](https://rsshub.app/wallhaven/latest/true), and then specify a smaller `limit`. We can get [/wallhaven/latest/true?limit=5](https://rsshub.app/wallhaven/latest/true?limit=5).
:::
### Category
<RouteEn author="nczitzk Fatpandac" example="/wallhaven/latest" path="/wallhaven/:category?/:needDetails?" :paramsDesc="['Category, see below, Latest by default', 'Need Details, `true/yes` as yes, no by default']">
| Latest | Hot | Toplist | Random |
| ------ | --- | ------- | ------ |
| latest | hot | toplist | random |
</RouteEn>
### Search
<RouteEn author="nczitzk Fatpandac" example="/wallhaven/search/categories=110&purity=110&sorting=date_added&order=desc" path="/wallhaven/search/:filter?/:needDetails?" :paramsDesc="['Filter, empty by default', 'Need Details, `true`/`yes` as yes, no by default']">
::: tip Tip
Subscribe pages starting with `https://wallhaven.cc/search`, fill the text after `?` as `filter` in the route. The following is an example:
The text after `?` is `q=id%3A711&sorting=random&ref=fp&seed=8g0dgd` for [Wallpaper Search: #landscape - wallhaven.cc](https://wallhaven.cc/search?q=id%3A711&sorting=random&ref=fp&seed=8g0dgd), so the route is [/wallhaven/q=id%3A711&sorting=random&ref=fp&seed=8g0dgd](https://rsshub.app/wallhaven/q=id%3A711&sorting=random&ref=fp&seed=8g0dgd)
:::
</RouteEn>
## yande.re
::: tip

View File

@ -358,6 +358,42 @@ R18 显示
<Route author="MegrezZhu" example="/tits-guru/category/bikini" path="/tits-guru/category/:type" :paramsDesc="['指定类别,详见[这里](https://tits-guru.com/categories)']"/>
## wallhaven
::: tip 提示
参数 **需要图片信息** 设置为 `true` `yes` `t` `y` 等值后RSS 会携带各图片的标题、上传者、上传时间、分类信息,可支持 RSS 阅读器的筛选功能。
但开启后对该网站请求次数大量增多,从而导致网站返回 `Response code 429 (Too Many Requests)`。所以需要指定更小的 `limit` 参数值,即在路由后添加 `?limit=<单次请求获取数目>`,下面是一个例子:
如 [Latest Wallpapers](https://wallhaven.cc/latest),开启 **需要图片信息** 后的路由为 [/wallhaven/latest/true](https://rsshub.app/wallhaven/latest/true),此时再指定更小的 `limit` 参数值,即 [/wallhaven/latest/true?limit=5](https://rsshub.app/wallhaven/latest/true?limit=5)
:::
### 分类
<Route author="nczitzk Fatpandac" example="/wallhaven/latest" path="/wallhaven/:category?/:needDetails?" :paramsDesc="['分类,见下表,默认为 Latest', '需要图片信息,填写 true/yes 表示需要,默认不需要']">
| Latest | Hot | Toplist | Random |
| ------ | --- | ------- | ------ |
| latest | hot | toplist | random |
</Route>
### 搜索
<Route author="nczitzk Fatpandac" example="/wallhaven/search/q=id%3A711&sorting=random&ref=fp&seed=8g0dgd" path="/wallhaven/search/:filter?/:needDetails?" :paramsDesc="['过滤器,默认为空', '需要图片信息,填写 `true`/`yes` 表示需要,默认不需要']">
::: tip 提示
订阅以 `https://wallhaven.cc/search` 起始的页面,将 `?` 后的字段作为 `filter` 填写入路由。下面是一个例子:
如 [Wallpaper Search: #landscape - wallhaven.cc](https://wallhaven.cc/search?q=id%3A711&sorting=random&ref=fp&seed=8g0dgd),中 `?` 后的字段为 `q=id%3A711&sorting=random&ref=fp&seed=8g0dgd`,所以可以得到路由是 [/wallhaven/search/q=id%3A711&sorting=random&ref=fp&seed=8g0dgd](https://rsshub.app/wallhaven/search/q=id%3A711&sorting=random&ref=fp&seed=8g0dgd)
:::
</Route>
## Wallpaperhub
<Route author="nczitzk" example="/wallpaperhub" path="/wallpaperhub" />

55
lib/v2/wallhaven/index.js Normal file
View File

@ -0,0 +1,55 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const { parseDate } = require('@/utils/parse-date');
const rootUrl = 'https://wallhaven.cc';
module.exports = async (ctx) => {
const filter = ctx.params.filter ?? 'latest';
const needDetails = /t|y/i.test(ctx.params.needDetails ?? 'false');
const url = `${rootUrl}/${filter.indexOf('=') > 0 ? `search?${filter.replace(/page=\d+/g, 'page=1')}` : filter}`;
const response = await got.get(url);
const $ = cheerio.load(response.data);
let items = $('li > figure.thumb')
.slice(0, ctx.query.limit ? parseInt(ctx.query.limit) : 24)
.map((_, item) => ({
title: $(item).find('img.lazyload').attr('data-src').split('/').pop(),
description: $(item)
.html()
.match(/<img.*?>/)[0],
link: $(item).find('a.preview').attr('href'),
}))
.get();
if (needDetails) {
items = await Promise.all(
items.map((item) =>
ctx.cache.tryGet(item.link, async () => {
const detailResponse = await got({
method: 'get',
url: item.link,
});
const content = cheerio.load(detailResponse.data);
item.title = content('meta[name="title"]').attr('content');
item.author = content('.username').text();
item.pubDate = parseDate(content('time').attr('datetime'));
item.category = content('.tagname')
.toArray()
.map((tag) => content(tag).text());
item.description = content('div.scrollbox').html();
return item;
})
)
);
}
ctx.state.data = {
title: $('title').text(),
link: url,
item: items,
};
};

View File

@ -0,0 +1,4 @@
module.exports = {
'/search/:filter?/:needDetails?': ['nczitzk', 'Fatpandac'],
'/:filter?/:needDetails?': ['nczitzk', 'Fatpandac'],
};

53
lib/v2/wallhaven/radar.js Normal file
View File

@ -0,0 +1,53 @@
module.exports = {
'wallhaven.cc': {
_name: 'wallhaven',
'.': [
{
title: 'Latest',
docs: 'https://docs.rsshub.app/picture.html#wallhaven-zhu-zhu-ti',
source: ['/:category', '/'],
target: (params) => {
if (params.category === 'latest') {
return '/wallhaven/latest';
}
},
},
{
title: 'Hot',
docs: 'https://docs.rsshub.app/picture.html#wallhaven-zhu-zhu-ti',
source: ['/:category', '/'],
target: (params) => {
if (params.category === 'hot') {
return '/wallhaven/hot';
}
},
},
{
title: 'TopList',
docs: 'https://docs.rsshub.app/picture.html#wallhaven-zhu-zhu-ti',
source: ['/:category', '/'],
target: (params) => {
if (params.category === 'toplist') {
return '/wallhaven/toplist';
}
},
},
{
title: 'Random',
docs: 'https://docs.rsshub.app/picture.html#wallhaven-zhu-zhu-ti',
source: ['/:category', '/'],
target: (params) => {
if (params.category === 'random') {
return '/wallhaven/random';
}
},
},
{
title: 'Search',
docs: 'https://docs.rsshub.app/picture.html#wallhaven-sou-xiao-sou-shao-suo',
source: ['/'],
target: '/wallhaven/search/:filter?/:needDetails?',
},
],
},
};

View File

@ -0,0 +1,4 @@
module.exports = function (router) {
router.get('/search/:filter?/:needDetails?', require('./index'));
router.get('/:filter?/:needDetails?', require('./index'));
};