rsshub
Version:
Make RSS Great Again!
185 lines (167 loc) • 5.94 kB
text/typescript
import { Route } from '@/types';
import cache from '@/utils/cache';
import got from '@/utils/got';
import { config } from '@/config';
import { art } from '@/utils/render';
import { parseDate } from '@/utils/parse-date';
import path from 'node:path';
import MarkdownIt from 'markdown-it';
import ConfigNotFoundError from '@/errors/types/config-not-found';
const md = MarkdownIt({
html: true,
});
export const route: Route = {
path: '/subscriptions',
categories: ['anime'],
example: '/iwara/subscriptions',
parameters: {},
features: {
requireConfig: [
{
name: 'IWARA_USERNAME',
description: '',
},
{
name: 'IWARA_PASSWORD',
description: '',
},
],
requirePuppeteer: false,
antiCrawler: false,
supportBT: false,
supportPodcast: false,
supportScihub: false,
},
radar: [
{
source: ['ecchi.iwara.tv/'],
},
],
name: 'User Subscriptions',
maintainers: ['FeCCC'],
handler,
url: 'ecchi.iwara.tv/',
description: `::: warning
This route requires username and password, therefore it's only available when self-hosting, refer to the [Deploy Guide](https://docs.rsshub.app/deploy/config#route-specific-configurations) for route-specific configurations.
:::`,
};
async function handler() {
if (!config.iwara || !config.iwara.username || !config.iwara.password) {
throw new ConfigNotFoundError('Iwara subscription RSS is disabled due to the lack of <a href="https://docs.rsshub.app/deploy/config#route-specific-configurations">relevant config</a>');
}
const rootUrl = `https://www.iwara.tv`;
const username = config.iwara.username;
const password = config.iwara.password;
// get refresh token
const refreshHeaders = await cache.tryGet(
'iwara:token',
async () => {
const loginResponse = await got({
method: 'post',
url: 'https://api.iwara.tv/user/login',
headers: {
'content-type': 'application/json',
},
body: JSON.stringify({
email: username,
password,
}),
});
return {
authorization: 'Bearer ' + loginResponse.data.token,
};
},
30 * 24 * 60 * 60,
false
);
// get subscription list
const videoSubUrl = 'https://api.iwara.tv/videos?page=0&limit=30&subscribed=true';
const imageSubUrl = 'https://api.iwara.tv/images?page=0&limit=30&subscribed=true';
// get access token
const accessResponse = await got({
method: 'post',
url: 'https://api.iwara.tv/user/token',
headers: refreshHeaders,
});
const authHeaders = {
authorization: 'Bearer ' + accessResponse.data.accessToken,
};
const videoResponse = await got({
method: 'get',
url: videoSubUrl,
headers: authHeaders,
});
const imageResponse = await got({
method: 'get',
url: imageSubUrl,
headers: authHeaders,
});
const videoList = videoResponse.data.results.map((item) => {
const img_path = item.private === true ? 'https://i.iwara.tv/image/original/' : 'https://i.iwara.tv/image/thumbnail/';
const imageUrl = item.file ? img_path + item.file.id.toString().padStart(2, '0') + '/thumbnail-' + item.thumbnail.toString().padStart(2, '0') + '.jpg' : '';
return {
title: item.title,
author: item.user.name,
link: rootUrl + '/video/' + item.id,
category: 'Video',
imageUrl,
pubDate: parseDate(item.createdAt),
private: item.private,
};
});
const imageList = imageResponse.data.results.map((item) => {
const imageUrl = item.thumbnail ? 'https://i.iwara.tv/image/thumbnail/' + item.thumbnail.id + '/' + item.thumbnail.id + '.jpg' : '';
return {
title: item.title,
author: item.user.name,
link: rootUrl + '/image/' + item.id,
category: 'Image',
imageUrl,
pubDate: parseDate(item.createdAt),
};
});
// fulltext
const list = [...videoList, ...imageList];
const items = await Promise.all(
list.map((item) =>
cache.tryGet(item.link, async () => {
let description = art(path.join(__dirname, 'templates/subscriptions.art'), {
type: item.category,
imageUrl: item.imageUrl,
});
if (item.private === true) {
description += 'private';
return {
title: item.title,
author: item.author,
link: item.link,
category: item.category,
pubDate: item.pubDate,
description,
};
}
const link = item.link.replace('www.iwara.tv', 'api.iwara.tv');
const response = await got({
method: 'get',
url: link,
headers: authHeaders,
});
const body = response.data.body ? md.render(response.data.body) : '';
description += body;
return {
title: item.title,
author: item.author,
link: item.link,
category: item.category,
pubDate: item.pubDate,
description,
};
})
)
);
return {
title: `Iwara Subscription`,
link: rootUrl,
item: items,
};
}