feat: add ConfigNotFoundError and InvalidParameterError

This commit is contained in:
DIYgod 2024-04-07 17:36:18 +08:00
parent cef1ed1eb6
commit 79fcce2729
No known key found for this signature in database
183 changed files with 423 additions and 224 deletions

View File

@ -0,0 +1,5 @@
class ConfigNotFoundError extends Error {
name = 'ConfigNotFoundError';
}
export default ConfigNotFoundError;

View File

@ -0,0 +1,5 @@
class InvalidParameterError extends Error {
name = 'InvalidParameterError';
}
export default InvalidParameterError;

View File

@ -7,6 +7,7 @@ import got from '@/utils/got';
import { art } from '@/utils/render';
import path from 'node:path';
import { config } from '@/config';
import InvalidParameterError from '@/errors/types/invalid-parameter';
const rootUrl = 'https://kyfw.12306.cn';
@ -85,7 +86,7 @@ async function handler(ctx) {
},
});
if (response.data.data === undefined || response.data.data.length === 0) {
throw new Error('没有找到相关车次,请检查参数是否正确');
throw new InvalidParameterError('没有找到相关车次,请检查参数是否正确');
}
const data = response.data.data.result;
const map = response.data.data.map;

View File

@ -4,6 +4,7 @@ import got from '@/utils/got';
import { load } from 'cheerio';
import iconv from 'iconv-lite';
import { parseDate } from '@/utils/parse-date';
import InvalidParameterError from '@/errors/types/invalid-parameter';
const rootUrl = 'https://news.163.com';
@ -119,9 +120,9 @@ async function handler(ctx) {
const cfg = config[category];
if (!cfg) {
throw new Error('Bad category. See <a href="https://docs.rsshub.app/routes/new-media#wang-yi-xin-wen-pai-hang-bang">docs</a>');
throw new InvalidParameterError('Bad category. See <a href="https://docs.rsshub.app/routes/new-media#wang-yi-xin-wen-pai-hang-bang">docs</a>');
} else if ((category !== 'whole' && type === 'click' && time === 'month') || (category === 'whole' && type === 'click' && time === 'hour') || (type === 'follow' && time === 'hour')) {
throw new Error('Bad timeRange range. See <a href="https://docs.rsshub.app/routes/new-media#wang-yi-xin-wen-pai-hang-bang">docs</a>');
throw new InvalidParameterError('Bad timeRange range. See <a href="https://docs.rsshub.app/routes/new-media#wang-yi-xin-wen-pai-hang-bang">docs</a>');
}
const currentUrl = category === 'money' ? cfg.link : `${rootUrl}${cfg.link}`;

View File

@ -1,3 +1,4 @@
import InvalidParameterError from '@/errors/types/invalid-parameter';
import { Route } from '@/types';
import cache from '@/utils/cache';
import got from '@/utils/got';
@ -43,7 +44,7 @@ export const route: Route = {
async function handler(ctx) {
if (!ctx.req.param('type')) {
throw new Error('Bad parameter. See <a href="https://docs.rsshub.app/routes/game#wang-yi-da-shen">https://docs.rsshub.app/routes/game#wang-yi-da-shen</a>');
throw new InvalidParameterError('Bad parameter. See <a href="https://docs.rsshub.app/routes/game#wang-yi-da-shen">https://docs.rsshub.app/routes/game#wang-yi-da-shen</a>');
}
const selectedType = Number.parseInt(ctx.req.param('type'));
let type;

View File

@ -8,6 +8,7 @@ import { parseDate } from '@/utils/parse-date';
import { art } from '@/utils/render';
import path from 'node:path';
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
const defaultDomain = 'jmcomic1.me';
// list of address: https://jmcomic2.bet
@ -15,7 +16,7 @@ const allowDomain = new Set(['18comic.vip', '18comic.org', 'jmcomic.me', 'jmcomi
const getRootUrl = (domain) => {
if (!config.feature.allow_user_supply_unsafe_domain && !allowDomain.has(domain)) {
throw new Error(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
throw new ConfigNotFoundError(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
}
return `https://${domain}`;

View File

@ -6,6 +6,7 @@ import timezone from '@/utils/timezone';
import { parseDate } from '@/utils/parse-date';
import iconv from 'iconv-lite';
import { isValidHost } from '@/utils/valid-host';
import InvalidParameterError from '@/errors/types/invalid-parameter';
const setCookie = function (cookieName, cookieValue, seconds, path, domain, secure) {
let expires = null;
@ -52,7 +53,7 @@ export const route: Route = {
async function handler(ctx) {
const city = ctx.req.param('city') ?? 'www';
if (!isValidHost(city)) {
throw new Error('Invalid city');
throw new InvalidParameterError('Invalid city');
}
const rootUrl = `https://${city}.19lou.com`;

View File

@ -5,6 +5,7 @@ import got from '@/utils/got';
import path from 'node:path';
import { art } from '@/utils/render';
import { parseDate } from '@/utils/parse-date';
import InvalidParameterError from '@/errors/types/invalid-parameter';
const getCategories = (tryGet) =>
tryGet('4gamers:categories', async () => {
@ -48,7 +49,7 @@ const parseItem = async (item) => {
case 'ImageGroupSection':
return renderImages(section.items);
default:
throw new Error(`Unhandled section type: ${section['@type']} on ${item.link}`);
throw new InvalidParameterError(`Unhandled section type: ${section['@type']} on ${item.link}`);
}
})
.join('')

View File

@ -10,6 +10,7 @@ import { load } from 'cheerio';
import got from '@/utils/got';
import { art } from '@/utils/render';
import { isValidHost } from '@/utils/valid-host';
import InvalidParameterError from '@/errors/types/invalid-parameter';
const cookieJar = new CookieJar();
@ -133,7 +134,7 @@ async function handler(ctx) {
const country = ctx.req.param('country') ?? 'tw';
if (!isValidHost(country) && country !== 'tw') {
throw new Error('Invalid country codes. Only "tw" is supported now.');
throw new InvalidParameterError('Invalid country codes. Only "tw" is supported now.');
}
/** @type {House[]} */

View File

@ -1,9 +1,10 @@
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
const allowDomain = new Set(['91porn.com', 'www.91porn.com', '0122.91p30.com', 'www.91zuixindizhi.com', 'w1218.91p46.com']);
const domainValidation = (domain) => {
if (!config.feature.allow_user_supply_unsafe_domain && !allowDomain.has(domain)) {
throw new Error(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
throw new ConfigNotFoundError(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
}
};

View File

@ -3,6 +3,7 @@ import cache from '@/utils/cache';
import got from '@/utils/got';
import { load } from 'cheerio';
import { parseDate } from '@/utils/parse-date';
import InvalidParameterError from '@/errors/types/invalid-parameter';
const baseUrl = 'https://www.acfun.cn';
const categoryMap = {
@ -66,13 +67,13 @@ export const route: Route = {
async function handler(ctx) {
const { categoryId, sortType = 'createTime', timeRange = 'all' } = ctx.req.param();
if (!categoryMap[categoryId]) {
throw new Error(`Invalid category Id: ${categoryId}`);
throw new InvalidParameterError(`Invalid category Id: ${categoryId}`);
}
if (!sortTypeEnum.has(sortType)) {
throw new Error(`Invalid sort type: ${sortType}`);
throw new InvalidParameterError(`Invalid sort type: ${sortType}`);
}
if (!timeRangeEnum.has(timeRange)) {
throw new Error(`Invalid time range: ${timeRange}`);
throw new InvalidParameterError(`Invalid time range: ${timeRange}`);
}
const url = `${baseUrl}/v/list${categoryId}/index.htm`;

View File

@ -4,6 +4,7 @@ import { puppeteerGet, renderDesc } from './utils';
import { config } from '@/config';
import { isValidHost } from '@/utils/valid-host';
import puppeteer from '@/utils/puppeteer';
import InvalidParameterError from '@/errors/types/invalid-parameter';
const handler = async (ctx) => {
const pub = ctx.req.param('pub');
@ -11,7 +12,7 @@ const handler = async (ctx) => {
const host = `https://pubs.aip.org`;
const jrnlUrl = `${host}/${pub}/${jrn}/issue`;
if (!isValidHost(pub)) {
throw new Error('Invalid pub');
throw new InvalidParameterError('Invalid pub');
}
// use Puppeteer due to the obstacle by cloudflare challenge

View File

@ -4,6 +4,7 @@ import got from '@/utils/got';
import { load } from 'cheerio';
import { rootUrl, ossUrl, ProcessFeed } from './utils';
import InvalidParameterError from '@/errors/types/invalid-parameter';
export const route: Route = {
path: '/thinktank/:id/:type?',
@ -43,7 +44,7 @@ async function handler(ctx) {
.toArray()
.filter((h) => (type ? $(h).text() === type : true));
if (!targetList) {
throw new Error(`Not found ${type} in ${id}: ${currentUrl}`);
throw new InvalidParameterError(`Not found ${type} in ${id}: ${currentUrl}`);
}
for (const l of targetList) {

View File

@ -3,6 +3,7 @@ import getComments from './comments';
import getFromAPI from './offcial-subject-api';
import getEps from './ep';
import { queryToBoolean } from '@/utils/readable-social';
import InvalidParameterError from '@/errors/types/invalid-parameter';
export const route: Route = {
path: '/tv/subject/:id/:type?/:showOriginalName?',
@ -50,7 +51,7 @@ async function handler(ctx) {
response = await getFromAPI('topic')(id, showOriginalName);
break;
default:
throw new Error(`暂不支持对${type}的订阅`);
throw new InvalidParameterError(`暂不支持对${type}的订阅`);
}
return response;
}

View File

@ -11,6 +11,7 @@ import { art } from '@/utils/render';
import path from 'node:path';
import asyncPool from 'tiny-async-pool';
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
// Visit https://www.bdys.me for the list of domains
const allowDomains = new Set(['52bdys.com', 'bde4.icu', 'bdys01.com']);
@ -107,7 +108,7 @@ async function handler(ctx) {
const site = ctx.req.query('domain') || 'bdys01.com';
if (!config.feature.allow_user_supply_unsafe_domain && !allowDomains.has(new URL(`https://${site}`).hostname)) {
throw new Error(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
throw new ConfigNotFoundError(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
}
const rootUrl = `https://www.${site}`;

View File

@ -5,6 +5,7 @@ import { load } from 'cheerio';
import timezone from '@/utils/timezone';
import { parseDate } from '@/utils/parse-date';
import { isValidHost } from '@/utils/valid-host';
import InvalidParameterError from '@/errors/types/invalid-parameter';
export const route: Route = {
path: '/news/:city',
@ -43,7 +44,7 @@ export const route: Route = {
async function handler(ctx) {
const city = ctx.req.param('city');
if (!isValidHost(city)) {
throw new Error('Invalid city');
throw new InvalidParameterError('Invalid city');
}
const rootUrl = `http://${city}.bendibao.com`;

View File

@ -2,6 +2,7 @@ import { Route } from '@/types';
import got from '@/utils/got';
import cache from './cache';
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
export const route: Route = {
path: '/user/followers/:uid/:loginUid',
@ -45,7 +46,7 @@ async function handler(ctx) {
const cookie = config.bilibili.cookies[loginUid];
if (cookie === undefined) {
throw new Error('缺少对应 loginUid 的 Bilibili 用户登录后的 Cookie 值 <a href="https://docs.rsshub.app/zh/deploy/config#route-specific-configurations">bilibili 用户关注动态系列路由</a>');
throw new ConfigNotFoundError('缺少对应 loginUid 的 Bilibili 用户登录后的 Cookie 值 <a href="https://docs.rsshub.app/zh/deploy/config#route-specific-configurations">bilibili 用户关注动态系列路由</a>');
}
const name = await cache.getUsernameFromUID(uid);
@ -68,7 +69,7 @@ async function handler(ctx) {
},
});
if (response.data.code === -6 || response.data.code === -101) {
throw new Error('对应 loginUid 的 Bilibili 用户的 Cookie 已过期');
throw new ConfigNotFoundError('对应 loginUid 的 Bilibili 用户的 Cookie 已过期');
}
const data = response.data.data.list;

View File

@ -2,6 +2,7 @@ import { Route } from '@/types';
import got from '@/utils/got';
import cache from './cache';
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
export const route: Route = {
path: '/followings/article/:uid',
@ -39,7 +40,7 @@ async function handler(ctx) {
const cookie = config.bilibili.cookies[uid];
if (cookie === undefined) {
throw new Error('缺少对应 uid 的 Bilibili 用户登录后的 Cookie 值');
throw new ConfigNotFoundError('缺少对应 uid 的 Bilibili 用户登录后的 Cookie 值');
}
const response = await got({
@ -51,7 +52,7 @@ async function handler(ctx) {
},
});
if (response.data.code === -6) {
throw new Error('对应 uid 的 Bilibili 用户的 Cookie 已过期');
throw new ConfigNotFoundError('对应 uid 的 Bilibili 用户的 Cookie 已过期');
}
const cards = response.data.data.cards;

View File

@ -6,6 +6,7 @@ import utils from './utils';
import JSONbig from 'json-bigint';
import { fallback, queryToBoolean } from '@/utils/readable-social';
import querystring from 'querystring';
import ConfigNotFoundError from '@/errors/types/config-not-found';
export const route: Route = {
path: '/followings/dynamic/:uid/:routeParams?',
@ -49,7 +50,7 @@ async function handler(ctx) {
const cookie = config.bilibili.cookies[uid];
if (cookie === undefined) {
throw new Error('缺少对应 uid 的 Bilibili 用户登录后的 Cookie 值');
throw new ConfigNotFoundError('缺少对应 uid 的 Bilibili 用户登录后的 Cookie 值');
}
const response = await got({
@ -61,7 +62,7 @@ async function handler(ctx) {
},
});
if (response.data.code === -6) {
throw new Error('对应 uid 的 Bilibili 用户的 Cookie 已过期');
throw new ConfigNotFoundError('对应 uid 的 Bilibili 用户的 Cookie 已过期');
}
const data = JSONbig.parse(response.body).data.cards;

View File

@ -3,6 +3,7 @@ import got from '@/utils/got';
import cache from './cache';
import { config } from '@/config';
import utils from './utils';
import ConfigNotFoundError from '@/errors/types/config-not-found';
export const route: Route = {
path: '/followings/video/:uid/:disableEmbed?',
@ -41,7 +42,7 @@ async function handler(ctx) {
const cookie = config.bilibili.cookies[uid];
if (cookie === undefined) {
throw new Error('缺少对应 uid 的 Bilibili 用户登录后的 Cookie 值');
throw new ConfigNotFoundError('缺少对应 uid 的 Bilibili 用户登录后的 Cookie 值');
}
const response = await got({
@ -53,7 +54,7 @@ async function handler(ctx) {
},
});
if (response.data.code === -6) {
throw new Error('对应 uid 的 Bilibili 用户的 Cookie 已过期');
throw new ConfigNotFoundError('对应 uid 的 Bilibili 用户的 Cookie 已过期');
}
const cards = response.data.data.cards;

View File

@ -2,6 +2,8 @@ import { Route } from '@/types';
import got from '@/utils/got';
import cache from './cache';
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
import InvalidParameterError from '@/errors/types/invalid-parameter';
export const route: Route = {
path: '/user/followings/:uid/:loginUid',
@ -43,7 +45,7 @@ async function handler(ctx) {
const loginUid = ctx.req.param('loginUid');
const cookie = config.bilibili.cookies[loginUid];
if (cookie === undefined) {
throw new Error('缺少对应 loginUid 的 Bilibili 用户登录后的 Cookie 值 <a href="https://docs.rsshub.app/zh/deploy/config#route-specific-configurations">bilibili 用户关注动态系列路由</a>');
throw new ConfigNotFoundError('缺少对应 loginUid 的 Bilibili 用户登录后的 Cookie 值 <a href="https://docs.rsshub.app/zh/deploy/config#route-specific-configurations">bilibili 用户关注动态系列路由</a>');
}
const uid = ctx.req.param('uid');
@ -67,11 +69,11 @@ async function handler(ctx) {
},
});
if (response.data.code === -6) {
throw new Error('对应 loginUid 的 Bilibili 用户的 Cookie 已过期');
throw new ConfigNotFoundError('对应 loginUid 的 Bilibili 用户的 Cookie 已过期');
}
// 22115 : 用户已设置隐私,无法查看
if (response.data.code === 22115) {
throw new Error(response.data.message);
throw new InvalidParameterError(response.data.message);
}
const data = response.data.data.list;

View File

@ -2,6 +2,7 @@ import { Route } from '@/types';
import got from '@/utils/got';
import cache from './cache';
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
export const route: Route = {
path: '/manga/followings/:uid/:limits?',
@ -39,7 +40,7 @@ async function handler(ctx) {
const cookie = config.bilibili.cookies[uid];
if (cookie === undefined) {
throw new Error('缺少对应 uid 的 Bilibili 用户登录后的 Cookie 值');
throw new ConfigNotFoundError('缺少对应 uid 的 Bilibili 用户登录后的 Cookie 值');
}
const page_size = ctx.req.param('limits') || 10;
const link = 'https://manga.bilibili.com/account-center';
@ -53,7 +54,7 @@ async function handler(ctx) {
},
});
if (response.data.code === -6) {
throw new Error('对应 uid 的 Bilibili 用户的 Cookie 已过期');
throw new ConfigNotFoundError('对应 uid 的 Bilibili 用户的 Cookie 已过期');
}
const comics = response.data.data;

View File

@ -4,6 +4,7 @@ import cache from './cache';
import { config } from '@/config';
import utils from './utils';
import { parseDate } from '@/utils/parse-date';
import ConfigNotFoundError from '@/errors/types/config-not-found';
export const route: Route = {
path: '/watchlater/:uid/:disableEmbed?',
@ -42,7 +43,7 @@ async function handler(ctx) {
const cookie = config.bilibili.cookies[uid];
if (cookie === undefined) {
throw new Error('缺少对应 uid 的 Bilibili 用户登录后的 Cookie 值');
throw new ConfigNotFoundError('缺少对应 uid 的 Bilibili 用户登录后的 Cookie 值');
}
const response = await got({
@ -55,7 +56,7 @@ async function handler(ctx) {
});
if (response.data.code) {
const message = response.data.code === -6 ? '对应 uid 的 Bilibili 用户的 Cookie 已过期' : response.data.message;
throw new Error(`Error code ${response.data.code}: ${message}`);
throw new ConfigNotFoundError(`Error code ${response.data.code}: ${message}`);
}
const list = response.data.data.list || [];

View File

@ -7,6 +7,7 @@ import iconv from 'iconv-lite';
import timezone from '@/utils/timezone';
import { parseDate } from '@/utils/parse-date';
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
const allowHost = new Set([
'www.xbiquwx.la',
'www.biqu5200.net',
@ -36,7 +37,7 @@ async function handler(ctx) {
const rootUrl = getSubPath(ctx).split('/').slice(1, 4).join('/');
const currentUrl = getSubPath(ctx).slice(1);
if (!config.feature.allow_user_supply_unsafe_domain && !allowHost.has(new URL(rootUrl).hostname)) {
throw new Error(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
throw new ConfigNotFoundError(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
}
const response = await got({

View File

@ -10,6 +10,7 @@ import { parseDate } from '@/utils/parse-date';
import { art } from '@/utils/render';
import path from 'node:path';
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
const allowDomain = new Set(['2btjia.com', '88btbtt.com', 'btbtt15.com', 'btbtt20.com']);
export const route: Route = {
@ -71,7 +72,7 @@ async function handler(ctx) {
let category = ctx.req.param('category') ?? '';
let domain = ctx.req.query('domain') ?? 'btbtt15.com';
if (!config.feature.allow_user_supply_unsafe_domain && !allowDomain.has(new URL(`http://${domain}/`).hostname)) {
throw new Error(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
throw new ConfigNotFoundError(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
}
if (category === 'base') {

View File

@ -5,6 +5,7 @@ import { load } from 'cheerio';
import { isValidHost } from '@/utils/valid-host';
import { parseDate } from '@/utils/parse-date';
import { parseBlogArticle } from './utils';
import InvalidParameterError from '@/errors/types/invalid-parameter';
export const route: Route = {
path: '/blog/:column?',
@ -30,7 +31,7 @@ async function handler(ctx) {
const { limit = 20 } = ctx.req.query();
if (column) {
if (!isValidHost(column)) {
throw new Error('Invalid column');
throw new InvalidParameterError('Invalid column');
}
const link = `https://${column}.blog.caixin.com`;
const { data: response } = await got(link);

View File

@ -6,6 +6,7 @@ import { isValidHost } from '@/utils/valid-host';
import { parseDate } from '@/utils/parse-date';
import timezone from '@/utils/timezone';
import { parseArticle } from './utils';
import InvalidParameterError from '@/errors/types/invalid-parameter';
export const route: Route = {
path: '/:column/:category',
@ -47,7 +48,7 @@ async function handler(ctx) {
const column = ctx.req.param('column');
const url = `https://${column}.caixin.com/${category}`;
if (!isValidHost(column)) {
throw new Error('Invalid column');
throw new InvalidParameterError('Invalid column');
}
const response = await got(url);

View File

@ -10,6 +10,7 @@ import { art } from '@/utils/render';
import path from 'node:path';
import { rootUrl, getSearchParams } from './utils';
import InvalidParameterError from '@/errors/types/invalid-parameter';
const categories = {
1000: '头条',
@ -57,7 +58,7 @@ async function handler(ctx) {
const title = categories[category];
if (!title) {
throw new Error('Bad category. See <a href="https://docs.rsshub.app/routes/finance#cai-lian-she-shen-du">docs</a>');
throw new InvalidParameterError('Bad category. See <a href="https://docs.rsshub.app/routes/finance#cai-lian-she-shen-du">docs</a>');
}
const apiUrl = `${rootUrl}/v3/depth/home/assembled/${category}`;

View File

@ -8,6 +8,7 @@ import { load } from 'cheerio';
import { parseDate } from '@/utils/parse-date';
import { art } from '@/utils/render';
import path from 'node:path';
import InvalidParameterError from '@/errors/types/invalid-parameter';
const categories = {
jxrb: '嘉兴日报',
@ -25,7 +26,7 @@ async function handler(ctx) {
const category = ctx.req.param('category') ?? 'jxrb';
const id = ctx.req.param('id');
if (!Object.keys(categories).includes(category)) {
throw new Error('Invalid category');
throw new InvalidParameterError('Invalid category');
}
const rootUrl = `https://${category}.cnjxol.com`;

View File

@ -8,6 +8,7 @@ import { load } from 'cheerio';
import { parseDate } from '@/utils/parse-date';
import { art } from '@/utils/render';
import path from 'node:path';
import InvalidParameterError from '@/errors/types/invalid-parameter';
export const route: Route = {
path: '/:name',
@ -50,7 +51,7 @@ async function handler(ctx) {
.map((el) => $(el).find('a').first().attr('href'));
if (links.length === 0) {
throw new Error(`Comic Not Found - ${name}`);
throw new InvalidParameterError(`Comic Not Found - ${name}`);
}
const items = await Promise.all(
links.map((link) =>

View File

@ -1,6 +1,7 @@
import { Route } from '@/types';
import got from '@/utils/got';
import utils from './utils';
import InvalidParameterError from '@/errors/types/invalid-parameter';
export const route: Route = {
path: '/dyh/:dyhId',
@ -48,7 +49,7 @@ async function handler(ctx) {
out = out.filter(Boolean); // 去除空值
if (out.length === 0) {
throw new Error('仅限于采集站内订阅的看看号的图文及动态内容。这个ID可能是站外订阅。');
throw new InvalidParameterError('仅限于采集站内订阅的看看号的图文及动态内容。这个ID可能是站外订阅。');
}
return {
title: `酷安看看号-${targetTitle}`,

View File

@ -1,6 +1,7 @@
import { Route } from '@/types';
import got from '@/utils/got';
import utils from './utils';
import InvalidParameterError from '@/errors/types/invalid-parameter';
export const route: Route = {
path: '/huati/:tag',
@ -32,7 +33,7 @@ async function handler(ctx) {
out = out.filter(Boolean); // 去除空值
if (out.length === 0) {
throw new Error('这个话题还没有被创建或现在没有图文及动态内容。');
throw new InvalidParameterError('这个话题还没有被创建或现在没有图文及动态内容。');
}
return {
title: `酷安话题-${tag}`,

View File

@ -1,6 +1,7 @@
import { Route } from '@/types';
import got from '@/utils/got';
import utils from './utils';
import InvalidParameterError from '@/errors/types/invalid-parameter';
export const route: Route = {
path: '/user/:uid/dynamic',
@ -29,7 +30,7 @@ async function handler(ctx) {
});
const data = response.data.data;
if (!data) {
throw new Error('这个人没有任何动态。');
throw new InvalidParameterError('这个人没有任何动态。');
}
let out = await Promise.all(
data.map((item) => {
@ -43,7 +44,7 @@ async function handler(ctx) {
out = out.filter(Boolean); // 去除空值
if (out.length === 0) {
throw new Error('这个人还没有图文或动态。');
throw new InvalidParameterError('这个人还没有图文或动态。');
}
return {
title: `酷安个人动态-${username}`,

View File

@ -8,6 +8,7 @@ import { parseDate } from '@/utils/parse-date';
import { art } from '@/utils/render';
import path from 'node:path';
import { baseUrl, getChannel, getChannelMessages, getGuild } from './discord-api';
import ConfigNotFoundError from '@/errors/types/config-not-found';
export const route: Route = {
path: '/channel/:channelId',
@ -39,7 +40,7 @@ export const route: Route = {
async function handler(ctx) {
if (!config.discord || !config.discord.authorization) {
throw new Error('Discord RSS is disabled due to the lack of <a href="https://docs.rsshub.app/deploy/config#route-specific-configurations">relevant config</a>');
throw new ConfigNotFoundError('Discord RSS is disabled due to the lack of <a href="https://docs.rsshub.app/deploy/config#route-specific-configurations">relevant config</a>');
}
const { authorization } = config.discord;
const channelId = ctx.req.param('channelId');

View File

@ -1,8 +1,9 @@
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
function getConfig(ctx) {
if (!config.discourse.config[ctx.req.param('configId')]) {
throw new Error('Discourse RSS is disabled due to the lack of <a href="https://docs.rsshub.app/deploy/">relevant config</a>');
throw new ConfigNotFoundError('Discourse RSS is disabled due to the lack of <a href="https://docs.rsshub.app/deploy/">relevant config</a>');
}
return config.discourse.config[ctx.req.param('configId')];
}

View File

@ -5,6 +5,8 @@ import { load } from 'cheerio';
import iconv from 'iconv-lite';
import { parseDate } from '@/utils/parse-date';
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
import InvalidParameterError from '@/errors/types/invalid-parameter';
function fixUrl(itemLink, baseUrl) {
// 处理相对链接
@ -68,7 +70,7 @@ async function handler(ctx) {
const cookie = cid === undefined ? '' : config.discuz.cookies[cid];
if (cookie === undefined) {
throw new Error('缺少对应论坛的cookie.');
throw new ConfigNotFoundError('缺少对应论坛的cookie.');
}
const header = {
@ -149,7 +151,7 @@ async function handler(ctx) {
)
);
} else {
throw new Error('不支持当前Discuz版本.');
throw new InvalidParameterError('不支持当前Discuz版本.');
}
return {

View File

@ -1,3 +1,4 @@
import InvalidParameterError from '@/errors/types/invalid-parameter';
import { Route } from '@/types';
import got from '@/utils/got';
import { load } from 'cheerio';
@ -141,7 +142,7 @@ async function handler(ctx) {
const info = infos[ctx.req.param('type')];
// 判断参数是否合理
if (info === undefined) {
throw new Error('不支持指定类型!');
throw new InvalidParameterError('不支持指定类型!');
}
if (ctx.req.param('free') !== undefined) {
info.params.is_free = 1;

View File

@ -2,6 +2,7 @@ import { Route } from '@/types';
import got from '@/utils/got';
import { load } from 'cheerio';
import { parseDate } from '@/utils/parse-date';
import InvalidParameterError from '@/errors/types/invalid-parameter';
const host = 'https://www.dlsite.com';
const infos = {
@ -75,7 +76,7 @@ async function handler(ctx) {
const info = infos[ctx.req.param('type')];
// 判断参数是否合理
if (info === undefined) {
throw new Error('不支持指定类型!');
throw new InvalidParameterError('不支持指定类型!');
}
const link = info.url.slice(1);

View File

@ -1,4 +1,5 @@
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
const defaultDomain = 'mp4us.com';
@ -87,7 +88,7 @@ function decodeCipherText(p, a, c, k, e, d) {
function ensureDomain(ctx, domain = defaultDomain) {
const origin = `https://${domain}`;
if (!config.feature.allow_user_supply_unsafe_domain && !allowedDomains.has(new URL(origin).hostname)) {
throw new Error(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
throw new ConfigNotFoundError(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
}
return origin;
}

View File

@ -6,6 +6,7 @@ import { config } from '@/config';
import { fallback, queryToBoolean } from '@/utils/readable-social';
import { templates, resolveUrl, proxyVideo, getOriginAvatar } from './utils';
import puppeteer from '@/utils/puppeteer';
import InvalidParameterError from '@/errors/types/invalid-parameter';
export const route: Route = {
path: '/hashtag/:cid/:routeParams?',
@ -34,7 +35,7 @@ export const route: Route = {
async function handler(ctx) {
const cid = ctx.req.param('cid');
if (isNaN(cid)) {
throw new TypeError('Invalid tag ID. Tag ID should be a number.');
throw new InvalidParameterError('Invalid tag ID. Tag ID should be a number.');
}
const routeParams = Object.fromEntries(new URLSearchParams(ctx.req.param('routeParams')));
const embed = fallback(undefined, queryToBoolean(routeParams.embed), false); // embed video

View File

@ -4,6 +4,7 @@ import { config } from '@/config';
import { getOriginAvatar } from './utils';
import logger from '@/utils/logger';
import puppeteer from '@/utils/puppeteer';
import InvalidParameterError from '@/errors/types/invalid-parameter';
export const route: Route = {
path: '/live/:rid',
@ -31,7 +32,7 @@ export const route: Route = {
async function handler(ctx) {
const rid = ctx.req.param('rid');
if (isNaN(rid)) {
throw new TypeError('Invalid room ID. Room ID should be a number.');
throw new InvalidParameterError('Invalid room ID. Room ID should be a number.');
}
const pageUrl = `https://live.douyin.com/${rid}`;

View File

@ -5,6 +5,7 @@ import { art } from '@/utils/render';
import { config } from '@/config';
import { fallback, queryToBoolean } from '@/utils/readable-social';
import { templates, resolveUrl, proxyVideo, getOriginAvatar, universalGet } from './utils';
import InvalidParameterError from '@/errors/types/invalid-parameter';
export const route: Route = {
path: '/user/:uid/:routeParams?',
@ -33,7 +34,7 @@ export const route: Route = {
async function handler(ctx) {
const uid = ctx.req.param('uid');
if (!uid.startsWith('MS4wLjABAAAA')) {
throw new Error('Invalid UID. UID should start with <b>MS4wLjABAAAA</b>.');
throw new InvalidParameterError('Invalid UID. UID should start with <b>MS4wLjABAAAA</b>.');
}
const routeParams = Object.fromEntries(new URLSearchParams(ctx.req.param('routeParams')));
const embed = fallback(undefined, queryToBoolean(routeParams.embed), false); // embed video

View File

@ -6,6 +6,7 @@ import { parseDate } from '@/utils/parse-date';
import defaults from './defaults';
import shortcuts from './shortcuts';
import { isValidHost } from '@/utils/valid-host';
import InvalidParameterError from '@/errors/types/invalid-parameter';
export const route: Route = {
path: ['/*/*', '/:0?'],
@ -17,7 +18,7 @@ export const route: Route = {
async function handler(ctx) {
const site = ctx.params[0] ?? 'news';
if (!isValidHost(site)) {
throw new Error('Invalid site');
throw new InvalidParameterError('Invalid site');
}
let items;

View File

@ -4,6 +4,7 @@ import got from '@/utils/got';
import { load } from 'cheerio';
import { parseDate } from '@/utils/parse-date';
import { isValidHost } from '@/utils/valid-host';
import InvalidParameterError from '@/errors/types/invalid-parameter';
const cateList = new Set(['all', 'design-resources', 'learn-design', 'inside-eagle']);
export const route: Route = {
@ -35,7 +36,7 @@ async function handler(ctx) {
let cate = ctx.req.param('cate') ?? 'all';
let language = ctx.req.param('language') ?? 'cn';
if (!isValidHost(cate) || !isValidHost(language)) {
throw new Error('Invalid host');
throw new InvalidParameterError('Invalid host');
}
if (!cateList.has(cate)) {
language = cate;

View File

@ -1,6 +1,7 @@
import { Route } from '@/types';
import cache from '@/utils/cache';
import EhAPI from './ehapi';
import ConfigNotFoundError from '@/errors/types/config-not-found';
export const route: Route = {
path: '/favorites/:favcat?/:order?/:page?/:routeParams?',
@ -22,7 +23,7 @@ export const route: Route = {
async function handler(ctx) {
if (!EhAPI.has_cookie) {
throw new Error('Ehentai favorites RSS is disabled due to the lack of <a href="https://docs.rsshub.app/deploy/config#route-specific-configurations">relevant config</a>');
throw new ConfigNotFoundError('Ehentai favorites RSS is disabled due to the lack of <a href="https://docs.rsshub.app/deploy/config#route-specific-configurations">relevant config</a>');
}
const favcat = ctx.req.param('favcat') ? Number.parseInt(ctx.req.param('favcat')) : 0;
const page = ctx.req.param('page');

View File

@ -9,6 +9,7 @@ import { load } from 'cheerio';
import { parseDate } from '@/utils/parse-date';
import { art } from '@/utils/render';
import path from 'node:path';
import InvalidParameterError from '@/errors/types/invalid-parameter';
const allowRegion = new Set(['tw', 'hk']);
export const route: Route = {
@ -37,7 +38,7 @@ export const route: Route = {
async function handler(ctx) {
const region = ctx.req.param('region') ?? 'tw';
if (!allowRegion.has(region)) {
throw new Error('Invalid region');
throw new InvalidParameterError('Invalid region');
}
const feed = await parser.parseURL(`https://www.eprice.com.${region}/news/rss.xml`);

View File

@ -4,6 +4,7 @@ const __dirname = getCurrentPath(import.meta.url);
import got from '@/utils/got';
import path from 'node:path';
import { art } from '@/utils/render';
import InvalidParameterError from '@/errors/types/invalid-parameter';
const apiBaseUrl = 'https://apiv3.fansly.com';
const baseUrl = 'https://fansly.com';
@ -27,7 +28,7 @@ const getAccountByUsername = (username, tryGet) =>
});
if (!accountResponse.response.length) {
throw new Error('This profile or page does not exist.');
throw new InvalidParameterError('This profile or page does not exist.');
}
return accountResponse.response[0];

View File

@ -7,6 +7,7 @@ import { parseDate } from '@/utils/parse-date';
import { art } from '@/utils/render';
import path from 'node:path';
import { isValidHost } from '@/utils/valid-host';
import InvalidParameterError from '@/errors/types/invalid-parameter';
export const route: Route = {
path: ['/global/:lang/:type?', '/ff14_global/:lang/:type?'],
@ -41,7 +42,7 @@ async function handler(ctx) {
const type = ctx.req.param('type') ?? 'all';
if (!isValidHost(lang)) {
throw new Error('Invalid lang');
throw new InvalidParameterError('Invalid lang');
}
const response = await got({

View File

@ -3,6 +3,7 @@ import got from '@/utils/got';
import { load } from 'cheerio';
import timezone from '@/utils/timezone';
import { parseDate } from '@/utils/parse-date';
import InvalidParameterError from '@/errors/types/invalid-parameter';
const categories = {
news: 0,
@ -41,7 +42,7 @@ async function handler(ctx) {
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 200;
if (!Object.hasOwn(categories, category.toLowerCase())) {
throw new Error(`No category '${category}'.`);
throw new InvalidParameterError(`No category '${category}'.`);
}
const rootUrl = 'https://finviz.com';

View File

@ -4,6 +4,7 @@ import got from '@/utils/got';
import { load } from 'cheerio';
import parser from '@/utils/rss-parser';
import { isValidHost } from '@/utils/valid-host';
import InvalidParameterError from '@/errors/types/invalid-parameter';
export const route: Route = {
path: '/:domain/:category?',
@ -15,7 +16,7 @@ export const route: Route = {
async function handler(ctx) {
const { domain = 'news', category } = ctx.req.param();
if (!isValidHost(domain)) {
throw new Error('Invalid domain');
throw new InvalidParameterError('Invalid domain');
}
const baseUrl = `https://${domain}.gamme.com.tw`;
const feed = await parser.parseURL(`${baseUrl + (category ? `/category/${category}` : '')}/feed`);

View File

@ -4,6 +4,7 @@ import got from '@/utils/got';
import { load } from 'cheerio';
import { parseDate } from '@/utils/parse-date';
import { isValidHost } from '@/utils/valid-host';
import InvalidParameterError from '@/errors/types/invalid-parameter';
export const route: Route = {
path: '/:domain/tag/:tag',
@ -15,7 +16,7 @@ export const route: Route = {
async function handler(ctx) {
const { domain = 'news', tag } = ctx.req.param();
if (!isValidHost(domain)) {
throw new Error('Invalid domain');
throw new InvalidParameterError('Invalid domain');
}
const baseUrl = `https://${domain}.gamme.com.tw`;
const pageUrl = `${baseUrl}/tag/${tag}`;

View File

@ -1,3 +1,4 @@
import InvalidParameterError from '@/errors/types/invalid-parameter';
import { Route } from '@/types';
import cache from '@/utils/cache';
import got from '@/utils/got';
@ -60,7 +61,7 @@ async function handler(ctx) {
list = list.get();
if (list.length > 0 && list.every((item) => item.url === undefined)) {
throw new Error('Article URL not found! Please submit an issue on GitHub.');
throw new InvalidParameterError('Article URL not found! Please submit an issue on GitHub.');
}
const out = await Promise.all(

View File

@ -1,3 +1,4 @@
import InvalidParameterError from '@/errors/types/invalid-parameter';
import { Route } from '@/types';
import cache from '@/utils/cache';
import got from '@/utils/got';
@ -52,7 +53,7 @@ async function handler(ctx) {
.get();
if (list.length > 0 && list.every((item) => item.url === undefined)) {
throw new Error('Article URL not found! Please submit an issue on GitHub.');
throw new InvalidParameterError('Article URL not found! Please submit an issue on GitHub.');
}
const out = await Promise.all(

View File

@ -1,6 +1,7 @@
import { Route } from '@/types';
import got from '@/utils/got';
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
export const route: Route = {
path: '/user/followers/:user',
@ -27,7 +28,7 @@ export const route: Route = {
async function handler(ctx) {
if (!config.github || !config.github.access_token) {
throw new Error('GitHub follower RSS is disabled due to the lack of <a href="https://docs.rsshub.app/deploy/config#route-specific-configurations">relevant config</a>');
throw new ConfigNotFoundError('GitHub follower RSS is disabled due to the lack of <a href="https://docs.rsshub.app/deploy/config#route-specific-configurations">relevant config</a>');
}
const user = ctx.req.param('user');

View File

@ -4,6 +4,7 @@ import { parseDate } from '@/utils/parse-date';
const apiUrl = 'https://api.github.com';
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
export const route: Route = {
path: '/notifications',
@ -36,7 +37,7 @@ export const route: Route = {
async function handler(ctx) {
if (!config.github || !config.github.access_token) {
throw new Error('GitHub trending RSS is disabled due to the lack of <a href="https://docs.rsshub.app/deploy/config#route-specific-configurations">relevant config</a>');
throw new ConfigNotFoundError('GitHub trending RSS is disabled due to the lack of <a href="https://docs.rsshub.app/deploy/config#route-specific-configurations">relevant config</a>');
}
const headers = {
Accept: 'application/vnd.github.v3+json',

View File

@ -1,6 +1,7 @@
import { Route } from '@/types';
import got from '@/utils/got';
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
export const route: Route = {
path: '/stars/:user/:repo',
@ -27,7 +28,7 @@ export const route: Route = {
async function handler(ctx) {
if (!config.github || !config.github.access_token) {
throw new Error('GitHub star RSS is disabled due to the lack of <a href="https://docs.rsshub.app/deploy/config#route-specific-configurations">relevant config</a>');
throw new ConfigNotFoundError('GitHub star RSS is disabled due to the lack of <a href="https://docs.rsshub.app/deploy/config#route-specific-configurations">relevant config</a>');
}
const user = ctx.req.param('user');
const repo = ctx.req.param('repo');

View File

@ -7,6 +7,7 @@ import got from '@/utils/got';
import { art } from '@/utils/render';
import { load } from 'cheerio';
import path from 'node:path';
import ConfigNotFoundError from '@/errors/types/config-not-found';
export const route: Route = {
path: '/trending/:since/:language/:spoken_language?',
@ -44,7 +45,7 @@ export const route: Route = {
async function handler(ctx) {
if (!config.github || !config.github.access_token) {
throw new Error('GitHub trending RSS is disabled due to the lack of <a href="https://docs.rsshub.app/deploy/config#route-specific-configurations">relevant config</a>');
throw new ConfigNotFoundError('GitHub trending RSS is disabled due to the lack of <a href="https://docs.rsshub.app/deploy/config#route-specific-configurations">relevant config</a>');
}
const since = ctx.req.param('since');
const language = ctx.req.param('language') === 'any' ? '' : ctx.req.param('language');

View File

@ -7,6 +7,7 @@ import { config } from '@/config';
import { art } from '@/utils/render';
import path from 'node:path';
import { parseDate } from '@/utils/parse-date';
import ConfigNotFoundError from '@/errors/types/config-not-found';
const titleMap = {
date: 'Newest',
@ -52,7 +53,7 @@ async function handler(ctx) {
const API_KEY = config.google.fontsApiKey;
if (!API_KEY) {
throw new Error('Google Fonts API key is required.');
throw new ConfigNotFoundError('Google Fonts API key is required.');
}
const googleFontsAPI = `https://www.googleapis.com/webfonts/v1/webfonts?sort=${sort}&key=${API_KEY}`;

View File

@ -4,6 +4,7 @@ import got from '@/utils/got';
import { load } from 'cheerio';
import { parseDate } from '@/utils/parse-date';
import timezone from '@/utils/timezone';
import InvalidParameterError from '@/errors/types/invalid-parameter';
const rootUrl = 'http://www.sz.gov.cn/cn/xxgk/zfxxgj/';
const config = {
@ -49,7 +50,7 @@ export const route: Route = {
async function handler(ctx) {
const cfg = config[ctx.req.param('caty')];
if (!cfg) {
throw new Error('Bad category. See <a href="https://docs.rsshub.app/routes/government#guang-dong-sheng-ren-min-zheng-fu-guang-dong-sheng-shen-zhen-shi-ren-min-zheng-fu">docs</a>');
throw new InvalidParameterError('Bad category. See <a href="https://docs.rsshub.app/routes/government#guang-dong-sheng-ren-min-zheng-fu-guang-dong-sheng-shen-zhen-shi-ren-min-zheng-fu">docs</a>');
}
const currentUrl = new URL(cfg.link, rootUrl).href;

View File

@ -3,6 +3,7 @@ import got from '@/utils/got';
import { load } from 'cheerio';
import { parseDate } from '@/utils/parse-date';
import timezone from '@/utils/timezone';
import InvalidParameterError from '@/errors/types/invalid-parameter';
const config = {
tzgg: {
@ -41,7 +42,7 @@ async function handler(ctx) {
const baseUrl = 'http://zjj.sz.gov.cn/xxgk/';
const cfg = config[ctx.req.param('caty')];
if (!cfg) {
throw new Error('Bad category. See <a href="https://docs.rsshub.app/routes/government#guang-dong-sheng-ren-min-zheng-fu-shen-zhen-shi-zhu-fang-he-jian-she-ju">docs</a>');
throw new InvalidParameterError('Bad category. See <a href="https://docs.rsshub.app/routes/government#guang-dong-sheng-ren-min-zheng-fu-shen-zhen-shi-zhu-fang-he-jian-she-ju">docs</a>');
}
const currentUrl = new URL(cfg.link, baseUrl).href;

View File

@ -4,6 +4,7 @@ import got from '@/utils/got';
import { load } from 'cheerio';
import { parseDate } from '@/utils/parse-date';
import timezone from '@/utils/timezone';
import InvalidParameterError from '@/errors/types/invalid-parameter';
export const route: Route = {
path: '/suzhou/news/:uid',
@ -119,7 +120,7 @@ async function handler(ctx) {
title = '苏州市政府 - 民生资讯';
break;
default:
throw new Error('pattern not matched');
throw new InvalidParameterError('pattern not matched');
}
if (apiUrl) {
const response = await got(apiUrl);

View File

@ -7,6 +7,7 @@ import { load } from 'cheerio';
import { art } from '@/utils/render';
import path from 'node:path';
import { isValidHost } from '@/utils/valid-host';
import InvalidParameterError from '@/errors/types/invalid-parameter';
export const route: Route = {
path: '/:username/:products',
@ -31,7 +32,7 @@ async function handler(ctx) {
const username = ctx.req.param('username');
const products = ctx.req.param('products');
if (!isValidHost(username)) {
throw new Error('Invalid username');
throw new InvalidParameterError('Invalid username');
}
const url = `https://${username}.gumroad.com/l/${products}`;

View File

@ -1,6 +1,7 @@
import { Route } from '@/types';
import got from '@/utils/got';
import { parseList, parseItem } from './utils';
import InvalidParameterError from '@/errors/types/invalid-parameter';
const channelMap = {
calendar: 'pac',
@ -42,7 +43,7 @@ async function handler(ctx) {
const result = parseList(response.result);
if (result.length === 0) {
throw new Error('Unknown channel');
throw new InvalidParameterError('Unknown channel');
}
const channelName = result[0].channels[0].name;

View File

@ -4,6 +4,7 @@ import got from '@/utils/got';
import { load } from 'cheerio';
import { parseDate } from '@/utils/parse-date';
import { isValidHost } from '@/utils/valid-host';
import InvalidParameterError from '@/errors/types/invalid-parameter';
function getKeysRecursive(dic, key, attr, array) {
for (const v of Object.values(dic)) {
@ -46,7 +47,7 @@ export const route: Route = {
async function handler(ctx) {
const category = ctx.req.param('category') ?? 'china';
if (!isValidHost(category)) {
throw new Error('Invalid category');
throw new InvalidParameterError('Invalid category');
}
const host = `https://${category}.huanqiu.com`;

View File

@ -4,6 +4,7 @@ import { ig, login } from './utils';
import logger from '@/utils/logger';
import { config } from '@/config';
import { renderItems } from '../common-utils';
import InvalidParameterError from '@/errors/types/invalid-parameter';
// loadContent pulls the desired user/tag/etc
async function loadContent(category, nameOrId, tryGet) {
@ -93,7 +94,7 @@ async function handler(ctx) {
// e.g. username for user feed
const { category, key } = ctx.req.param();
if (!availableCategories.includes(category)) {
throw new Error('Such feed is not supported.');
throw new InvalidParameterError('Such feed is not supported.');
}
if (config.instagram && config.instagram.proxy) {

View File

@ -1,12 +1,13 @@
import { IgApiClient } from 'instagram-private-api';
import logger from '@/utils/logger';
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
const ig = new IgApiClient();
async function login(ig, cache) {
if (!config.instagram || !config.instagram.username || !config.instagram.password) {
throw new Error('Instagram RSS is disabled due to the lack of <a href="https://docs.rsshub.app/deploy/config#route-specific-configurations">relevant config</a>');
throw new ConfigNotFoundError('Instagram RSS is disabled due to the lack of <a href="https://docs.rsshub.app/deploy/config#route-specific-configurations">relevant config</a>');
}
const LOGIN_CACHE_KEY = 'instagram:login';
const { username, password } = config.instagram;

View File

@ -4,6 +4,8 @@ import { CookieJar } from 'tough-cookie';
import { config } from '@/config';
import { renderItems } from '../common-utils';
import { baseUrl, COOKIE_URL, checkLogin, getUserInfo, getUserFeedItems, getTagsFeedItems, getLoggedOutTagsFeedItems, renderGuestItems } from './utils';
import InvalidParameterError from '@/errors/types/invalid-parameter';
import ConfigNotFoundError from '@/errors/types/config-not-found';
export const route: Route = {
path: '/2/:category/:key',
@ -39,7 +41,7 @@ async function handler(ctx) {
const { category, key } = ctx.req.param();
const { cookie } = config.instagram;
if (!availableCategories.includes(category)) {
throw new Error('Such feed is not supported.');
throw new InvalidParameterError('Such feed is not supported.');
}
let cookieJar = await cache.get('instagram:cookieJar');
@ -58,7 +60,7 @@ async function handler(ctx) {
}
if (!wwwClaimV2 && cookie && !(await checkLogin(cookieJar, cache))) {
throw new Error('Invalid cookie');
throw new ConfigNotFoundError('Invalid cookie');
}
let feedTitle, feedLink, feedDescription, feedLogo;

View File

@ -6,6 +6,7 @@ import { parseDate } from '@/utils/parse-date';
import { config } from '@/config';
import { art } from '@/utils/render';
import path from 'node:path';
import ConfigNotFoundError from '@/errors/types/config-not-found';
const baseUrl = 'https://www.instagram.com';
const COOKIE_URL = 'https://instagram.com';
@ -59,7 +60,7 @@ const getUserInfo = async (username, cookieJar, cache) => {
},
});
if (response.url.includes('/accounts/login/')) {
throw new Error('Invalid cookie');
throw new ConfigNotFoundError('Invalid cookie');
}
webProfileInfo = response.data.data.user;
@ -69,7 +70,7 @@ const getUserInfo = async (username, cookieJar, cache) => {
await cache.set(`instagram:userInfo:${id}`, webProfileInfo);
} catch (error) {
if (error.message.includes("Cookie not in this host's domain")) {
throw new Error('Invalid cookie');
throw new ConfigNotFoundError('Invalid cookie');
}
throw error;
}
@ -97,7 +98,7 @@ const getUserFeedItems = (id, username, cookieJar, cache) =>
},
});
if (response.url.includes('/accounts/login/')) {
throw new Error(`Invalid cookie.
throw new ConfigNotFoundError(`Invalid cookie.
Please also check if your account is being blocked by Instagram.`);
}

View File

@ -7,6 +7,7 @@ import { load } from 'cheerio';
import { parseDate } from '@/utils/parse-date';
import { art } from '@/utils/render';
import path from 'node:path';
import InvalidParameterError from '@/errors/types/invalid-parameter';
export const route: Route = {
path: '/album/:id',
@ -43,7 +44,7 @@ async function handler(ctx) {
} = await got(`https://pcw-api.iqiyi.com/album/album/baseinfo/${album.videoAlbumInfo.albumId}`);
if (Object.keys(album.cacheAlbumList).length === 0) {
throw new Error(`${baseInfo.name} is not available in this server region.`);
throw new InvalidParameterError(`${baseInfo.name} is not available in this server region.`);
}
let pos = 1;

View File

@ -10,6 +10,7 @@ import { parseDate } from '@/utils/parse-date';
import { art } from '@/utils/render';
import path from 'node:path';
import { isValidHost } from '@/utils/valid-host';
import InvalidParameterError from '@/errors/types/invalid-parameter';
export const route: Route = {
path: '/devlog/:user/:id',
@ -38,7 +39,7 @@ async function handler(ctx) {
const user = ctx.req.param('user') ?? '';
const id = ctx.req.param('id') ?? '';
if (!isValidHost(user)) {
throw new Error('Invalid user');
throw new InvalidParameterError('Invalid user');
}
const rootUrl = `https://${user}.itch.io/${id}/devlog`;

View File

@ -1,3 +1,4 @@
import InvalidParameterError from '@/errors/types/invalid-parameter';
import { Route } from '@/types';
import cache from '@/utils/cache';
import got from '@/utils/got';
@ -59,7 +60,7 @@ export const route: Route = {
async function handler(ctx) {
const cfg = config[ctx.req.param('caty')];
if (!cfg) {
throw new Error('Bad category. See <a href="https://docs.rsshub.app/routes/new-media#it-zhi-jia">https://docs.rsshub.app/routes/new-media#it-zhi-jia</a>');
throw new InvalidParameterError('Bad category. See <a href="https://docs.rsshub.app/routes/new-media#it-zhi-jia">https://docs.rsshub.app/routes/new-media#it-zhi-jia</a>');
}
const current_url = get_url(ctx.req.param('caty'));

View File

@ -1,3 +1,4 @@
import InvalidParameterError from '@/errors/types/invalid-parameter';
import { Route } from '@/types';
import cache from '@/utils/cache';
import got from '@/utils/got';
@ -49,7 +50,7 @@ async function handler(ctx) {
const id = type2id[option];
if (!id) {
throw new Error('Bad type. See <a href="https://docs.rsshub.app/routes/new-media#it-zhi-jia">https://docs.rsshub.app/routes/new-media#it-zhi-jia</a>');
throw new InvalidParameterError('Bad type. See <a href="https://docs.rsshub.app/routes/new-media#it-zhi-jia">https://docs.rsshub.app/routes/new-media#it-zhi-jia</a>');
}
const list = $(`#${id} > li`)

View File

@ -9,6 +9,7 @@ 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,
});
@ -51,7 +52,7 @@ export const route: Route = {
async function handler() {
if (!config.iwara || !config.iwara.username || !config.iwara.password) {
throw new Error('Iwara subscription RSS is disabled due to the lack of <a href="https://docs.rsshub.app/deploy/config#route-specific-configurations">relevant config</a>');
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`;

View File

@ -10,6 +10,7 @@ import { parseDate } from '@/utils/parse-date';
import { art } from '@/utils/render';
import path from 'node:path';
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
const toSize = (raw) => {
const matches = raw.match(/(\d+(\.\d+)?)(\w+)/);
@ -41,7 +42,7 @@ async function handler(ctx) {
const westernUrl = `https://www.${westernDomain}`;
if (!config.feature.allow_user_supply_unsafe_domain && (!allowDomain.has(new URL(`https://${domain}/`).hostname) || !allowDomain.has(new URL(`https://${westernDomain}/`).hostname))) {
throw new Error(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
throw new ConfigNotFoundError(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
}
const currentUrl = `${isWestern ? westernUrl : rootUrl}${getSubPath(ctx)

View File

@ -3,13 +3,14 @@ import got from '@/utils/got';
import { load } from 'cheerio';
import { parseDate } from '@/utils/parse-date';
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
const allowDomain = new Set(['javdb.com', 'javdb36.com', 'javdb007.com', 'javdb521.com']);
const ProcessItems = async (ctx, currentUrl, title) => {
const domain = ctx.req.query('domain') ?? 'javdb.com';
const url = new URL(currentUrl, `https://${domain}`);
if (!config.feature.allow_user_supply_unsafe_domain && !allowDomain.has(url.hostname)) {
throw new Error(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
throw new ConfigNotFoundError(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
}
const rootUrl = `https://${domain}`;

View File

@ -9,6 +9,8 @@ import timezone from '@/utils/timezone';
import { parseDate } from '@/utils/parse-date';
import { art } from '@/utils/render';
import path from 'node:path';
import ConfigNotFoundError from '@/errors/types/config-not-found';
import InvalidParameterError from '@/errors/types/invalid-parameter';
const resolveRelativeLink = (link, baseUrl) => (link.startsWith('http') ? link : `${baseUrl}${link}`);
@ -37,7 +39,7 @@ async function handler(ctx) {
// raise error for invalid languages
if (!['china', 'tchina'].includes(language)) {
throw new Error('Invalid language');
throw new ConfigNotFoundError('Invalid language');
}
const rootUrl = `https://${language}.kyodonews.net`;
@ -47,7 +49,7 @@ async function handler(ctx) {
try {
response = await got(currentUrl);
} catch (error) {
throw error.response && error.response.statusCode === 404 ? new Error('Invalid keyword') : error;
throw error.response && error.response.statusCode === 404 ? new InvalidParameterError('Invalid keyword') : error;
}
const $ = load(response.data, { xmlMode: keyword === 'rss' });

View File

@ -5,6 +5,8 @@ import { parseDate } from '@/utils/parse-date';
import MarkdownIt from 'markdown-it';
const md = MarkdownIt({ html: true });
import { config } from '@/config';
import InvalidParameterError from '@/errors/types/invalid-parameter';
import ConfigNotFoundError from '@/errors/types/config-not-found';
export const route: Route = {
path: '/:community/:sort?',
@ -34,12 +36,12 @@ async function handler(ctx) {
const community = ctx.req.param('community');
const communitySlices = community.split('@');
if (communitySlices.length !== 2) {
throw new Error(`Invalid community: ${community}`);
throw new InvalidParameterError(`Invalid community: ${community}`);
}
const instance = community.split('@')[1];
const allowedDomain = ['lemmy.world', 'lemm.ee', 'lemmy.ml', 'sh.itjust.works', 'feddit.de', 'hexbear.net', 'beehaw.org', 'lemmynsfw.com', 'lemmy.ca', 'programming.dev'];
if (!config.feature.allow_user_supply_unsafe_domain && !allowedDomain.includes(new URL(`http://${instance}/`).hostname)) {
throw new Error(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
throw new ConfigNotFoundError(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
}
const communityUrl = `https://${instance}/api/v3/community?name=${community}`;

View File

@ -2,6 +2,7 @@ import { Route } from '@/types';
import got from '@/utils/got';
import { load } from 'cheerio';
import { isValidHost } from '@/utils/valid-host';
import InvalidParameterError from '@/errors/types/invalid-parameter';
export const route: Route = {
path: '/:region?',
@ -31,7 +32,7 @@ async function handler(ctx) {
const region = ctx.req.param('region') ?? 'ukraine';
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 50;
if (!isValidHost(region)) {
throw new Error('Invalid region');
throw new InvalidParameterError('Invalid region');
}
const url = `https://${region}.liveuamap.com/`;

View File

@ -1,3 +1,4 @@
import InvalidParameterError from '@/errors/types/invalid-parameter';
import { Route } from '@/types';
import got from '@/utils/got';
import { parseDate } from '@/utils/parse-date';
@ -25,7 +26,7 @@ async function handler(ctx) {
const name = ctx.req.param('name') ?? 'i';
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : '50';
if (!isValidHost(name)) {
throw new Error('Invalid name');
throw new InvalidParameterError('Invalid name');
}
const rootUrl = `${name}.lofter.com`;

View File

@ -10,6 +10,7 @@ import timezone from '@/utils/timezone';
import { parseDate } from '@/utils/parse-date';
import { art } from '@/utils/render';
import path from 'node:path';
import InvalidParameterError from '@/errors/types/invalid-parameter';
export const route: Route = {
path: '/:id?/:category{.+}?',
@ -21,7 +22,7 @@ export const route: Route = {
async function handler(ctx) {
const { id = 'news', category = 'china' } = ctx.req.param();
if (!isValidHost(id)) {
throw new Error('Invalid id');
throw new InvalidParameterError('Invalid id');
}
const limit = ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 30;

View File

@ -5,6 +5,7 @@ import { config } from '@/config';
import { simpleParser } from 'mailparser';
import logger from '@/utils/logger';
import { parseDate } from '@/utils/parse-date';
import ConfigNotFoundError from '@/errors/types/config-not-found';
export const route: Route = {
path: '/imap/:email/:folder{.+}?',
@ -23,7 +24,7 @@ async function handler(ctx) {
};
if (!mailConfig.username || !mailConfig.password || !mailConfig.host || !mailConfig.port) {
throw new Error('Email Inbox RSS is disabled due to the lack of <a href="https://docs.rsshub.app/deploy/#route-specific-configurations">relevant config</a>');
throw new ConfigNotFoundError('Email Inbox RSS is disabled due to the lack of <a href="https://docs.rsshub.app/deploy/#route-specific-configurations">relevant config</a>');
}
const client = new ImapFlow({

View File

@ -8,6 +8,7 @@ import { load } from 'cheerio';
import { art } from '@/utils/render';
import path from 'node:path';
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
const web_url = 'https://www.manhuagui.com/user/book/shelf/1';
export const route: Route = {
@ -45,7 +46,7 @@ export const route: Route = {
async function handler() {
if (!config.manhuagui || !config.manhuagui.cookie) {
throw new Error('manhuagui RSS is disabled due to the lack of <a href="https://docs.rsshub.app/deploy/config#route-specific-configurations">relevant config</a>');
throw new ConfigNotFoundError('manhuagui RSS is disabled due to the lack of <a href="https://docs.rsshub.app/deploy/config#route-specific-configurations">relevant config</a>');
}
const cookie = config.manhuagui.cookie;
const response = await got({

View File

@ -1,6 +1,7 @@
import { Route } from '@/types';
import utils from './utils';
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
export const route: Route = {
path: '/account_id/:site/:account_id/statuses/:only_media?',
@ -14,7 +15,7 @@ async function handler(ctx) {
const account_id = ctx.req.param('account_id');
const only_media = ctx.req.param('only_media') ? 'true' : 'false';
if (!config.feature.allow_user_supply_unsafe_domain && !utils.allowSiteList.includes(site)) {
throw new Error(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
throw new ConfigNotFoundError(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
}
const { account_data, data } = await utils.getAccountStatuses(site, account_id, only_media);

View File

@ -2,6 +2,7 @@ import { Route } from '@/types';
import got from '@/utils/got';
import utils from './utils';
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
export const route: Route = {
path: '/timeline/:site/:only_media?',
@ -26,7 +27,7 @@ async function handler(ctx) {
const site = ctx.req.param('site');
const only_media = ctx.req.param('only_media') ? 'true' : 'false';
if (!config.feature.allow_user_supply_unsafe_domain && !utils.allowSiteList.includes(site)) {
throw new Error(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
throw new ConfigNotFoundError(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
}
const url = `http://${site}/api/v1/timelines/public?local=true&only_media=${only_media}`;

View File

@ -2,6 +2,7 @@ import { Route } from '@/types';
import got from '@/utils/got';
import utils from './utils';
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
export const route: Route = {
path: '/remote/:site/:only_media?',
@ -26,7 +27,7 @@ async function handler(ctx) {
const site = ctx.req.param('site');
const only_media = ctx.req.param('only_media') ? 'true' : 'false';
if (!config.feature.allow_user_supply_unsafe_domain && !utils.allowSiteList.includes(site)) {
throw new Error(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
throw new ConfigNotFoundError(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
}
const url = `http://${site}/api/v1/timelines/public?remote=true&only_media=${only_media}`;

View File

@ -2,6 +2,7 @@ import cache from '@/utils/cache';
import got from '@/utils/got';
import { parseDate } from '@/utils/parse-date';
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
const allowSiteList = ['mastodon.social', 'pawoo.net', config.mastodon.apiHost].filter(Boolean);
@ -93,10 +94,10 @@ async function getAccountIdByAcct(acct) {
const site = mastodonConfig.apiHost || acctHost;
const acctDomain = mastodonConfig.acctDomain || acctHost;
if (!(site && acctDomain)) {
throw new Error('Mastodon RSS is disabled due to the lack of <a href="https://docs.rsshub.app/deploy/config#route-specific-configurations">relevant config</a>');
throw new ConfigNotFoundError('Mastodon RSS is disabled due to the lack of <a href="https://docs.rsshub.app/deploy/config#route-specific-configurations">relevant config</a>');
}
if (!config.feature.allow_user_supply_unsafe_domain && !allowSiteList.includes(site)) {
throw new Error(`RSS for this domain is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true' or 'MASTODON_API_HOST' is set.`);
throw new ConfigNotFoundError(`RSS for this domain is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true' or 'MASTODON_API_HOST' is set.`);
}
const search_url = `https://${site}/api/v2/search`;

View File

@ -3,6 +3,7 @@ import { config } from '@/config';
import parseArticle from './parse-article.js';
import { getFollowingFeedQuery } from './graphql.js';
import ConfigNotFoundError from '@/errors/types/config-not-found.js';
export const route: Route = {
path: '/following/:user',
@ -35,7 +36,7 @@ async function handler(ctx) {
const cookie = config.medium.cookies[user];
if (cookie === undefined) {
throw new Error(`缺少 Medium 用户 ${user} 登录后的 Cookie 值`);
throw new ConfigNotFoundError(`缺少 Medium 用户 ${user} 登录后的 Cookie 值`);
}
const posts = await getFollowingFeedQuery(user, cookie);
@ -43,7 +44,7 @@ async function handler(ctx) {
if (!posts) {
// login failed
throw new Error(`Medium 用户 ${user} 的 Cookie 无效或已过期`);
throw new ConfigNotFoundError(`Medium 用户 ${user} 的 Cookie 无效或已过期`);
}
const urls = posts.items.map((data) => data.post.mediumUrl);

View File

@ -3,6 +3,7 @@ import { config } from '@/config';
import parseArticle from './parse-article.js';
import { getWebInlineRecommendedFeedQuery } from './graphql.js';
import ConfigNotFoundError from '@/errors/types/config-not-found.js';
export const route: Route = {
path: '/for-you/:user',
@ -35,7 +36,7 @@ async function handler(ctx) {
const cookie = config.medium.cookies[user];
if (cookie === undefined) {
throw new Error(`缺少 Medium 用户 ${user} 登录后的 Cookie 值`);
throw new ConfigNotFoundError(`缺少 Medium 用户 ${user} 登录后的 Cookie 值`);
}
const posts = await getWebInlineRecommendedFeedQuery(user, cookie);
@ -43,7 +44,7 @@ async function handler(ctx) {
if (!posts) {
// login failed
throw new Error(`Medium 用户 ${user} 的 Cookie 无效或已过期`);
throw new ConfigNotFoundError(`Medium 用户 ${user} 的 Cookie 无效或已过期`);
}
const urls = posts.items.map((data) => data.post.mediumUrl);

View File

@ -3,6 +3,8 @@ import { config } from '@/config';
import parseArticle from './parse-article.js';
import { getUserCatalogMainContentQuery } from './graphql.js';
import ConfigNotFoundError from '@/errors/types/config-not-found.js';
import InvalidParameterError from '@/errors/types/invalid-parameter.js';
export const route: Route = {
path: '/list/:user/:catalogId',
@ -37,10 +39,10 @@ async function handler(ctx) {
ctx.set('json', catalog);
if (catalog && catalog.__typename === 'Forbidden') {
throw new Error(`无权访问 id 为 ${catalogId} 的 List可能是未设置 Cookie 或 Cookie 已过期)`);
throw new ConfigNotFoundError(`无权访问 id 为 ${catalogId} 的 List可能是未设置 Cookie 或 Cookie 已过期)`);
}
if (!catalog || !catalog.itemsConnection) {
throw new Error(`id 为 ${catalogId} 的 List 不存在`);
throw new InvalidParameterError(`id 为 ${catalogId} 的 List 不存在`);
}
const name = catalog.name;

View File

@ -3,6 +3,7 @@ import { config } from '@/config';
import parseArticle from './parse-article.js';
import { getWebInlineTopicFeedQuery } from './graphql.js';
import ConfigNotFoundError from '@/errors/types/config-not-found.js';
export const route: Route = {
path: '/tag/:user/:tag',
@ -38,7 +39,7 @@ async function handler(ctx) {
const cookie = config.medium.cookies[user];
if (cookie === undefined) {
throw new Error(`缺少 Medium 用户 ${user} 登录后的 Cookie 值`);
throw new ConfigNotFoundError(`缺少 Medium 用户 ${user} 登录后的 Cookie 值`);
}
const posts = await getWebInlineTopicFeedQuery(user, tag, cookie);
@ -46,7 +47,7 @@ async function handler(ctx) {
if (!posts) {
// login failed
throw new Error(`Medium 用户 ${user} 的 Cookie 无效或已过期`);
throw new ConfigNotFoundError(`Medium 用户 ${user} 的 Cookie 无效或已过期`);
}
const urls = posts.items.map((data) => data.post.mediumUrl);

View File

@ -1,10 +1,11 @@
import cache from '@/utils/cache';
import got from '@/utils/got';
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
const getUserFullInfo = (ctx, uid) => {
if (!uid && !config.mihoyo.cookie) {
throw new Error('GetUserFullInfo is not available due to the absense of [Miyoushe Cookie]. Check <a href="https://docs.rsshub.app/deploy/config#route-specific-configurations">relevant config tutorial</a>');
throw new ConfigNotFoundError('GetUserFullInfo is not available due to the absense of [Miyoushe Cookie]. Check <a href="https://docs.rsshub.app/deploy/config#route-specific-configurations">relevant config tutorial</a>');
}
uid ||= '';
const key = 'mihoyo:user-full-info-uid-' + uid;

View File

@ -3,6 +3,7 @@ import got from '@/utils/got';
import cache from './cache';
import { config } from '@/config';
import { post2item } from './utils';
import ConfigNotFoundError from '@/errors/types/config-not-found';
export const route: Route = {
path: '/bbs/timeline',
@ -37,7 +38,7 @@ export const route: Route = {
async function handler(ctx) {
if (!config.mihoyo.cookie) {
throw new Error('Miyoushe Timeline is not available due to the absense of [Miyoushe Cookie]. Check <a href="https://docs.rsshub.app/deploy/config#route-specific-configurations">relevant config tutorial</a>');
throw new ConfigNotFoundError('Miyoushe Timeline is not available due to the absense of [Miyoushe Cookie]. Check <a href="https://docs.rsshub.app/deploy/config#route-specific-configurations">relevant config tutorial</a>');
}
const page_size = ctx.req.query('limit') || '20';

View File

@ -1,6 +1,7 @@
import { Route, Data } from '@/types';
import got from '@/utils/got';
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
export const route: Route = {
path: '/entry/:feeds/:parameters?',
@ -63,7 +64,7 @@ async function handler(ctx) {
const token = config.miniflux.token;
if (!token) {
throw new Error('This RSS feed is disabled due to its incorrect configuration: the token is missing.');
throw new ConfigNotFoundError('This RSS feed is disabled due to its incorrect configuration: the token is missing.');
}
// In this function, var`mark`, `link`, and `limit`, `addFeedName`

View File

@ -1,6 +1,7 @@
import { Route } from '@/types';
import got from '@/utils/got';
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
export const route: Route = {
path: '/subscription/:parameters?',
@ -43,7 +44,7 @@ async function handler(ctx) {
const token = config.miniflux.token;
if (!token) {
throw new Error('This RSS feed is disabled due to its incorrect configuration: the token is missing.');
throw new ConfigNotFoundError('This RSS feed is disabled due to its incorrect configuration: the token is missing.');
}
function set(item) {

View File

@ -7,6 +7,7 @@ const md = MarkdownIt({
linkify: true,
});
import { isValidHost } from '@/utils/valid-host';
import InvalidParameterError from '@/errors/types/invalid-parameter';
export const route: Route = {
path: '/:id',
@ -29,7 +30,7 @@ export const route: Route = {
async function handler(ctx) {
const id = ctx.req.param('id');
if (!id.endsWith('.eth') && !isValidHost(id)) {
throw new Error('Invalid id');
throw new InvalidParameterError('Invalid id');
}
const rootUrl = 'https://mirror.xyz';
const currentUrl = id.endsWith('.eth') ? `${rootUrl}/${id}` : `https://${id}.mirror.xyz`;

View File

@ -2,6 +2,7 @@ import { Route } from '@/types';
import got from '@/utils/got';
import utils from './utils';
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
export const route: Route = {
path: '/notes/featured/:site',
@ -24,7 +25,7 @@ export const route: Route = {
async function handler(ctx) {
const site = ctx.req.param('site');
if (!config.feature.allow_user_supply_unsafe_domain && !utils.allowSiteList.includes(site)) {
throw new Error(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
throw new ConfigNotFoundError(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
}
// docs on: https://misskey-hub.net/docs/api/endpoints/notes/featured.html

View File

@ -3,6 +3,7 @@ import got from '@/utils/got';
import CryptoJS from 'crypto-js';
import { parseDate } from '@/utils/parse-date';
import { queries } from './queries';
import InvalidParameterError from '@/errors/types/invalid-parameter';
export const route: Route = {
path: '/:username/:type?',
@ -37,7 +38,7 @@ async function handler(ctx) {
const type = ctx.req.param('type') ?? 'uploads';
if (!['stream', 'uploads', 'favorites', 'listens'].includes(type)) {
throw new Error(`Invalid type: ${type}`);
throw new InvalidParameterError(`Invalid type: ${type}`);
}
const username = ctx.req.param('username');

View File

@ -9,6 +9,7 @@ import { parseDate } from '@/utils/parse-date';
import { art } from '@/utils/render';
import path from 'node:path';
import { isValidHost } from '@/utils/valid-host';
import InvalidParameterError from '@/errors/types/invalid-parameter';
export const route: Route = {
path: '/activity/:category?/:language?/:latestAdditions?/:latestEdits?/:latestAlerts?/:latestPictures?',
@ -75,7 +76,7 @@ async function handler(ctx) {
const latestPictures = ctx.req.param('latestPictures') ?? '1';
if (language && !isValidHost(language)) {
throw new Error('Invalid language');
throw new InvalidParameterError('Invalid language');
}
const rootUrl = `https://${language === 'en' || language === '' ? '' : `${language}.`}myfigurecollection.net`;

View File

@ -8,6 +8,7 @@ import { load } from 'cheerio';
import { art } from '@/utils/render';
import path from 'node:path';
import { isValidHost } from '@/utils/valid-host';
import InvalidParameterError from '@/errors/types/invalid-parameter';
const shortcuts = {
potd: 'picture/browse/potd/',
@ -46,7 +47,7 @@ async function handler(ctx) {
const language = ctx.req.param('language') ?? '';
const category = ctx.req.param('category') ?? 'figure';
if (language && !isValidHost(language)) {
throw new Error('Invalid language');
throw new InvalidParameterError('Invalid language');
}
const rootUrl = `https://${language === 'en' || language === '' ? '' : `${language}.`}myfigurecollection.net`;

View File

@ -2,6 +2,7 @@ import { Route } from '@/types';
import got from '@/utils/got';
import utils from './utils';
import { config } from '@/config';
import ConfigNotFoundError from '@/errors/types/config-not-found';
export const route: Route = {
path: '/douyin/:dyid',
@ -31,7 +32,7 @@ export const route: Route = {
async function handler(ctx) {
if (!config.newrank || !config.newrank.cookie) {
throw new Error('newrank RSS is disabled due to the lack of <a href="https://docs.rsshub.app/deploy/config#route-specific-configurations">relevant config</a>');
throw new ConfigNotFoundError('newrank RSS is disabled due to the lack of <a href="https://docs.rsshub.app/deploy/config#route-specific-configurations">relevant config</a>');
}
const uid = ctx.req.param('dyid');
const nonce = utils.random_nonce(9);

Some files were not shown because too many files have changed in this diff Show More