style(eslint): add eslint-unicorn (#14257)

* style: add eslint-unicorn

* style: fix unicorn/no-useless-spread

* style: fix unicorn/no-useless-promise-resolve-reject

* style: fix unicorn/no-for-loop

* fix: codeql bad HTML filtering regexp

* fix: codeql incomplete replace

* fix: unicorn/no-abusive-eslint-disable

* style: fix unicorn/no-new-array

* style: fix unicorn/no-typeof-undefined

* style: fix unicorn/no-zero-fractions

* style: fix unicorn/no-empty-file

* style: fix unicorn/prefer-date-now

* revert: auto fix unicorn/prefer-switch on lib/v2/kuaidi100/utils.js

* style: fix unicorn/prefer-array-find

* style: fix unicorn/prefer-array-flat

* style: fix unicorn/prefer-array-flat-map

* style: fix unicorn/prefer-at

* style: fix unicorn/prefer-string-starts-ends-with

* style: fix unicorn/prefer-includes

* fix: codeql URL substring sanitization

* style: fix unicorn/prefer-optional-catch-binding

* style: fix unicorn/catch-error-name

* style: fix unicorn/escape-case

* style: fix unicorn/prefer-native-coercion-functions

* style: fix unicorn/prefer-regexp-test

* style: fix unicorn/require-array-join-separator

* style: fix unicorn/prefer-math-trunc

* style: fix unicorn/prefer-negative-index

* style: fix unicorn/prefer-dom-node-dataset

* style: fix unicorn/prefer-dom-node-text-content

* style: fix unicorn/prefer-query-selector

* style: fix unicorn/no-array-for-each

* style: fix unicorn/no-negated-condition

* style: fix unicorn/prefer-add-event-listener

* style: fix unicorn/import-style

* style: fix prefer-regex-literals

* style: disable unicorn/no-useless-switch-case

* style: disable unicorn/text-encoding-identifier-case

* style: fix unicorn/prefer-set-has

* style: fix unicorn/prefer-spread

* revert: auto fix on lib/routes/universities/ynnu/edu/base64.js

* style: fix unicorn/no-useless-undefined

* style: fix unicorn/no-array-push-push

* style: fix unicorn/no-useless-undefined again

* style: fix unicorn/no-lonely-if

* style: fix unicorn/prefer-reflect-apply

* style: fix unicorn/switch-case-braces

* style: fix unicorn/prefer-switch

* style: fix unicorn/prefer-array-some

* fix: deepscan UNUSED_VAR_ASSIGN

* style: fix unicorn/prefer-ternary

* fix: follow-up of unicorn/prefer-ternary

* revert: auto fix of unicorn/prefer-string-slice for substring()

* style: disable unicorn/prefer-string-slice

fix: auto fix slice over deprecated substr

* style: fix unicorn/throw-new-error

* style: fix unicorn/filename-case

* test: fix dateParser renaming

* style: fix unicorn/better-regex

* style: fix unicorn/prefer-string-replace-all

* fix(deps): add sanitize-html

* style: fix no-prototype-builtins

* style: fix unicorn/consistent-destructuring

* style: fix unicorn/consistent-function-scoping

* style: fix unicorn/prefer-regexp-test

* style: fix unicorn/prefer-logical-operator-over-ternary

* style: fix unicorn/no-array-callback-reference

* style: add prefer-object-has-own

* style: warn unicorn/no-empty-file

* style: fix unicorn/prefer-number-properties

* style: fix no-useless-undefined again

* style: fix unicorn/numeric-separators-style

* style: disable unicorn/no-array-callback-reference

false postive with cheerio
This commit is contained in:
Tony
2024-01-18 12:43:40 +00:00
committed by GitHub
parent cd00220d98
commit 6d901cb7dc
1652 changed files with 6334 additions and 6435 deletions
+50 -42
View File
@@ -1,24 +1,21 @@
{
"extends": ["eslint:recommended", "plugin:n/recommended", "plugin:prettier/recommended", "plugin:yml/recommended"],
"plugins": ["prettier", "@stylistic/js"],
"extends": ["eslint:recommended", "plugin:n/recommended", "plugin:unicorn/recommended", "plugin:prettier/recommended", "plugin:yml/recommended"],
"plugins": ["prettier", "@stylistic/js", "unicorn"],
"parserOptions": {
"ecmaVersion": "latest",
"sourceType": "module"
},
"env": {
"node": true,
"es6": true,
"es2024": true,
"browser": true
},
"rules": {
// possible problems
"array-callback-return": 2,
"array-callback-return": ["error", { "allowImplicit": true }],
"no-await-in-loop": 2,
"no-control-regex": 0,
"no-duplicate-imports": 2,
"no-prototype-builtins": 0,
"no-unsafe-negation": 2,
"require-atomic-updates": 0,
// suggestions
"arrow-body-style": 2,
"block-scoped-var": 2,
@@ -29,16 +26,7 @@
"no-eval": 2,
"no-extend-native": 2,
"no-extra-label": 2,
"no-global-assign": 2,
"no-implicit-coercion": [
"error",
{
"boolean": false,
"number": false,
"string": false,
"disallowTemplateShorthand": true
}
],
"no-implicit-coercion": ["error", { "boolean": false, "number": false, "string": false, "disallowTemplateShorthand": true }],
"no-implicit-globals": 2,
"no-labels": 2,
"no-multi-str": 2,
@@ -52,9 +40,49 @@
"object-shorthand": 2,
"prefer-arrow-callback": 2,
"prefer-const": 2,
"prefer-regex-literals": 1,
"prefer-object-has-own": 2,
"prefer-regex-literals": ["error", { "disallowRedundantWrapping": true }],
"require-await": 2,
// plugin specific
"unicorn/consistent-destructuring": 1,
"unicorn/consistent-function-scoping": 1,
"unicorn/explicit-length-check": 0,
"unicorn/filename-case": ["error", { "case": "kebabCase", "ignore": [".*\\.(yaml|yml)$", "RequestInProgress\\.js$"] }],
"unicorn/new-for-builtins": 0,
"unicorn/no-array-callback-reference": 0,
"unicorn/no-array-reduce": 1,
"unicorn/no-await-expression-member": 1,
"unicorn/no-empty-file": 1,
"unicorn/no-hex-escape": 1,
"unicorn/no-null": 0,
"unicorn/no-object-as-default-parameter": 1,
"unicorn/no-process-exit": 0,
"unicorn/no-useless-switch-case": 0,
"unicorn/no-useless-undefined": ["error", { "checkArguments": false }],
"unicorn/numeric-separators-style": [
"warn",
{
"onlyIfContainsSeparator": false,
"number": { "minimumDigits": 7, "groupLength": 3 },
"binary": { "minimumDigits": 9, "groupLength": 4 },
"octal": { "minimumDigits": 9, "groupLength": 4 },
"hexadecimal": { "minimumDigits": 5, "groupLength": 2 }
}
],
"unicorn/prefer-code-point": 1,
"unicorn/prefer-logical-operator-over-ternary": 1,
"unicorn/prefer-module": 0,
"unicorn/prefer-node-protocol": 0,
"unicorn/prefer-number-properties": ["warn", { "checkInfinity": false }],
"unicorn/prefer-object-from-entries": 1,
"unicorn/prefer-regexp-test": 1,
"unicorn/prefer-string-replace-all": 1,
"unicorn/prefer-string-slice": 0,
"unicorn/prefer-switch": ["error", { "emptyDefaultCase": "do-nothing-comment" }],
"unicorn/prefer-top-level-await": 0,
"unicorn/prevent-abbreviations": 0,
"unicorn/switch-case-braces": ["error", "avoid"],
"unicorn/text-encoding-identifier-case": 0,
// previous eslint formatting rules
"@stylistic/js/arrow-parens": 2,
"@stylistic/js/arrow-spacing": 2,
@@ -74,40 +102,20 @@
"@stylistic/js/space-unary-ops": 2,
"@stylistic/js/spaced-comment": 2,
// https://github.com/eslint-community/eslint-plugin-n
"n/no-extraneous-require": [
"error",
{
"allowModules": ["puppeteer-extra-plugin-user-preferences", "puppeteer-extra-plugin-user-data-dir"]
}
],
"n/no-extraneous-require": ["error", { "allowModules": ["puppeteer-extra-plugin-user-preferences", "puppeteer-extra-plugin-user-data-dir"] }],
"n/no-deprecated-api": 1,
"n/no-missing-require": 0,
"n/no-process-exit": 0,
"n/no-unpublished-require": [
"error",
{
"allowModules": ["tosource"]
}
],
"n/no-unpublished-require": ["error", { "allowModules": ["tosource"] }],
"prettier/prettier": 0,
"yml/quotes": [
"error",
{
"prefer": "single"
}
]
"yml/quotes": ["error", { "prefer": "single" }]
},
"overrides": [
{
"files": ["*.yaml", "*.yml"],
"parser": "yaml-eslint-parser",
"rules": {
"lines-around-comment": [
"error",
{
"beforeBlockComment": false
}
]
"lines-around-comment": ["error", { "beforeBlockComment": false }]
}
}
]
+3 -3
View File
@@ -167,7 +167,7 @@
docs: 'https://docs.rsshub.app/routes/multimedia#onejav',
source: '/',
target: (params, url, document) => {
const today = document.querySelector('div.card.mb-1.card-overview').getAttribute('data-date').replace(/-/g, '');
const today = document.querySelector('div.card.mb-1.card-overview').dataset.date.replaceAll('-', '');
return `/onejav/day/${today}`;
},
},
@@ -215,7 +215,7 @@
} else {
return false;
}
return `/sexinsex/${pid}/${typeid ? typeid : ''}`;
return `/sexinsex/${pid}/${typeid ?? ''}`;
},
},
],
@@ -230,7 +230,7 @@
target: (params, url) => {
const id = new URL(url).searchParams.get('fid');
const type = new URL(url).searchParams.get('type');
return `/t66y/${id}/${type ? type : ''}`;
return `/t66y/${id}/${type ?? ''}`;
},
},
],
+2 -3
View File
@@ -6,8 +6,7 @@ router.get('/routes/:name?', (ctx) => {
let counter = 0;
const maintainer = require('./maintainer');
Object.keys(maintainer).forEach((i) => {
const path = i;
for (const path of Object.keys(maintainer)) {
const top = path.split('/')[1];
if (!ctx.params.name || top === ctx.params.name) {
@@ -18,7 +17,7 @@ router.get('/routes/:name?', (ctx) => {
}
counter++;
}
});
}
ctx.body = { counter, result };
});
+5 -5
View File
@@ -20,13 +20,13 @@ const antiHotlink = require('./middleware/anti-hotlink');
const loadOnDemand = require('./middleware/load-on-demand');
const router = require('./router');
const core_router = require('./core_router');
const protected_router = require('./protected_router');
const core_router = require('./core-router');
const protected_router = require('./protected-router');
const mount = require('koa-mount');
// API related
const apiTemplate = require('./middleware/api-template');
const api_router = require('./api_router');
const api_router = require('./api-router');
const apiResponseHandler = require('./middleware/api-response-handler');
process.on('uncaughtException', (e) => {
@@ -37,8 +37,8 @@ const app = new Koa();
app.proxy = true;
// favicon
app.use(favicon(__dirname + '/favicon.png', { maxAge: 31536000000 }));
app.use(serve(__dirname + '/static', { maxage: 31536000000 }));
app.use(favicon(__dirname + '/favicon.png', { maxAge: 31_536_000_000 }));
app.use(serve(__dirname + '/static', { maxage: 31_536_000_000 }));
// global error handing
app.use(onerror);
+10 -10
View File
@@ -45,21 +45,21 @@ const calculateValue = () => {
socket: envs.SOCKET || null, // 监听 Unix Socket, null 为禁用
},
listenInaddrAny: envs.LISTEN_INADDR_ANY || 1, // 是否允许公网连接,取值 0 1
requestRetry: parseInt(envs.REQUEST_RETRY) || 2, // 请求失败重试次数
requestTimeout: parseInt(envs.REQUEST_TIMEOUT) || 30000, // Milliseconds to wait for the server to end the response before aborting the request
ua: envs.UA ? envs.UA : envs.NO_RANDOM_UA === 'true' || envs.NO_RANDOM_UA === '1' ? TRUE_UA : randUserAgent({ browser: 'chrome', os: 'mac os', device: 'desktop' }),
requestRetry: Number.parseInt(envs.REQUEST_RETRY) || 2, // 请求失败重试次数
requestTimeout: Number.parseInt(envs.REQUEST_TIMEOUT) || 30000, // Milliseconds to wait for the server to end the response before aborting the request
ua: envs.UA ?? (envs.NO_RANDOM_UA === 'true' || envs.NO_RANDOM_UA === '1' ? TRUE_UA : randUserAgent({ browser: 'chrome', os: 'mac os', device: 'desktop' })),
trueUA: TRUE_UA,
// cors request
allowOrigin: envs.ALLOW_ORIGIN,
// cache
cache: {
type: typeof envs.CACHE_TYPE === 'undefined' ? 'memory' : envs.CACHE_TYPE, // 缓存类型,支持 'memory' 和 'redis',设为空可以禁止缓存
requestTimeout: parseInt(envs.CACHE_REQUEST_TIMEOUT) || 60,
routeExpire: parseInt(envs.CACHE_EXPIRE) || 5 * 60, // 路由缓存时间,单位为秒
contentExpire: parseInt(envs.CACHE_CONTENT_EXPIRE) || 1 * 60 * 60, // 不变内容缓存时间,单位为秒
type: envs.CACHE_TYPE === undefined ? 'memory' : envs.CACHE_TYPE, // 缓存类型,支持 'memory' 和 'redis',设为空可以禁止缓存
requestTimeout: Number.parseInt(envs.CACHE_REQUEST_TIMEOUT) || 60,
routeExpire: Number.parseInt(envs.CACHE_EXPIRE) || 5 * 60, // 路由缓存时间,单位为秒
contentExpire: Number.parseInt(envs.CACHE_CONTENT_EXPIRE) || 1 * 60 * 60, // 不变内容缓存时间,单位为秒
},
memory: {
max: parseInt(envs.MEMORY_MAX) || Math.pow(2, 8), // The maximum number of items that remain in the cache. This must be a positive finite intger.
max: Number.parseInt(envs.MEMORY_MAX) || Math.pow(2, 8), // The maximum number of items that remain in the cache. This must be a positive finite intger.
// https://github.com/isaacs/node-lru-cache#options
},
redis: {
@@ -96,7 +96,7 @@ const calculateValue = () => {
showLoggerTimestamp: envs.SHOW_LOGGER_TIMESTAMP,
sentry: {
dsn: envs.SENTRY,
routeTimeout: parseInt(envs.SENTRY_ROUTE_TIMEOUT) || 30000,
routeTimeout: Number.parseInt(envs.SENTRY_ROUTE_TIMEOUT) || 30000,
},
// feed config
hotlink: {
@@ -110,7 +110,7 @@ const calculateValue = () => {
allow_user_supply_unsafe_domain: envs.ALLOW_USER_SUPPLY_UNSAFE_DOMAIN === 'true',
},
suffix: envs.SUFFIX,
titleLengthLimit: parseInt(envs.TITLE_LENGTH_LIMIT) || 150,
titleLengthLimit: Number.parseInt(envs.TITLE_LENGTH_LIMIT) || 150,
openai: {
apiKey: envs.OPENAI_API_KEY,
model: envs.OPENAI_MODEL || 'gpt-3.5-turbo-16k',
+2 -2
View File
@@ -16,7 +16,7 @@ if (config.enableCluster && cluster.isMaster && process.env.NODE_ENV !== 'test'
if (fs.existsSync(config.connect.socket)) {
fs.unlinkSync(config.connect.socket);
}
server = app.listen(config.connect.socket, parseInt(config.listenInaddrAny) ? null : '127.0.0.1');
server = app.listen(config.connect.socket, Number.parseInt(config.listenInaddrAny) ? null : '127.0.0.1');
logger.info('Listening Unix Socket ' + config.connect.socket);
process.on('SIGINT', () => {
fs.unlinkSync(config.connect.socket);
@@ -24,7 +24,7 @@ if (config.enableCluster && cluster.isMaster && process.env.NODE_ENV !== 'test'
});
}
if (config.connect.port) {
server = app.listen(config.connect.port, parseInt(config.listenInaddrAny) ? null : '127.0.0.1');
server = app.listen(config.connect.port, Number.parseInt(config.listenInaddrAny) ? null : '127.0.0.1');
logger.info('Listening Port ' + config.connect.port);
}
+9 -9
View File
@@ -1,12 +1,12 @@
const dirname = __dirname + '/v2';
const fs = require('fs');
const { join } = require('path');
const path = require('path');
// Presence Check
for (const dir of fs.readdirSync(dirname)) {
const dirPath = join(dirname, dir);
if (fs.existsSync(join(dirPath, 'router.js')) && !fs.existsSync(join(dirPath, 'maintainer.js'))) {
throw Error(`No maintainer.js in "${dirPath}".`);
const dirPath = path.join(dirname, dir);
if (fs.existsSync(path.join(dirPath, 'router.js')) && !fs.existsSync(path.join(dirPath, 'maintainer.js'))) {
throw new Error(`No maintainer.js in "${dirPath}".`);
}
}
@@ -24,15 +24,15 @@ for (const dir in maintainerPath) {
// typo check e.g., ✘ module.export, ✔ module.exports
if (!Object.keys(routes).length) {
throw Error(`No maintainer in "${dir}".`);
throw new Error(`No maintainer in "${dir}".`);
}
for (const author of Object.values(routes)) {
if (!Array.isArray(author)) {
throw Error(`Maintainers' name should be an array in "${dir}".`);
throw new TypeError(`Maintainers' name should be an array in "${dir}".`);
}
// check for [], [''] or ['Someone', '']
if (author.length < 1 || author.includes('')) {
throw Error(`Empty maintainer in "${dir}".`);
throw new Error(`Empty maintainer in "${dir}".`);
}
}
@@ -43,11 +43,11 @@ for (const dir in maintainerPath) {
// 兼容旧版路由
const router = require('./router');
router.stack.forEach((e) => {
for (const e of router.stack) {
if (!maintainers[e.path]) {
maintainers[e.path] = [];
}
});
}
module.exports = Object.keys(maintainers)
.sort()
+10 -16
View File
@@ -5,11 +5,11 @@ const isLocalhost = require('is-localhost-ip');
const reject = (ctx) => {
ctx.response.status = 403;
throw Error('Authentication failed. Access denied.');
throw new Error('Authentication failed. Access denied.');
};
const ipv4Pattern = /^(\d{1,3}\.){3}\d{1,3}$/;
const cidrPattern = /(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\/(\d{1,2})/;
const cidrPattern = /((?:\d{1,3}\.){3}\d{1,3})\/(\d{1,2})/;
const ipInCidr = (cidr, ip) => {
const cidrMatch = cidr.match(cidrPattern);
@@ -17,7 +17,7 @@ const ipInCidr = (cidr, ip) => {
if (!cidrMatch || !ipMatch) {
return false;
}
const subnetMask = parseInt(cidrMatch[2]);
const subnetMask = Number.parseInt(cidrMatch[2]);
const cidrIpBits = ipv4ToBitsring(cidrMatch[1]).substring(0, subnetMask);
const ipBits = ipv4ToBitsring(ip).substring(0, subnetMask);
return cidrIpBits === ipBits;
@@ -26,7 +26,7 @@ const ipInCidr = (cidr, ip) => {
const ipv4ToBitsring = (ip) =>
ip
.split('.')
.map((part) => ('00000000' + parseInt(part).toString(2)).slice(-8))
.map((part) => ('00000000' + Number.parseInt(part).toString(2)).slice(-8))
.join('');
module.exports = async (ctx, next) => {
@@ -53,22 +53,16 @@ module.exports = async (ctx, next) => {
return grant();
}
if (config.accessKey) {
if (config.accessKey === accessKey || accessCode === md5(requestPath + config.accessKey)) {
return grant();
}
if (config.accessKey && (config.accessKey === accessKey || accessCode === md5(requestPath + config.accessKey))) {
return grant();
}
if (config.allowlist) {
if (config.allowlist.find((item) => ip.includes(item) || ipInCidr(item, ip) || requestPath.includes(item) || requestUA.includes(item))) {
return grant();
}
if (config.allowlist && config.allowlist.some((item) => ip.includes(item) || ipInCidr(item, ip) || requestPath.includes(item) || requestUA.includes(item))) {
return grant();
}
if (config.denylist) {
if (!config.denylist.find((item) => ip.includes(item) || ipInCidr(item, ip) || requestPath.includes(item) || requestUA.includes(item))) {
return grant();
}
if (config.denylist && !config.denylist.some((item) => ip.includes(item) || ipInCidr(item, ip) || requestPath.includes(item) || requestUA.includes(item))) {
return grant();
}
reject(ctx);
+12 -15
View File
@@ -4,8 +4,8 @@ const logger = require('@/utils/logger');
const path = require('path');
const { art } = require('@/utils/render');
const templateRegex = /\$\{([^{}]+)}/g;
const allowedUrlProperties = ['hash', 'host', 'hostname', 'href', 'origin', 'password', 'pathname', 'port', 'protocol', 'search', 'searchParams', 'username'];
const templateRegex = /\${([^{}]+)}/g;
const allowedUrlProperties = new Set(['hash', 'host', 'hostname', 'href', 'origin', 'password', 'pathname', 'port', 'protocol', 'search', 'searchParams', 'username']);
const IframeWrapperTemplate = path.join(__dirname, 'templates/iframe.art');
// match path or sub-path
@@ -26,7 +26,7 @@ const filterPath = (path) => {
};
const interpolate = (str, obj) =>
str.replace(templateRegex, (_, prop) => {
str.replaceAll(templateRegex, (_, prop) => {
let needEncode = false;
if (prop.endsWith('_ue')) {
// url encode
@@ -39,7 +39,7 @@ const parseUrl = (str) => {
let url;
try {
url = new URL(str);
} catch (e) {
} catch {
logger.error(`Failed to parse ${str}`);
}
@@ -87,12 +87,12 @@ const validateTemplate = (template) => {
if (!template) {
return;
}
[...template.matchAll(templateRegex)].forEach((match) => {
for (const match of template.matchAll(templateRegex)) {
const prop = match[1].endsWith('_ue') ? match[1].slice(0, -3) : match[1];
if (!allowedUrlProperties.includes(prop)) {
if (!allowedUrlProperties.has(prop)) {
throw new Error(`Invalid URL property: ${prop}`);
}
});
}
};
module.exports = async (ctx, next) => {
@@ -115,11 +115,7 @@ module.exports = async (ctx, next) => {
// Force config hotlink template on conflict
if (config.hotlink.template) {
if (!filterPath(ctx.request.path)) {
image_hotlink_template = undefined;
} else {
image_hotlink_template = config.hotlink.template;
}
image_hotlink_template = filterPath(ctx.request.path) ? config.hotlink.template : undefined;
}
if (!image_hotlink_template && !multimedia_hotlink_template && !shouldWrapInIframe) {
@@ -138,11 +134,12 @@ module.exports = async (ctx, next) => {
ctx.state.data.description = process(ctx.state.data.description, image_hotlink_template, multimedia_hotlink_template, shouldWrapInIframe);
}
ctx.state.data.item &&
ctx.state.data.item.forEach((item) => {
if (ctx.state.data.item) {
for (const item of ctx.state.data.item) {
if (item.description) {
item.description = process(item.description, image_hotlink_template, multimedia_hotlink_template, shouldWrapInIframe);
}
});
}
}
}
};
+9 -9
View File
@@ -57,22 +57,22 @@ module.exports = function (app) {
...cacheModule,
tryGet: async (key, getValueFunc, maxAge = config.cache.contentExpire, refresh = true) => {
if (typeof key !== 'string') {
throw Error('Cache key must be a string');
throw new TypeError('Cache key must be a string');
}
let v = await get(key, refresh);
if (!v) {
v = await getValueFunc();
set(key, v, maxAge);
} else {
if (v) {
let parsed;
try {
parsed = JSON.parse(v);
} catch (e) {
} catch {
parsed = null;
}
if (parsed) {
v = parsed;
}
} else {
v = await getValueFunc();
set(key, v, maxAge);
}
return v;
@@ -112,7 +112,7 @@ module.exports = function (app) {
ctx.state.data = JSON.parse(value);
return;
}
} catch (e) {
} catch {
//
}
@@ -121,9 +121,9 @@ module.exports = function (app) {
try {
await next();
} catch (e) {
} catch (error) {
await globalCache.set(controlKey, '0', config.cache.requestTimeout);
throw e;
throw error;
}
if (ctx.response.get('Cache-Control') !== 'no-cache' && ctx.state && ctx.state.data) {
+4 -4
View File
@@ -20,7 +20,7 @@ redisClient.on('connect', () => {
const getCacheTtlKey = (key) => {
if (key.startsWith('rsshub:cacheTtl:')) {
throw Error('"rsshub:cacheTtl:" prefix is reserved for the internal usage, please change your cache key'); // blocking any attempt to get/set the cacheTtl
throw new Error('"rsshub:cacheTtl:" prefix is reserved for the internal usage, please change your cache key'); // blocking any attempt to get/set the cacheTtl
}
return `rsshub:cacheTtl:${key}`;
};
@@ -31,13 +31,13 @@ module.exports = {
const cacheTtlKey = getCacheTtlKey(key);
let [value, cacheTtl] = await redisClient.mget(key, cacheTtlKey);
if (value && refresh) {
if (!cacheTtl) {
if (cacheTtl) {
redisClient.expire(cacheTtlKey, cacheTtl);
} else {
// if cacheTtl is not set, that means the cache expire time is contentExpire
cacheTtl = config.cache.contentExpire;
// dont save cacheTtl to Redis, as it is the default value
// redisClient.set(cacheTtlKey, cacheTtl, 'EX', cacheTtl);
} else {
redisClient.expire(cacheTtlKey, cacheTtl);
}
redisClient.expire(key, cacheTtl);
value = value + '';
+1 -1
View File
@@ -24,7 +24,7 @@ module.exports = async (ctx, next) => {
return;
}
const status = (ctx.status / 100) | 0;
const status = Math.trunc(ctx.status / 100);
if (2 !== status) {
return;
}
+3 -3
View File
@@ -11,7 +11,9 @@ module.exports = function (app) {
if (p.length > 0) {
modName = p[0];
if (!loadedRoutes.has(modName)) {
if (loadedRoutes.has(modName)) {
mounted = true;
} else {
const mod = routes[modName];
// Mount module
if (mod) {
@@ -21,8 +23,6 @@ module.exports = function (app) {
mod(router);
app.use(mount(`/${modName}`, router.routes())).use(router.allowedMethods());
}
} else {
mounted = true;
}
}
+15 -15
View File
@@ -20,15 +20,15 @@ if (config.sentry.dsn) {
try {
gitHash = require('git-rev-sync').short();
} catch (e) {
} catch {
gitHash = (process.env.HEROKU_SLUG_COMMIT && process.env.HEROKU_SLUG_COMMIT.slice(0, 7)) || (process.env.VERCEL_GIT_COMMIT_SHA && process.env.VERCEL_GIT_COMMIT_SHA.slice(0, 7)) || 'unknown';
}
module.exports = async (ctx, next) => {
try {
const time = +new Date();
const time = Date.now();
await next();
if (config.sentry.dsn && +new Date() - time >= config.sentry.routeTimeout) {
if (config.sentry.dsn && Date.now() - time >= config.sentry.routeTimeout) {
Sentry.withScope((scope) => {
scope.setTag('route', ctx._matchedRoute);
scope.setTag('name', ctx.request.path.split('/')[1]);
@@ -36,8 +36,8 @@ module.exports = async (ctx, next) => {
Sentry.captureException(new Error('Route Timeout'));
});
}
} catch (err) {
if (err instanceof Error && !err.stack.split('\n')[1].includes('lib/middleware/parameter.js')) {
} catch (error) {
if (error instanceof Error && !error.stack.split('\n')[1].includes('lib/middleware/parameter.js')) {
// Append v2 route path if a route throws an error
// since koa-mount will remove the mount path from ctx.request.path
// https://github.com/koajs/mount/issues/62
@@ -45,11 +45,11 @@ module.exports = async (ctx, next) => {
ctx._matchedRoute = ctx._matchedRoute ? (ctx.mountPath ?? '') + ctx._matchedRoute : ctx._matchedRoute;
}
let message = err;
if (err.name && (err.name === 'HTTPError' || err.name === 'RequestError')) {
message = `${err.message}: target website might be blocking our access, you can <a href="https://docs.rsshub.app/install/">host your own RSSHub instance</a> for a better usability.`;
} else if (err instanceof Error) {
message = process.env.NODE_ENV === 'production' ? err.message : err.stack;
let message = error;
if (error.name && (error.name === 'HTTPError' || error.name === 'RequestError')) {
message = `${error.message}: target website might be blocking our access, you can <a href="https://docs.rsshub.app/install/">host your own RSSHub instance</a> for a better usability.`;
} else if (error instanceof Error) {
message = process.env.NODE_ENV === 'production' ? error.message : error.stack;
}
logger.error(`Error in ${ctx.request.path}: ${message}`);
@@ -57,7 +57,7 @@ module.exports = async (ctx, next) => {
if (config.isPackage) {
ctx.body = {
error: {
message: err.message ? err.message : err,
message: error.message ?? error,
},
};
} else {
@@ -65,12 +65,12 @@ module.exports = async (ctx, next) => {
'Content-Type': 'text/html; charset=UTF-8',
});
if (err instanceof RequestInProgressError) {
if (error instanceof RequestInProgressError) {
ctx.status = 503;
message = err.message;
message = error.message;
ctx.set('Cache-Control', `public, max-age=${config.cache.requestTimeout}`);
} else if (ctx.status === 403) {
message = err.message;
message = error.message;
} else {
ctx.status = 404;
}
@@ -112,7 +112,7 @@ module.exports = async (ctx, next) => {
scope.setTag('route', ctx._matchedRoute);
scope.setTag('name', ctx.request.path.split('/')[1]);
scope.addEventProcessor((event) => Sentry.Handlers.parseRequest(event, ctx.request));
Sentry.captureException(err);
Sentry.captureException(error);
});
}
}
+24 -36
View File
@@ -21,7 +21,7 @@ const resolveRelativeLink = ($, elem, attr, baseUrl) => {
// e.g. <video><source src="https://example.com"></video> should leave <video> unchanged
$elem.attr(attr, new URL(oldAttr, baseUrl).href);
}
} catch (e) {
} catch {
// no-empty
}
}
@@ -51,12 +51,12 @@ module.exports = async (ctx, next) => {
await next();
if (!ctx.state.data && !ctx._matchedRoute) {
throw Error('wrong path');
throw new Error('wrong path');
}
if (ctx.state.data) {
if ((!ctx.state.data.item || ctx.state.data.item.length === 0) && !ctx.state.data.allowEmpty) {
throw Error('this route is empty, please check the original site or <a href="https://github.com/DIYgod/RSSHub/issues/new/choose">create an issue</a>');
throw new Error('this route is empty, please check the original site or <a href="https://github.com/DIYgod/RSSHub/issues/new/choose">create an issue</a>');
}
// fix allowEmpty
@@ -82,12 +82,8 @@ module.exports = async (ctx, next) => {
// handle link
if (item.link) {
let baseUrl = ctx.state.data.link;
if (baseUrl && !baseUrl.match(/^https?:\/\//)) {
if (baseUrl.match(/^\/\//)) {
baseUrl = 'http:' + baseUrl;
} else {
baseUrl = 'http://' + baseUrl;
}
if (baseUrl && !/^https?:\/\//.test(baseUrl)) {
baseUrl = /^\/\//.test(baseUrl) ? 'http:' + baseUrl : 'http://' + baseUrl;
}
item.link = new URL(item.link, baseUrl).href;
@@ -98,12 +94,8 @@ module.exports = async (ctx, next) => {
const $ = cheerio.load(item.description);
let baseUrl = item.link || ctx.state.data.link;
if (baseUrl && !baseUrl.match(/^https?:\/\//)) {
if (baseUrl.match(/^\/\//)) {
baseUrl = 'http:' + baseUrl;
} else {
baseUrl = 'http://' + baseUrl;
}
if (baseUrl && !/^https?:\/\//.test(baseUrl)) {
baseUrl = /^\/\//.test(baseUrl) ? 'http:' + baseUrl : 'http://' + baseUrl;
}
$('script').remove();
@@ -128,9 +120,9 @@ module.exports = async (ctx, next) => {
}
// redundant attributes
['onclick', 'onerror', 'onload'].forEach((e) => {
for (const e of ['onclick', 'onerror', 'onload']) {
$ele.removeAttr(e);
});
}
});
// resolve relative link & fix referrer policy
@@ -170,7 +162,7 @@ module.exports = async (ctx, next) => {
return item;
};
ctx.state.data.item = await Promise.all(ctx.state.data.item.map(handleItem));
ctx.state.data.item = await Promise.all(ctx.state.data.item.map((itm) => handleItem(itm)));
if (ctx.query) {
// filter
@@ -187,7 +179,7 @@ module.exports = async (ctx, next) => {
case 're2':
return RE2JS.compile(string, insensitive ? RE2JS.CASE_INSENSITIVE : 0);
default:
throw Error(`Invalid Engine Value: ${engine}, please check your config.`);
throw new Error(`Invalid Engine Value: ${engine}, please check your config.`);
}
};
@@ -262,8 +254,8 @@ module.exports = async (ctx, next) => {
ctx.state.data.item = ctx.state.data.item.filter(({ pubDate }) => {
let isFilter = true;
try {
isFilter = !pubDate || now - new Date(pubDate).getTime() <= parseInt(ctx.query.filter_time) * 1000;
} catch (err) {
isFilter = !pubDate || now - new Date(pubDate).getTime() <= Number.parseInt(ctx.query.filter_time) * 1000;
} catch {
// no-empty
}
return isFilter;
@@ -272,7 +264,7 @@ module.exports = async (ctx, next) => {
// limit
if (ctx.query.limit) {
ctx.state.data.item = ctx.state.data.item.slice(0, parseInt(ctx.query.limit));
ctx.state.data.item = ctx.state.data.item.slice(0, Number.parseInt(ctx.query.limit));
}
// telegram instant view
@@ -299,7 +291,7 @@ module.exports = async (ctx, next) => {
html: $.html(),
});
return result;
} catch (e) {
} catch {
// no-empty
}
});
@@ -328,7 +320,7 @@ module.exports = async (ctx, next) => {
if (summary !== '') {
item.description = summary + '<hr/><br/>' + item.description;
}
} catch (e) {
} catch {
// when openai failed, return default description and not write cache
}
}
@@ -347,32 +339,28 @@ module.exports = async (ctx, next) => {
// opencc
if (ctx.query.opencc) {
ctx.state.data.item.forEach((item) => {
for (const item of ctx.state.data.item) {
item.title = simplecc(item.title ?? item.link, ctx.query.opencc);
item.description = simplecc(item.description ?? item.title ?? item.link, ctx.query.opencc);
});
}
}
// brief
if (ctx.query.brief) {
const num = /[1-9]\d{2,}/;
if (num.test(ctx.query.brief)) {
ctx.query.brief = parseInt(ctx.query.brief);
ctx.state.data.item.forEach((item) => {
ctx.query.brief = Number.parseInt(ctx.query.brief);
for (const item of ctx.state.data.item) {
let text;
if (item.description) {
text = item.description.replace(/<\/?[^>]+(>|$)/g, '');
text = item.description.replaceAll(/<\/?[^>]+(>|$)/g, '');
}
if (text?.length) {
if (text.length > ctx.query.brief) {
item.description = `<p>${text.substring(0, ctx.query.brief)}…</p>`;
} else {
item.description = `<p>${text}</p>`;
}
item.description = text.length > ctx.query.brief ? `<p>${text.substring(0, ctx.query.brief)}…</p>` : `<p>${text}</p>`;
}
});
}
} else {
throw Error(`Invalid parameter brief. Please check the doc https://docs.rsshub.app/parameter#shu-chu-jian-xun`);
throw new Error(`Invalid parameter brief. Please check the doc https://docs.rsshub.app/parameter#shu-chu-jian-xun`);
}
}
+38 -42
View File
@@ -22,11 +22,7 @@ module.exports = async (ctx, next) => {
ctx.set({
'Content-Type': 'application/json; charset=UTF-8',
});
if (ctx.state.json) {
ctx.body = JSON.stringify(ctx.state.json, null, 4);
} else {
ctx.body = JSON.stringify({ message: 'plugin does not set debug json' });
}
ctx.body = ctx.state.json ? JSON.stringify(ctx.state.json, null, 4) : JSON.stringify({ message: 'plugin does not set debug json' });
}
if (outputType.endsWith('.debug.html')) {
@@ -34,12 +30,8 @@ module.exports = async (ctx, next) => {
'Content-Type': 'text/html; charset=UTF-8',
});
const index = parseInt(outputType.match(/(\d+)\.debug\.html$/)[1]);
if (!(ctx.state.data && ctx.state.data.item && ctx.state.data.item[index])) {
ctx.body = `ctx.state.data.item[${index}] not found`;
} else {
ctx.body = ctx.state.data.item[index].description;
}
const index = Number.parseInt(outputType.match(/(\d+)\.debug\.html$/)[1]);
ctx.body = ctx.state.data && ctx.state.data.item && ctx.state.data.item[index] ? ctx.state.data.item[index].description : `ctx.state.data.item[${index}] not found`;
}
}
@@ -49,55 +41,59 @@ module.exports = async (ctx, next) => {
if (ctx.state.data) {
const collapseWhitespaceForProperties = (properties, obj) => {
properties.forEach((prop) => {
for (const prop of properties) {
if (obj[prop]) {
obj[prop] = collapseWhitespace(obj[prop]);
}
});
}
};
collapseWhitespaceForProperties(['title', 'subtitle', 'author'], ctx.state.data);
ctx.state.data.item?.forEach((item) => {
if (item.title) {
item.title = collapseWhitespace(item.title);
// trim title length
for (let length = 0, i = 0; i < item.title.length; i++) {
length += Buffer.from(item.title[i]).length !== 1 ? 2 : 1;
if (length > config.titleLengthLimit) {
item.title = `${item.title.slice(0, i)}...`;
break;
if (ctx.state.data.item) {
for (const item of ctx.state.data.item) {
if (item.title) {
item.title = collapseWhitespace(item.title);
// trim title length
for (let length = 0, i = 0; i < item.title.length; i++) {
length += Buffer.from(item.title[i]).length === 1 ? 1 : 2;
if (length > config.titleLengthLimit) {
item.title = `${item.title.slice(0, i)}...`;
break;
}
}
}
}
if (typeof item.author === 'string') {
item.author = collapseWhitespace(item.author);
} else if (typeof item.author === 'object' && item.author !== null) {
item.author.forEach((a) => (a.name = collapseWhitespace(a.name)));
if (outputType !== 'json') {
item.author = item.author.map((a) => a.name).join(', ');
if (typeof item.author === 'string') {
item.author = collapseWhitespace(item.author);
} else if (typeof item.author === 'object' && item.author !== null) {
for (const a of item.author) {
a.name = collapseWhitespace(a.name);
}
if (outputType !== 'json') {
item.author = item.author.map((a) => a.name).join(', ');
}
}
if (item.itunes_duration && ((typeof item.itunes_duration === 'string' && !item.itunes_duration.includes(':')) || (typeof item.itunes_duration === 'number' && !isNaN(item.itunes_duration)))) {
item.itunes_duration = +item.itunes_duration;
item.itunes_duration =
Math.floor(item.itunes_duration / 3600) + ':' + (Math.floor((item.itunes_duration % 3600) / 60) / 100).toFixed(2).slice(-2) + ':' + (((item.itunes_duration % 3600) % 60) / 100).toFixed(2).slice(-2);
}
if (outputType !== 'rss') {
item.pubDate = convertDateToISO8601(item.pubDate);
item.updated = convertDateToISO8601(item.updated);
}
}
if (item.itunes_duration && ((typeof item.itunes_duration === 'string' && item.itunes_duration.indexOf(':') === -1) || (typeof item.itunes_duration === 'number' && !isNaN(item.itunes_duration)))) {
item.itunes_duration = +item.itunes_duration;
item.itunes_duration =
Math.floor(item.itunes_duration / 3600) + ':' + (Math.floor((item.itunes_duration % 3600) / 60) / 100).toFixed(2).slice(-2) + ':' + (((item.itunes_duration % 3600) % 60) / 100).toFixed(2).slice(-2);
}
if (outputType !== 'rss') {
item.pubDate = convertDateToISO8601(item.pubDate);
item.updated = convertDateToISO8601(item.updated);
}
});
}
}
const currentDate = new Date();
const data = {
lastBuildDate: currentDate.toUTCString(),
updated: currentDate.toISOString(),
ttl: (config.cache.routeExpire / 60) | 0,
ttl: Math.trunc(config.cache.routeExpire / 60),
atomlink: ctx.request.href,
...ctx.state.data,
};
+1 -1
View File
@@ -2,5 +2,5 @@
// https://stackoverflow.com/questions/1497885/remove-control-characters-from-php-string/1497928#1497928
module.exports = async (ctx, next) => {
await next();
ctx.body = typeof ctx.body !== 'object' ? ctx.body.replace(/[\x00-\x09\x0B\x0C\x0E-\x1F\x7F]/g, '') : ctx.body;
ctx.body = typeof ctx.body === 'object' ? ctx.body : ctx.body.replaceAll(/[\u0000-\u0009\u000B\u000C\u000E-\u001F\u007F]/g, '');
};
+3 -3
View File
@@ -461,7 +461,7 @@ module.exports = {
docs: 'https://docs.rsshub.app/routes/multimedia#onejav',
source: '/',
target: (params, url, document) => {
const today = document.querySelector('div.card.mb-1.card-overview').getAttribute('data-date').replace(/-/g, '');
const today = document.querySelector('div.card.mb-1.card-overview').dataset.date.replaceAll('-', '');
return `/onejav/day/${today}`;
},
},
@@ -509,7 +509,7 @@ module.exports = {
} else {
return false;
}
return `/sexinsex/${pid}/${typeid ? typeid : ''}`;
return `/sexinsex/${pid}/${typeid ?? ''}`;
},
},
],
@@ -524,7 +524,7 @@ module.exports = {
target: (params, url) => {
const id = new URL(url).searchParams.get('fid');
const type = new URL(url).searchParams.get('type');
return `/t66y/${id}/${type ? type : ''}`;
return `/t66y/${id}/${type ?? ''}`;
},
},
],
+23 -23
View File
@@ -1,75 +1,75 @@
const dirname = __dirname + '/v2';
const fs = require('fs');
const toSource = require('tosource');
const { join } = require('path');
const path = require('path');
// Namespaces that do not require radar.js
const allowNamespace = ['discourse', 'discuz', 'ehentai', 'lemmy', 'mail', 'test'];
const allowNamespace = new Set(['discourse', 'discuz', 'ehentai', 'lemmy', 'mail', 'test']);
// Check if a radar.js file is exist under each folder of dirname
for (const dir of fs.readdirSync(dirname)) {
const dirPath = join(dirname, dir);
if (!fs.existsSync(join(dirPath, 'radar.js')) && !allowNamespace.includes(dir)) {
throw Error(`No radar.js in "${dirPath}".`);
const dirPath = path.join(dirname, dir);
if (!fs.existsSync(path.join(dirPath, 'radar.js')) && !allowNamespace.has(dir)) {
throw new Error(`No radar.js in "${dirPath}".`);
}
}
const validateRadarRules = (rule, dir) => {
const allowDomains = ['www.gov.cn'];
const allowDomains = new Set(['www.gov.cn']);
const blockWords = ['/', 'http', 'www'];
const domain = Object.keys(rule);
if (!domain.length && !allowNamespace.includes(dir)) {
if (!domain.length && !allowNamespace.has(dir)) {
// typo check e.g., ✘ module.export, ✔ module.exports
throw Error(`No Radar rule in "${dir}".`);
throw new Error(`No Radar rule in "${dir}".`);
}
for (const [d, r] of Object.entries(rule)) {
if (blockWords.some((word) => d.startsWith(word)) && !allowDomains.includes(d)) {
throw Error(`Domain name "${d}" should not contain any of ${blockWords.join(', ')}.`);
if (blockWords.some((word) => d.startsWith(word)) && !allowDomains.has(d)) {
throw new Error(`Domain name "${d}" should not contain any of ${blockWords.join(', ')}.`);
}
if (!r.hasOwnProperty('_name')) {
throw Error(`No _name in "${dir}".`);
if (!Object.hasOwn(r, '_name')) {
throw new Error(`No _name in "${dir}".`);
}
// property check
for (const [host, items] of Object.entries(r)) {
if (host !== '_name') {
if (!Array.isArray(items)) {
throw Error(`Radar rules for domain "${host}" in "${dir}" should be placed in an array.`);
throw new TypeError(`Radar rules for domain "${host}" in "${dir}" should be placed in an array.`);
}
for (const item of items) {
if (!item.hasOwnProperty('title') || !item.hasOwnProperty('docs')) {
throw Error(`Radar rules for "${host}" in "${dir}" should have at least "title" and "docs".`);
if (!Object.hasOwn(item, 'title') || !Object.hasOwn(item, 'docs')) {
throw new Error(`Radar rules for "${host}" in "${dir}" should have at least "title" and "docs".`);
}
if (!item.title || !item.docs) {
throw Error(`Radar rules for "${host}" in "${dir}" should not be empty.`);
throw new Error(`Radar rules for "${host}" in "${dir}" should not be empty.`);
}
if (!item.docs.startsWith('https://docs.rsshub.app/')) {
throw Error(`Radar rules for "${host}" in "${dir}" should start with 'https://docs.rsshub.app/'.`);
throw new Error(`Radar rules for "${host}" in "${dir}" should start with 'https://docs.rsshub.app/'.`);
}
if (Array.isArray(item.source)) {
if (!item.source.length) {
// check for []
throw Error(`Radar rule of "${item.title}" for subdomain "${host}" in "${dir}" should not be empty.`);
throw new Error(`Radar rule of "${item.title}" for subdomain "${host}" in "${dir}" should not be empty.`);
}
if (item.source.some((s) => s.includes('#') || s.includes('='))) {
// Some will try to match '/some/path?a=1' which is not supported
throw Error(`Radar rule of "${item.title}" for subdomain "${host}" in "${dir}" cannot match URL hash or URL search parameters.`);
throw new Error(`Radar rule of "${item.title}" for subdomain "${host}" in "${dir}" cannot match URL hash or URL search parameters.`);
}
if (item.source.some((s) => !s.length)) {
// check for ['/some/thing', ''] and ['']
throw Error(`Radar rule of "${item.title}" for subdomain "${host}" in "${dir}" should not be empty.`);
throw new Error(`Radar rule of "${item.title}" for subdomain "${host}" in "${dir}" should not be empty.`);
}
}
if (typeof item.source === 'string') {
if (!item.source.length) {
// check for ''
throw Error(`Radar rule of "${item.title}" for subdomain "${host}" in "${dir}" should not be empty.`);
throw new Error(`Radar rule of "${item.title}" for subdomain "${host}" in "${dir}" should not be empty.`);
}
if (item.source.includes('#') || item.source.includes('=')) {
throw Error(`Radar rule of "${item.title}" for subdomain "${host}" in "${dir}" cannot match URL hash or URL search parameters.`);
throw new Error(`Radar rule of "${item.title}" for subdomain "${host}" in "${dir}" cannot match URL hash or URL search parameters.`);
}
}
for (const key in item) {
if (key !== 'title' && key !== 'docs' && key !== 'source' && key !== 'target') {
throw Error(`Radar rules for "${host}" in "${dir}" should not have property "${key}".`);
throw new Error(`Radar rules for "${host}" in "${dir}" should not have property "${key}".`);
}
}
}
+31 -31
View File
@@ -53,12 +53,12 @@ router.get('/huya/live/:id', lazyloadRouteHandler('./routes/huya/live'));
router.get('/fdroid/apprelease/:app', lazyloadRouteHandler('./routes/fdroid/apprelease'));
// konachan
router.get('/konachan/post/popular_recent', lazyloadRouteHandler('./routes/konachan/post_popular_recent'));
router.get('/konachan.com/post/popular_recent', lazyloadRouteHandler('./routes/konachan/post_popular_recent'));
router.get('/konachan.net/post/popular_recent', lazyloadRouteHandler('./routes/konachan/post_popular_recent'));
router.get('/konachan/post/popular_recent/:period', lazyloadRouteHandler('./routes/konachan/post_popular_recent'));
router.get('/konachan.com/post/popular_recent/:period', lazyloadRouteHandler('./routes/konachan/post_popular_recent'));
router.get('/konachan.net/post/popular_recent/:period', lazyloadRouteHandler('./routes/konachan/post_popular_recent'));
router.get('/konachan/post/popular_recent', lazyloadRouteHandler('./routes/konachan/post-popular-recent'));
router.get('/konachan.com/post/popular_recent', lazyloadRouteHandler('./routes/konachan/post-popular-recent'));
router.get('/konachan.net/post/popular_recent', lazyloadRouteHandler('./routes/konachan/post-popular-recent'));
router.get('/konachan/post/popular_recent/:period', lazyloadRouteHandler('./routes/konachan/post-popular-recent'));
router.get('/konachan.com/post/popular_recent/:period', lazyloadRouteHandler('./routes/konachan/post-popular-recent'));
router.get('/konachan.net/post/popular_recent/:period', lazyloadRouteHandler('./routes/konachan/post-popular-recent'));
// PornHub
// router.get('/pornhub/category/:caty', lazyloadRouteHandler('./routes/pornhub/category'));
@@ -69,8 +69,8 @@ router.get('/konachan.net/post/popular_recent/:period', lazyloadRouteHandler('./
// router.get('/pornhub/:language?/pornstar/:username/:sort?', lazyloadRouteHandler('./routes/pornhub/pornstar'));
// yande.re
router.get('/yande.re/post/popular_recent', lazyloadRouteHandler('./routes/yande.re/post_popular_recent'));
router.get('/yande.re/post/popular_recent/:period', lazyloadRouteHandler('./routes/yande.re/post_popular_recent'));
router.get('/yande.re/post/popular_recent', lazyloadRouteHandler('./routes/yande.re/post-popular-recent'));
router.get('/yande.re/post/popular_recent/:period', lazyloadRouteHandler('./routes/yande.re/post-popular-recent'));
// EZTV
router.get('/eztv/torrents/:imdb_id', lazyloadRouteHandler('./routes/eztv/imdb'));
@@ -173,9 +173,9 @@ router.get('/dpu/wlfw/news/:type?', lazyloadRouteHandler('./routes/universities/
router.get('/njtech/jwc', lazyloadRouteHandler('./routes/universities/njtech/jwc'));
// 河海大学
router.get('/hhu/libNews', lazyloadRouteHandler('./routes/universities/hhu/libNews'));
router.get('/hhu/libNews', lazyloadRouteHandler('./routes/universities/hhu/lib-news'));
// 河海大学常州校区
router.get('/hhu/libNewsc', lazyloadRouteHandler('./routes/universities/hhu/libNewsc'));
router.get('/hhu/libNewsc', lazyloadRouteHandler('./routes/universities/hhu/lib-newsc'));
// 上海科技大学
router.get('/shanghaitech/activity', lazyloadRouteHandler('./routes/universities/shanghaitech/activity'));
@@ -197,8 +197,8 @@ router.get('/thu/:type', lazyloadRouteHandler('./routes/universities/thu/index')
router.get('/shou/www/:type', lazyloadRouteHandler('./routes/universities/shou/www'));
// 西南科技大学
router.get('/swust/jwc/news', lazyloadRouteHandler('./routes/universities/swust/jwc_news'));
router.get('/swust/jwc/notice/:type?', lazyloadRouteHandler('./routes/universities/swust/jwc_notice'));
router.get('/swust/jwc/news', lazyloadRouteHandler('./routes/universities/swust/jwc-news'));
router.get('/swust/jwc/notice/:type?', lazyloadRouteHandler('./routes/universities/swust/jwc-notice'));
router.get('/swust/cs/:type?', lazyloadRouteHandler('./routes/universities/swust/cs'));
// UTdallas ISSO
@@ -308,7 +308,7 @@ router.get('/lyu/news/:type', lazyloadRouteHandler('./routes/universities/lyu/ne
// 福州大学
router.get('/fzu/:type', lazyloadRouteHandler('./routes/universities/fzu/news'));
router.get('/fzu_min/:type', lazyloadRouteHandler('./routes/universities/fzu/news_min'));
router.get('/fzu_min/:type', lazyloadRouteHandler('./routes/universities/fzu/news-min'));
// 厦门大学
router.get('/xmu/aero/:type', lazyloadRouteHandler('./routes/universities/xmu/aero'));
@@ -358,7 +358,7 @@ router.get('/parcel/hermesuk/:tracking', lazyloadRouteHandler('./routes/parcel/h
// 数字尾巴
router.get('/dgtle', lazyloadRouteHandler('./routes/dgtle/index'));
router.get('/dgtle/whale/category/:category', lazyloadRouteHandler('./routes/dgtle/whale'));
router.get('/dgtle/whale/rank/:type/:rule', lazyloadRouteHandler('./routes/dgtle/whale_rank'));
router.get('/dgtle/whale/rank/:type/:rule', lazyloadRouteHandler('./routes/dgtle/whale-rank'));
router.get('/dgtle/trade/:typeId?', lazyloadRouteHandler('./routes/dgtle/trade'));
router.get('/dgtle/trade/search/:keyword', lazyloadRouteHandler('./routes/dgtle/keyword'));
@@ -429,11 +429,11 @@ router.get('/testerhome/newest', lazyloadRouteHandler('./routes/testerhome/newes
router.get('/coolbuy/newest', lazyloadRouteHandler('./routes/coolbuy/newest'));
// MiniFlux
router.get('/miniflux/subscription/:parameters?', lazyloadRouteHandler('./routes/miniflux/get_feeds'));
router.get('/miniflux/:feeds/:parameters?', lazyloadRouteHandler('./routes/miniflux/get_entries'));
router.get('/miniflux/subscription/:parameters?', lazyloadRouteHandler('./routes/miniflux/get-feeds'));
router.get('/miniflux/:feeds/:parameters?', lazyloadRouteHandler('./routes/miniflux/get-entries'));
// 動畫瘋
router.get('/anigamer/new_anime', lazyloadRouteHandler('./routes/anigamer/new_anime'));
router.get('/anigamer/new_anime', lazyloadRouteHandler('./routes/anigamer/new-anime'));
router.get('/anigamer/anime/:sn', lazyloadRouteHandler('./routes/anigamer/anime'));
// 中国药科大学
@@ -567,7 +567,7 @@ router.get('/ui-cn/user/:id', lazyloadRouteHandler('./routes/ui-cn/user'));
// 一些博客
// 敬维-以认真的态度做完美的事情: https://jingwei.link/
router.get('/blogs/jingwei.link', lazyloadRouteHandler('./routes/blogs/jingwei_link'));
router.get('/blogs/jingwei.link', lazyloadRouteHandler('./routes/blogs/jingwei-link'));
// 王垠的博客-当然我在扯淡
router.get('/blogs/wangyin', lazyloadRouteHandler('./routes/blogs/wangyin'));
@@ -695,7 +695,7 @@ router.get('/aqicn/:city/:pollution?', lazyloadRouteHandler('./routes/aqicn/inde
// 猫眼电影
router.get('/maoyan/hot', lazyloadRouteHandler('./routes/maoyan/hot'));
router.get('/maoyan/upcoming', lazyloadRouteHandler('./routes/maoyan/upcoming'));
router.get('/maoyan/hotComplete/:orderby?/:ascOrDesc?/:top?', lazyloadRouteHandler('./routes/maoyan/hotComplete'));
router.get('/maoyan/hotComplete/:orderby?/:ascOrDesc?/:top?', lazyloadRouteHandler('./routes/maoyan/hot-complete'));
// 国家退伍士兵信息
router.get('/gov/veterans/:type', lazyloadRouteHandler('./routes/gov/veterans/china'));
@@ -779,8 +779,8 @@ router.get('/simonsfoundation/recommend', lazyloadRouteHandler('./routes/simonsf
router.get('/siren/news', lazyloadRouteHandler('./routes/siren/index'));
// 学堂在线
router.get('/xuetangx/course/:cid/:type', lazyloadRouteHandler('./routes/xuetangx/course_info'));
router.get('/xuetangx/course/list/:mode/:credential/:status/:type?', lazyloadRouteHandler('./routes/xuetangx/course_list'));
router.get('/xuetangx/course/:cid/:type', lazyloadRouteHandler('./routes/xuetangx/course-info'));
router.get('/xuetangx/course/list/:mode/:credential/:status/:type?', lazyloadRouteHandler('./routes/xuetangx/course-list'));
// 正版中国
// router.get('/getitfree/category/:category?', lazyloadRouteHandler('./routes/getitfree/category.js'));
@@ -951,11 +951,11 @@ router.get('/emi-nitta/:type', lazyloadRouteHandler('./routes/emi-nitta/home'));
router.get('/vscode/marketplace/:type?', lazyloadRouteHandler('./routes/vscode/marketplace'));
// 饭否
router.get('/fanfou/user_timeline/:uid', lazyloadRouteHandler('./routes/fanfou/user_timeline'));
router.get('/fanfou/home_timeline', lazyloadRouteHandler('./routes/fanfou/home_timeline'));
router.get('/fanfou/user_timeline/:uid', lazyloadRouteHandler('./routes/fanfou/user-timeline'));
router.get('/fanfou/home_timeline', lazyloadRouteHandler('./routes/fanfou/home-timeline'));
router.get('/fanfou/favorites/:uid', lazyloadRouteHandler('./routes/fanfou/favorites'));
router.get('/fanfou/trends', lazyloadRouteHandler('./routes/fanfou/trends'));
router.get('/fanfou/public_timeline/:keyword', lazyloadRouteHandler('./routes/fanfou/public_timeline'));
router.get('/fanfou/public_timeline/:keyword', lazyloadRouteHandler('./routes/fanfou/public-timeline'));
// Remote Work
router.get('/remote-work/:caty?', lazyloadRouteHandler('./routes/remote-work/index'));
@@ -965,7 +965,7 @@ router.get('/chocolatey/software/:name?', lazyloadRouteHandler('./routes/chocola
// 巴哈姆特
router.get('/bahamut/creation/:author/:category?', lazyloadRouteHandler('./routes/bahamut/creation'));
router.get('/bahamut/creation_index/:category?/:subcategory?/:type?', lazyloadRouteHandler('./routes/bahamut/creation_index'));
router.get('/bahamut/creation_index/:category?/:subcategory?/:type?', lazyloadRouteHandler('./routes/bahamut/creation-index'));
// CentBrowser
router.get('/centbrowser/history', lazyloadRouteHandler('./routes/centbrowser/history'));
@@ -1065,7 +1065,7 @@ router.get('/haohaozhu/discover/:keyword?', lazyloadRouteHandler('./routes/haoha
// 魔法纪录
router.get('/magireco/announcements', lazyloadRouteHandler('./routes/magireco/announcements'));
router.get('/magireco/event_banner', lazyloadRouteHandler('./routes/magireco/event_banner'));
router.get('/magireco/event_banner', lazyloadRouteHandler('./routes/magireco/event-banner'));
// 我有一片芝麻地
router.get('/blogs/hedwig/:type', lazyloadRouteHandler('./routes/blogs/hedwig'));
@@ -1450,7 +1450,7 @@ router.get('/dw/:lang?/:caty?', lazyloadRouteHandler('./routes/dw/index'));
router.get('/citavi/:caty?', lazyloadRouteHandler('./routes/citavi/index'));
// Sesame
router.get('/sesame/release_notes', lazyloadRouteHandler('./routes/sesame/release_notes'));
router.get('/sesame/release_notes', lazyloadRouteHandler('./routes/sesame/release-notes'));
// QNAP
router.get('/qnap/release-notes/:id', lazyloadRouteHandler('./routes/qnap/release-notes'));
@@ -1475,7 +1475,7 @@ router.get('/grandchallenge/challenges', lazyloadRouteHandler('./routes/grandcha
router.get('/nwpu/:column', lazyloadRouteHandler('./routes/nwpu/index'));
// 美国联邦最高法院
router.get('/us/supremecourt/argument_audio/:year?', lazyloadRouteHandler('./routes/us/supremecourt/argument_audio'));
router.get('/us/supremecourt/argument_audio/:year?', lazyloadRouteHandler('./routes/us/supremecourt/argument-audio'));
// 优设网
router.get('/uisdc/hangye/:caty?', lazyloadRouteHandler('./routes/uisdc/hangye'));
@@ -1574,7 +1574,7 @@ router.get('/marginnote/tag/:id?', lazyloadRouteHandler('./routes/marginnote/tag
router.get('/asml/press-releases', lazyloadRouteHandler('./routes/asml/press-releases'));
// 有趣天文奇观
router.get('/interesting-sky/astronomical_events/:year?', lazyloadRouteHandler('./routes/interesting-sky/astronomical_events'));
router.get('/interesting-sky/astronomical_events/:year?', lazyloadRouteHandler('./routes/interesting-sky/astronomical-events'));
router.get('/interesting-sky/recent-interesting', lazyloadRouteHandler('./routes/interesting-sky/recent-interesting'));
router.get('/interesting-sky', lazyloadRouteHandler('./routes/interesting-sky/index'));
@@ -1704,8 +1704,8 @@ router.get('/furaffinity/journals/:username', lazyloadRouteHandler('./routes/fur
router.get('/furaffinity/gallery/:username/:nsfw?', lazyloadRouteHandler('./routes/furaffinity/gallery'));
router.get('/furaffinity/scraps/:username/:nsfw?', lazyloadRouteHandler('./routes/furaffinity/scraps'));
router.get('/furaffinity/favorites/:username/:nsfw?', lazyloadRouteHandler('./routes/furaffinity/favorites'));
router.get('/furaffinity/submission_comments/:id', lazyloadRouteHandler('./routes/furaffinity/submission_comments'));
router.get('/furaffinity/journal_comments/:id', lazyloadRouteHandler('./routes/furaffinity/journal_comments'));
router.get('/furaffinity/submission_comments/:id', lazyloadRouteHandler('./routes/furaffinity/submission-comments'));
router.get('/furaffinity/journal_comments/:id', lazyloadRouteHandler('./routes/furaffinity/journal-comments'));
// Trakt.tv
router.get('/trakt/collection/:username/:type?', lazyloadRouteHandler('./routes/trakt/collection'));
+1 -1
View File
@@ -17,7 +17,7 @@ module.exports = async (ctx) => {
description: `<img src="${$(item).find('img').attr('src')}" /> <br>
${$(item).find('div.p-row').text()}`,
link: $(item).find('h3 > a').attr('href'),
pubDate: new Date($(item).find('span.fr.time').text().trim().substr(0, 4), $(item).find('span.fr.time').text().trim().substr(5, 2), $(item).find('span.fr.time').text().trim().substr(8, 4)).toUTCString(),
pubDate: new Date($(item).find('span.fr.time').text().trim().slice(0, 4), $(item).find('span.fr.time').text().trim().slice(5, 7), $(item).find('span.fr.time').text().trim().slice(8, 12)).toUTCString(),
}))
.get(),
};
+2 -2
View File
@@ -32,7 +32,7 @@ module.exports = async (ctx) => {
const cache = await ctx.cache.get(link);
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const description = await ProcessFeed(link);
@@ -46,7 +46,7 @@ module.exports = async (ctx) => {
};
ctx.cache.set(link, JSON.stringify(single));
return Promise.resolve(single);
return single;
})
);
+1 -1
View File
@@ -6,7 +6,7 @@ module.exports = async (ctx) => {
method: 'get',
url: currentUrl,
});
const data = JSON.parse(response.data.substr('var alertData ='.length, response.data.length + 1));
const data = JSON.parse(response.data.slice('var alertData ='.length, 'var alertData ='.length + response.data.length + 1));
const list = data.map((item) => ({
title: item.headline,
+3 -3
View File
@@ -22,7 +22,7 @@ module.exports = async (ctx) => {
list.map(async (link) => {
const cache = await ctx.cache.get(link);
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const response = await got({
@@ -47,7 +47,7 @@ module.exports = async (ctx) => {
const $el = $(element);
const img_original_data = $el.attr('data-original');
const img_src = $el.attr('src');
if (typeof img_src === 'undefined' && img_original_data) {
if (img_src === undefined && img_original_data) {
$el.attr('src', img_original_data);
}
});
@@ -62,7 +62,7 @@ module.exports = async (ctx) => {
};
ctx.cache.set(link, JSON.stringify(single));
return Promise.resolve(single);
return single;
})
);
+3 -3
View File
@@ -17,7 +17,7 @@ module.exports = async (ctx) => {
const address = $(item).attr('href');
const cache = await ctx.cache.get(address);
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const res = await got.get(address);
const capture = cheerio.load(res.data);
@@ -33,7 +33,7 @@ module.exports = async (ctx) => {
intro +
capture('.transcript__inner')
.html()
.replace(/<p>\[?<em>\(?The above text.*this podcast.*?em.*?p>/g, '');
.replaceAll(/<p>\[?<em>\(?The above text.*this podcast.*?em.*?p>/g, '');
const track = capture('.podcasts__media > div > a').attr('href');
const single = {
title,
@@ -46,7 +46,7 @@ module.exports = async (ctx) => {
pubDate: new Date(time).toUTCString(),
};
ctx.cache.set(address, JSON.stringify(single));
return Promise.resolve(single);
return single;
})
);
ctx.state.data = {
+3 -3
View File
@@ -29,13 +29,13 @@ module.exports = async (ctx) => {
.map((item) => {
switch (item.bodyType) {
case 1:
return `<p>${item.text.replace(/\n/gm, '<br/>')}</p>`;
return `<p>${item.text.replaceAll(/\n/gm, '<br/>')}</p>`;
case 2:
return `<img src="${item.image}">`;
case 3:
return `<img src="${item.image}">`;
case 4:
return `<blockquote>${item.comment.user.name}:<br/>${item.comment.comment.body.replace(/\n/gm, '<br/>')}</blockquote>`;
return `<blockquote>${item.comment.user.name}:<br/>${item.comment.comment.body.replaceAll(/\n/gm, '<br/>')}</blockquote>`;
case 7:
return `<blockquote>${item.talk.name}:<br/>${GetContent(item.post)}</blockquote>`;
case 8:
@@ -49,7 +49,7 @@ module.exports = async (ctx) => {
const GetTitle = (post) => {
const texts = post.body.filter((s) => s.bodyType === 1);
const type_name = postTypes[post.postType];
return texts.length !== 0 ? texts[0].text.split('\n')[0] : type_name;
return texts.length === 0 ? type_name : texts[0].text.split('\n')[0];
};
const ProcessFeed = (data) =>
+2 -2
View File
@@ -20,7 +20,7 @@ module.exports = async (ctx) => {
.map(async (itemUrl) => {
const cache = await ctx.cache.get(itemUrl);
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const response = await got.get(itemUrl);
@@ -34,7 +34,7 @@ module.exports = async (ctx) => {
pubDate: new Date($('article header .entry-meta time').text()).toUTCString(),
};
ctx.cache.set(itemUrl, JSON.stringify(single));
return Promise.resolve(single);
return single;
})
);
+2 -2
View File
@@ -17,7 +17,7 @@ module.exports = async (ctx) => {
.map(async (_, item) => {
item = $(item);
const year = item.find('span').text().replace(/\(|\)/g, '');
const year = item.find('span').text().replaceAll(/\(|\)/g, '');
const pubDate = new Date(`${year}-12-31`).toUTCString();
const winnersUrls = [];
@@ -47,7 +47,7 @@ module.exports = async (ctx) => {
winnerDescription += image + column.html();
}
return Promise.resolve(winnerDescription);
return winnerDescription;
});
return {
+2 -2
View File
@@ -25,7 +25,7 @@ module.exports = async (ctx) => {
const cache = await ctx.cache.get(link);
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const response = await got({
@@ -41,7 +41,7 @@ module.exports = async (ctx) => {
link,
};
ctx.cache.set(link, JSON.stringify(single));
return Promise.resolve(single);
return single;
})
);
ctx.state.data = { title: '路由器交流', link: baseUrl, item: out };
+1 -6
View File
@@ -18,12 +18,7 @@ const config = {
};
module.exports = async (ctx) => {
let cfg;
if (ctx.params.type) {
cfg = config[ctx.params.type];
} else {
cfg = config.index;
}
const cfg = ctx.params.type ? config[ctx.params.type] : config.index;
const response = await got({
method: 'get',
+25 -21
View File
@@ -6,11 +6,7 @@ module.exports = async (ctx) => {
let url = 'https://api.yanxishe.com/api?page=1&size=30&parent_tag=';
if (id === 'all') {
url += '&tag=';
} else {
url += `&tag=${id}`;
}
url += id === 'all' ? '&tag=' : `&tag=${id}`;
if (sort === 'hot') {
url += '&is_hot=1&is_recommend=0';
} else if (sort === 'recommend') {
@@ -35,11 +31,7 @@ module.exports = async (ctx) => {
case 'blog': // 博客
description = data.content;
author = data.user.nickname;
if (data.relation_special) {
link = `https://www.yanxishe.com/columnDetail/${id}`;
} else {
link = `https://www.yanxishe.com/blogDetail/${id}`;
}
link = data.relation_special ? `https://www.yanxishe.com/columnDetail/${id}` : `https://www.yanxishe.com/blogDetail/${id}`;
break;
case 'question': // 问答
description = data.content;
@@ -48,9 +40,9 @@ module.exports = async (ctx) => {
break;
case 'article': // 翻译
description = `<table><tr><td width="50%"> ${data.title} </td><td> ${data.zh_title} </td></tr>`;
data.paragraphs.forEach((element) => {
for (const element of data.paragraphs) {
description += `<tr><td> ${element.content} </td><td> ${element.zh_content.content} </td></tr>`;
});
}
description += `</table>
<style>
table,
@@ -89,17 +81,29 @@ module.exports = async (ctx) => {
response.data.data.all.map(async (item) => {
let itemUrl = `https://api.yanxishe.com/api/sthread/${item.id}?token=null`;
if (item.type === 'blog') {
itemUrl += '&type=null';
} else if (item.type === 'article') {
itemUrl = `https://api.yanxishe.com/api/stranslate/article/${item.id}?token=null&type=null`;
} else if (item.type === 'paper') {
itemUrl = `https://api.yanxishe.com/api/spaper/detail?token=null&id=${item.id}`;
switch (item.type) {
case 'blog':
itemUrl += '&type=null';
break;
case 'article':
itemUrl = `https://api.yanxishe.com/api/stranslate/article/${item.id}?token=null&type=null`;
break;
case 'paper':
itemUrl = `https://api.yanxishe.com/api/spaper/detail?token=null&id=${item.id}`;
break;
default:
throw new Error(`Unknown type: ${item.type}`);
}
const cache = await ctx.cache.get(itemUrl);
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const response = await got({
@@ -112,12 +116,12 @@ module.exports = async (ctx) => {
const single = {
title: item.zh_title,
description: result.description,
pubDate: new Date(parseFloat(item.published_time + '000')).toUTCString(),
pubDate: new Date(Number.parseFloat(item.published_time + '000')).toUTCString(),
link: result.link,
author: result.author,
};
ctx.cache.set(itemUrl, JSON.stringify(single));
return Promise.resolve(single);
return single;
})
);
+1 -1
View File
@@ -1,7 +1,7 @@
const utils = require('./utils');
module.exports = async (ctx) => {
const currentUrl = `search/${ctx.params.model}/tags/${ctx.params.keyword ? ctx.params.keyword : ''}${ctx.params.sortBy ? '?sortby=' + ctx.params.sortBy : ''}`;
const currentUrl = `search/${ctx.params.model}/tags/${ctx.params.keyword ?? ''}${ctx.params.sortBy ? '?sortby=' + ctx.params.sortBy : ''}`;
ctx.state.data = await utils(ctx, currentUrl);
};
+3 -3
View File
@@ -5,7 +5,7 @@ const url = 'https://download.amd.com/drivers/xml/driver_09_us.xml';
// 06/10/2020 -> Wed Jun 10 2020 00:00:00
function convertDate(dateStr) {
const [month, day, year] = dateStr.split('/').map((x) => parseInt(x, 10));
const [month, day, year] = dateStr.split('/').map((x) => Number.parseInt(x, 10));
const date = new Date();
date.setFullYear(year, month - 1, day);
date.setHours(0, 0, 0, 0);
@@ -89,14 +89,14 @@ module.exports = async (ctx) => {
if (whql) {
try {
item.push(versionToRss(whql, false));
} catch (e) {
} catch {
// ignore
}
}
if (beta) {
try {
item.push(versionToRss(beta, true));
} catch (e) {
} catch {
// ignore
}
}
+9 -9
View File
@@ -20,7 +20,7 @@ module.exports = async (ctx) => {
const list = $('table.list tr');
// get how many new-books. amount in this page is 50
let count = parseInt(ctx.params.count);
let count = Number.parseInt(ctx.params.count);
if (Number.isNaN(count) || count < 1) {
count = 10; // default count of new-book list
} else if (count > 50) {
@@ -44,35 +44,35 @@ module.exports = async (ctx) => {
for (let i = 0; i < count; ++i) {
const $ = cheerio.load(cards[i]);
const link = $('meta[property="og:url"]').attr('content');
const link_dir = link.replace(/\/[^/]*$/g, '/');
const link_dir = link.replaceAll(/\/[^/]*$/g, '/');
const title_info = $('table[summary="タイトルデータ"] > tbody > tr');
let author = '';
let title = '';
let title_sub = '';
for (let j = 0; j < title_info.length; ++j) {
const tmp = entities.decodeXML($(title_info[j]).html()); // should convert from escaped to unicode
for (const element of title_info) {
const tmp = entities.decodeXML($(element).html()); // should convert from escaped to unicode
if (tmp.includes('作品名:')) {
title = $(title_info[j]).find('td:nth-child(2)').text();
title = $(element).find('td:nth-child(2)').text();
}
if (tmp.includes('副題:')) {
title_sub = $(title_info[j]).find('td:nth-child(2)').text();
title_sub = $(element).find('td:nth-child(2)').text();
}
if (tmp.includes('著者名:')) {
author = $(title_info[j]).find('td:nth-child(2)').text();
author = $(element).find('td:nth-child(2)').text();
}
}
if (title_sub !== '') {
title += ' —— ' + title_sub;
}
const pub_date_raw = $('table[summary="底本データ"] > tbody > tr:nth-child(3) > td:nth-child(2)').text();
const pub_date_num = pub_date_raw.replace(/.*|日/g, '').replace(/[年月]/g, '-');
const pub_date_num = pub_date_raw.replaceAll(/.*|日/g, '').replaceAll(/[年月]/g, '-');
const pub_date = new Date(pub_date_num).toUTCString();
const full_text_relative_link = $('table.download > tbody > tr:nth-child(3) > td:nth-child(3) > a').attr('href');
const full_text_link = link_dir + full_text_relative_link;
const full_text_link_html = '<a href="' + full_text_link + '">いますぐXHTML版で読む</a><br>';
const summury = $('table[summary="作品データ"]')
.html()
.replace(/href="/g, 'href="' + link_dir);
.replaceAll('href="', 'href="' + link_dir);
const item = {
title,
+2 -2
View File
@@ -15,11 +15,11 @@ module.exports = async (ctx) => {
const $ = cheerio.load(response.data);
if (ctx.params.caty === 'mostwanted') {
times.forEach((i) => {
for (const i of times) {
if (i !== ctx.params.time) {
$(`#charts-${i}`).remove();
}
});
}
}
$('i,img.play-icon-small').remove();
+2 -2
View File
@@ -21,7 +21,7 @@ module.exports = async (ctx) => {
feed.items.map(async (item) => {
const cache = await ctx.cache.get(item.link);
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const description = await ProcessFeed(item.link);
@@ -34,7 +34,7 @@ module.exports = async (ctx) => {
author: item.author,
};
ctx.cache.set(item.link, JSON.stringify(single));
return Promise.resolve(single);
return single;
})
);
+2 -6
View File
@@ -32,11 +32,7 @@ module.exports = async (ctx) => {
let currentUrl;
if (genre) {
if (category) {
if (category in categories) {
currentUrl = `${rootUrl}${categories[category]}`;
} else {
currentUrl = `${rootUrl}/${genre}/list/${category}.html`;
}
currentUrl = category in categories ? `${rootUrl}${categories[category]}` : `${rootUrl}/${genre}/list/${category}.html`;
} else {
currentUrl = `${rootUrl}/${genre}`;
}
@@ -60,7 +56,7 @@ module.exports = async (ctx) => {
const link = item.attr('href');
return {
link: link.indexOf('//') < 0 ? `${rootUrl}${link}` : `https:${link}`,
link: link.includes('//') ? `https:${link}` : `${rootUrl}${link}`,
};
})
.get();
+2 -2
View File
@@ -16,7 +16,7 @@ module.exports = async (ctx) => {
const cache = await ctx.cache.get(link);
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const response = await got.get(link);
@@ -57,7 +57,7 @@ module.exports = async (ctx) => {
link,
};
ctx.cache.set(link, JSON.stringify(single));
return Promise.resolve(single);
return single;
})
);
+4 -4
View File
@@ -1,7 +1,7 @@
const got = require('@/utils/got');
module.exports = async (ctx) => {
const keyword = ctx.params.keyword ? ctx.params.keyword : '';
const keyword = ctx.params.keyword ?? '';
let default_order, default_time;
if (keyword) {
@@ -12,9 +12,9 @@ module.exports = async (ctx) => {
default_time = 'm';
}
const order = ctx.params.order ? ctx.params.order : default_order;
const time = ctx.params.time ? ctx.params.time : default_time;
const top = ctx.params.top ? ctx.params.top : 30;
const order = ctx.params.order ?? default_order;
const time = ctx.params.time ?? default_time;
const top = ctx.params.top ?? 30;
const url = keyword ? `https://api.avgle.com/v1/search/${keyword}/0` : `https://api.avgle.com/v1/videos/0`;
const response = await got({
+60 -67
View File
@@ -3,80 +3,73 @@ const cheerio = require('cheerio');
module.exports = async (ctx) => {
const { type, tag } = ctx.params || '';
const response = await got({
method: 'get',
url: `https://axisstudiosgroup.com/${type}/${tag}`,
});
const response = await got(`https://axisstudiosgroup.com/${type}/${tag}`);
const data = response.data;
const $ = cheerio.load(data); // 使用 cheerio 加载返回的 HTML
const list = $('a.overlay-link').get().slice(0, 13);
const articledata = await Promise.all(
list.map(async (item) => {
const link = `https://axisstudiosgroup.com${$(item)
.attr('href')
.replace(/https:/, '')}`;
const cache = await ctx.cache.get(link);
if (cache) {
return Promise.resolve(JSON.parse(cache));
}
const response2 = await got({
method: 'get',
url: link,
});
const articleHtml = response2.data;
const $2 = cheerio.load(articleHtml);
$2('.slider-nav').remove(); // 图片导航
$2('.social-wrapper').remove(); // 社交按钮
$2('source').remove(); // 莫名其妙的图片
$2('video').remove(); // 视频标签
$2('button').remove(); // 按钮
$2('div.modal.fade').remove(); // 莫名奇妙的图片
$2('i').remove();
const youtube = $2('.mcdr.playlist-control a').attr('data-video-type') === 'video/youtube' ? $2('.mcdr.playlist-control a').attr('data-video-url').replace('https://www.youtube.com/watch?v=', '') : '';
const mp4 = $2('.mcdr.playlist-control a').attr('data-video-type') === 'video/mp4' ? $2('.mcdr.playlist-control a').attr('data-video-url') : '';
const content = $2('.container-fluid>div:nth-child(2)')
.html()
.replace(/<video*.+poster=/g, '<video controls="controls" poster=')
.replace(/<.?picture>/g, '')
.replace(/<picture*.+>/g, '')
.replace(/<div*.+>/g, '')
.replace(/<.?div>/g, '')
.replace(/<!--*.+-->/g, '');
const single = {
describe: content,
title: $2('.overlay-content').find('h1').text(),
link,
mp4,
youtube,
const list = $('a.overlay-link')
.toArray()
.map((item) => {
item = $(item);
return {
title: item.find('h2').text().trim(),
link: new URL(item.attr('href'), 'https://axisstudiosgroup.com').href,
};
ctx.cache.set(link, JSON.stringify(single));
return Promise.resolve(single);
})
});
const items = await Promise.all(
list.map((item) =>
ctx.cache.tryGet(item.link, async () => {
const response2 = await got(item.link);
const $2 = cheerio.load(response2.data);
$2('.slider-nav').remove(); // 图片导航
$2('.social-wrapper').remove(); // 社交按钮
$2('source').remove(); // 莫名其妙的图片
$2('video').remove(); // 视频标签
$2('button').remove(); // 按钮
$2('div.modal.fade').remove(); // 莫名奇妙的图片
$2('i').remove();
$2('*')
.contents()
.filter((_, el) => el.type === 'comment')
.remove();
const mcdrPlaylistControl = $2('.mcdr.playlist-control a');
const youtube = mcdrPlaylistControl.data('video-type') === 'video/youtube' ? mcdrPlaylistControl.data('video-url').replace('https://www.youtube.com/watch?v=', '') : '';
const mp4 = mcdrPlaylistControl.data('video-type') === 'video/mp4' ? mcdrPlaylistControl.data('video-url') : '';
const content = $2('.container-fluid>div:nth-child(2)');
content.find('video').attr('controls', 'controls');
content.find('picture').each((_, el) => {
el = $2(el);
el.replaceWith(el.html());
});
content.find('div').each((_, el) => {
el = $2(el);
if (el.children().length) {
el.replaceWith(el.children());
}
});
let video = '';
if (mp4) {
video = `<video width="100%" controls="controls" width="640" height="360" source src="${mp4}" type="video/mp4"></video><br>`;
}
if (youtube) {
video = `<iframe id="ytplayer" type="text/html" width="640" height="360" src='https://www.youtube-nocookie.com/embed/${youtube}' frameborder='0' webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe><br>`;
}
item.description = video + content.html();
return item;
})
)
);
ctx.state.data = {
title: `Axis Studios | ${type} ${tag ? tag : ''}`,
title: `Axis Studios | ${type} ${tag ?? ''}`,
link: 'http://axisstudiosgroup.com',
description: $('description').text(),
item: list.map((item, index) => {
let video = '';
if (articledata[index].mp4) {
video = `<video width="100%" controls="controls" width="640" height="360" source src="${articledata[index].mp4}" type="video/mp4"></video><br>`;
}
if (articledata[index].youtube) {
video = `<iframe id="ytplayer" type="text/html" width="640" height="360" src='https://youtube.com/embed/${articledata[index].youtube}' frameborder='0' webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe><br>`;
}
return {
title: articledata[index].title,
description: `${video}+${articledata[index].describe}`,
link: articledata[index].link,
};
}),
item: items,
};
};
+28 -10
View File
@@ -10,16 +10,34 @@ module.exports = async (ctx) => {
let link = `https://www.baby-kingdom.com/forum.php?mod=forumdisplay&fid=${id}`;
if (order === 'dateline') {
link += '&filter=author&orderby=dateline';
} else if (order === 'reply') {
link += '&filter=reply&orderby=replies';
} else if (order === 'view') {
link += '&filter=reply&orderby=views';
} else if (order === 'lastpost') {
link += '&filter=lastpost&orderby=lastpost';
} else if (order === 'heat') {
link += '&filter=heat&orderby=heats';
switch (order) {
case 'dateline':
link += '&filter=author&orderby=dateline';
break;
case 'reply':
link += '&filter=reply&orderby=replies';
break;
case 'view':
link += '&filter=reply&orderby=views';
break;
case 'lastpost':
link += '&filter=lastpost&orderby=lastpost';
break;
case 'heat':
link += '&filter=heat&orderby=heats';
break;
default:
// Do nothing
}
const response = await got.get(link);
@@ -57,16 +57,16 @@ const subcategory_map = {
};
module.exports = async (ctx) => {
const type = ctx.params.type ? ctx.params.type : '1';
const category = ctx.params.category ? ctx.params.category : '0';
const subcategory = ctx.params.subcategory ? ctx.params.subcategory : '0';
const type = ctx.params.type ?? '1';
const category = ctx.params.category ?? '0';
const subcategory = ctx.params.subcategory ?? '0';
const url = `https://home.gamer.com.tw/index.php?k1=${category}&k2=${subcategory}&vt=${type}&sm=3`;
const { items } = await utils.ProcessFeed(url, ctx);
ctx.state.data = {
title: `巴哈姆特创作大厅${category !== '0' ? ' - ' + category_map[category] : ''}${subcategory !== '0' ? ' - ' + subcategory_map[subcategory] : ''} - ${type_map[type]}`,
title: `巴哈姆特创作大厅${category === '0' ? '' : ' - ' + category_map[category]}${subcategory === '0' ? '' : ' - ' + subcategory_map[subcategory]} - ${type_map[type]}`,
link: url,
item: items,
};
+7 -7
View File
@@ -16,8 +16,8 @@ module.exports = {
const content = $('.MSG-list8C');
const images = $('img');
for (let k = 0; k < images.length; k++) {
$(images[k]).attr('src', $(images[k]).attr('data-src'));
for (const image of images) {
$(image).attr('src', $(image).attr('data-src'));
}
return {
@@ -35,7 +35,7 @@ module.exports = {
const cache = await ctx.cache.get(link);
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const topic = {
@@ -49,14 +49,14 @@ module.exports = {
const detail_response = await got.get(link);
const result = parseContent(detail_response.data);
if (!result.description) {
return Promise.resolve('');
return '';
}
topic.description = result.description;
} catch (err) {
return Promise.resolve('');
} catch {
return '';
}
ctx.cache.set(link, JSON.stringify(topic));
return Promise.resolve(topic);
return topic;
})
);
+1 -1
View File
@@ -6,7 +6,7 @@ module.exports = async (ctx) => {
const lang = ctx.params.lang || 'en';
const id = ctx.params.id || 'bandizip';
if (!isValidHost(lang)) {
throw Error('Invalid language code');
throw new Error('Invalid language code');
}
const rootUrl = `https://${lang}.bandisoft.com`;
+2 -2
View File
@@ -29,7 +29,7 @@ module.exports = async (ctx) => {
const cache = await ctx.cache.get(itemUrl);
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const response = await got.get(itemUrl);
@@ -44,7 +44,7 @@ module.exports = async (ctx) => {
pubDate: new Date(date).toUTCString(),
};
ctx.cache.set(itemUrl, JSON.stringify(single));
return Promise.resolve(single);
return single;
})
);
+2 -2
View File
@@ -16,7 +16,7 @@ module.exports = async (ctx) => {
const time = $('.Blog-meta-item--date').text();
const cache = await ctx.cache.get(address);
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const res = await got.get(address);
const capture = cheerio.load(res.data);
@@ -30,7 +30,7 @@ module.exports = async (ctx) => {
pubDate: new Date(time).toUTCString(),
};
ctx.cache.set(address, JSON.stringify(single));
return Promise.resolve(single);
return single;
})
);
ctx.state.data = {
+1 -1
View File
@@ -24,7 +24,7 @@ module.exports = async (ctx) => {
return {
title: item.text(),
link: link.indexOf('http') > -1 ? link : `${rootUrl}${link}`,
link: link.includes('http') ? link : `${rootUrl}${link}`,
};
})
.get();
+2 -2
View File
@@ -16,7 +16,7 @@ module.exports = async (ctx) => {
const itemUrl = $('a').attr('href');
const cache = await ctx.cache.get(itemUrl);
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const responses = await got.get(itemUrl);
@@ -32,7 +32,7 @@ module.exports = async (ctx) => {
description: $d('#contentStr').html(),
};
ctx.cache.set(itemUrl, JSON.stringify(single));
return Promise.resolve(single);
return single;
})
);
ctx.state.data = {
+3 -3
View File
@@ -9,7 +9,7 @@ const { isValidHost } = require('@/utils/valid-host');
module.exports = async (ctx) => {
const type = ctx.params.type;
if (!isValidHost(type)) {
throw Error('Invalid type');
throw new Error('Invalid type');
}
const url = `https://${type}.hedwig.pub`;
@@ -23,9 +23,9 @@ module.exports = async (ctx) => {
const list = content.props.pageProps.issuesByNewsletter.map((item) => {
let description = '';
item.blocks.forEach((block) => {
for (const block of item.blocks) {
description += md.render(block.markdown.text);
});
}
return {
title: item.subject,
description,
+2 -2
View File
@@ -12,7 +12,7 @@ module.exports = async (ctx) => {
const element = $(e);
const title = element.find('a').text();
const link = url + element.find('a').attr('href');
const dateraw = /\d{4}\/\d{2}\/\d{2}/.exec(link)[0];
const dateraw = /\d{4}(?:\/\d{2}){2}/.exec(link)[0];
return {
title,
@@ -30,7 +30,7 @@ module.exports = async (ctx) => {
const cache = await ctx.cache.get(link);
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const itemReponse = await got.get(link);
+5 -5
View File
@@ -1,9 +1,9 @@
const parser = require('@/utils/rss-parser');
const config = require('@/config').value;
const allowDomain = ['lawrence.code.blog'];
const allowDomain = new Set(['lawrence.code.blog']);
module.exports = async (ctx) => {
if (!config.feature.allow_user_supply_unsafe_domain && !allowDomain.includes(ctx.params.domain)) {
if (!config.feature.allow_user_supply_unsafe_domain && !allowDomain.has(ctx.params.domain)) {
ctx.throw(403, `This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
}
@@ -16,12 +16,12 @@ module.exports = async (ctx) => {
feed.items.map(async (item) => {
const cache = await ctx.cache.get(item.link);
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const description =
scheme === 'https' || !cdn
? item['content:encoded']
: item['content:encoded'].replace(/(?<=<img.*src=")(.*)(?=".*\/>)/g, (match, p) => {
: item['content:encoded'].replaceAll(/(?<=<img.*src=")(.*)(?=".*\/>)/g, (match, p) => {
if (p[0] === '/') {
return cdn + feed.link + p;
} else if (p.slice(0, 5) === 'http:') {
@@ -37,7 +37,7 @@ module.exports = async (ctx) => {
link: item.link,
author: item.creator,
};
return Promise.resolve(article);
return article;
})
);
+2 -2
View File
@@ -15,7 +15,7 @@ module.exports = async (ctx) => {
const cache = await ctx.cache.get(link);
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const response2 = await got({
@@ -39,7 +39,7 @@ module.exports = async (ctx) => {
link,
};
ctx.cache.set(link, JSON.stringify(single));
return Promise.resolve(single);
return single;
})
);
+6 -8
View File
@@ -14,7 +14,7 @@ module.exports = async (ctx) => {
const link = $(item).attr('href');
const cache = await ctx.cache.get(link);
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const response2 = await got({
method: 'get',
@@ -41,7 +41,7 @@ module.exports = async (ctx) => {
link,
};
ctx.cache.set(link, JSON.stringify(single));
return Promise.resolve(single);
return single;
})
);
@@ -50,16 +50,14 @@ module.exports = async (ctx) => {
link: 'http://blur.com',
description: $('description').text(),
item: list.map((item, index) => {
const Num = /[0-9]+/;
const Num = /\d+/;
let content = '';
const videostyle = `width="640" height="360"`;
const imgstyle = `style="max-width: 650px; height: auto; object-fit: contain; flex: 0 0 auto;"`;
content += `Client:${articledata[index].client}<br>${articledata[index].describe}`;
if (Num.test(articledata[index].mainvideo)) {
content += `<iframe ${videostyle} src='https://player.vimeo.com/video/${articledata[index].mainvideo}' frameborder='0' webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe><br>`;
} else {
content += `<iframe ${videostyle} src='https://youtube.com/embed/${articledata[index].mainvideo}' frameborder='0' webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe><br>`;
}
content += Num.test(articledata[index].mainvideo)
? `<iframe ${videostyle} src='https://player.vimeo.com/video/${articledata[index].mainvideo}' frameborder='0' webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe><br>`
: `<iframe ${videostyle} src='https://youtube.com/embed/${articledata[index].mainvideo}' frameborder='0' webkitAllowFullScreen mozallowfullscreen allowFullScreen></iframe><br>`;
if (articledata[index].images) {
for (let p = 0; p < articledata[index].images.length; p++) {
content += `<img ${imgstyle} src="${articledata[index].images[p].img}"><br>`;
+2 -4
View File
@@ -6,7 +6,7 @@ const maxPages = 5;
module.exports = async (ctx) => {
const { subdomain } = ctx.params;
if (!isValidHost(subdomain)) {
throw Error('Invalid subdomain');
throw new Error('Invalid subdomain');
}
const shopUrl = `https://${subdomain}.booth.pm`;
@@ -30,9 +30,7 @@ module.exports = async (ctx) => {
break;
}
for (let i = 0; i < pageItems.length; ++i) {
const pageItem = pageItems[i];
for (const pageItem of pageItems) {
// extract item name
const itemName = $('h2.item-name > a', pageItem).text();
+1 -1
View File
@@ -20,7 +20,7 @@ module.exports = async (ctx) => {
return {
link: item.attr('href'),
title: item.find('h5').text(),
pubDate: new Date(item.find('span').text().replace(/年|月/g, '-').replace(/日/, '')).toUTCString(),
pubDate: new Date(item.find('span').text().replaceAll(/年|月/g, '-').replace(/日/, '')).toUTCString(),
};
})
.get();
+2 -2
View File
@@ -37,7 +37,7 @@ module.exports = async (ctx) => {
const pubDate = new Date($('dc\\:date').text()).toUTCString();
const cache = await ctx.cache.get(address);
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const itemPage = await got.get(address);
const itemCapture = cheerio.load(itemPage.data);
@@ -101,7 +101,7 @@ module.exports = async (ctx) => {
pubDate,
};
ctx.cache.set(address, JSON.stringify(single));
return Promise.resolve(single);
return single;
})
);
ctx.state.data = {
+1 -1
View File
@@ -94,7 +94,7 @@ module.exports = async (ctx) => {
pubDate: new Date(pageMeta.issueDate).toUTCString(),
};
ctx.cache.set(address, JSON.stringify(single));
return Promise.resolve(single);
return single;
})
);
ctx.state.data = {
+2 -2
View File
@@ -24,7 +24,7 @@ module.exports = async (ctx) => {
const cache = await ctx.cache.get(link);
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const description = await ProcessFeed(link);
@@ -37,7 +37,7 @@ module.exports = async (ctx) => {
};
ctx.cache.set(link, JSON.stringify(single));
return Promise.resolve(single);
return single;
})
);
+1 -1
View File
@@ -19,7 +19,7 @@ module.exports = async (ctx) => {
return {
title: a.text(),
link: a.attr('href'),
pubDate: new Date(parseInt(a.attr('data-time'))).toUTCString(),
pubDate: new Date(Number.parseInt(a.attr('data-time'))).toUTCString(),
};
})
.get();
+1 -1
View File
@@ -20,7 +20,7 @@ module.exports = async (ctx) => {
return {
title: a.text(),
link: a.attr('href'),
pubDate: new Date(parseInt(a.attr('data-time'))).toUTCString(),
pubDate: new Date(Number.parseInt(a.attr('data-time'))).toUTCString(),
};
})
.get();
+1 -1
View File
@@ -35,7 +35,7 @@ module.exports = async (ctx) => {
item.author = content('.info h3').eq(0).text();
item.description = content('.postBody').eq(0).html();
item.pubDate = new Date(parseInt(content('.info .time').attr('data-timestamp')) * 1000).toUTCString();
item.pubDate = new Date(Number.parseInt(content('.info .time').attr('data-timestamp')) * 1000).toUTCString();
return item;
})
+2 -2
View File
@@ -43,11 +43,11 @@ module.exports = async (ctx) => {
'.recommender',
'[class*="pb-f-ads-"]',
];
unwanted_element_selectors.forEach((selector) => {
for (const selector of unwanted_element_selectors) {
content.find(selector).each((i, e) => {
$(e).remove();
});
});
}
return {
title: item.title.trim(),
+4 -4
View File
@@ -10,7 +10,7 @@ module.exports = async (ctx) => {
feed.items.map(async (item) => {
const cache = await ctx.cache.get(item.link);
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const response = await got({
@@ -25,7 +25,7 @@ module.exports = async (ctx) => {
// replace placeholer image url
imgNode.each((index, element) => {
if ($(element).attr('src') && $(element).attr('src').indexOf('none.gif') !== -1) {
if ($(element).attr('src') && $(element).attr('src').includes('none.gif')) {
$(element).attr('src', $(element).attr('zoomfile'));
}
@@ -51,12 +51,12 @@ module.exports = async (ctx) => {
author: item.author,
};
ctx.cache.set(item.link, JSON.stringify(single));
return Promise.resolve(single);
return single;
})
);
let title = feed.title.split('-');
title = `${title[title.length - 1]} - Chiphell`;
title = `${title.at(-1)} - Chiphell`;
ctx.state.data = {
title,
+1 -1
View File
@@ -19,7 +19,7 @@ function pick_versions(raw_html) {
const href = $('a', col).attr('href');
let version = '';
if (href) {
version = href.split('/').slice(-1)[0];
version = href.split('/').at(-1);
}
software.version = version;
}
+1 -1
View File
@@ -5,7 +5,7 @@ module.exports = async (ctx) => {
const response = await got({
method: 'get',
url: `https://dig.chouti.com/top/${hour}hr?_=${+new Date()}`,
url: `https://dig.chouti.com/top/${hour}hr?_=${Date.now()}`,
headers: {
Referer: 'https://dig.chouti.com/',
},
+1 -1
View File
@@ -22,7 +22,7 @@ module.exports = async (ctx) => {
return {
title: item.text(),
pubDate: new Date(item.prev().text()).toUTCString(),
link: link.indexOf('http') < 0 ? `${rootUrl}${link}` : link,
link: link.includes('http') ? link : `${rootUrl}${link}`,
};
})
.get();
+6 -6
View File
@@ -9,8 +9,8 @@ const types = {
};
module.exports = async (ctx) => {
const type = ctx.params.type ? ctx.params.type : 'hot';
const category = ctx.params.category ? ctx.params.category : '0';
const type = ctx.params.type ?? 'hot';
const category = ctx.params.category ?? '0';
const category_name = category === '0' ? '全部' : category;
const url = `http://www.cnu.cc/discoveryPage/${type}-${encodeURIComponent(category)}`;
@@ -28,7 +28,7 @@ module.exports = async (ctx) => {
const cache = await ctx.cache.get(link);
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const rssitem = {
@@ -43,11 +43,11 @@ module.exports = async (ctx) => {
rssitem.author = result.author;
rssitem.description = result.description;
rssitem.pubDate = result.pubDate;
} catch (err) {
return Promise.resolve('');
} catch {
return '';
}
ctx.cache.set(link, JSON.stringify(rssitem));
return Promise.resolve(rssitem);
return rssitem;
})
);
+5 -5
View File
@@ -18,7 +18,7 @@ module.exports = async (ctx) => {
const cache = await ctx.cache.get(link);
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const rssitem = {
@@ -30,17 +30,17 @@ module.exports = async (ctx) => {
const response = await got.get(link);
const result = utils.parseContent(response.data);
if (!result.description) {
return Promise.resolve('');
return '';
}
rssitem.author = result.author;
rssitem.description = result.description;
rssitem.pubDate = result.pubDate;
} catch (err) {
return Promise.resolve('');
} catch {
return '';
}
ctx.cache.set(link, JSON.stringify(rssitem));
return Promise.resolve(rssitem);
return rssitem;
})
);
+4 -4
View File
@@ -10,10 +10,10 @@ const parseContent = (htmlString) => {
const content = $('#work_body');
const imgs_json = JSON.parse($('#imgs_json').text());
for (let k = 0; k < imgs_json.length; k++) {
content.append(`<img src="${pic_base_url}${imgs_json[k].img}" />`);
content.append(`<div class='img_description'>${imgs_json[k].content}</div>`);
content.append(`<p>${imgs_json[k].text}</p>`);
for (const element of imgs_json) {
content.append(`<img src="${pic_base_url}${element.img}" />`);
content.append(`<div class='img_description'>${element.content}</div>`);
content.append(`<p>${element.text}</p>`);
}
return {
+2 -4
View File
@@ -11,10 +11,8 @@ module.exports = async (ctx) => {
const $listElement = $(this);
const title = $listElement.find('span.release-number').text();
if (title) {
if (!includePreRelease) {
if (title.includes('rc')) {
return;
}
if (!includePreRelease && title.includes('rc')) {
return;
}
items.push({
title: $listElement.find('span.release-number').text(),
+1 -1
View File
@@ -21,7 +21,7 @@ const config = {
module.exports = async (ctx) => {
const cfg = config[ctx.params.caty];
if (!cfg) {
throw Error('Bad category. See <a href="https://docs.rsshub.app/routes/finance#zhong-zheng-wang-zi-xun">docs</a>');
throw new Error('Bad category. See <a href="https://docs.rsshub.app/routes/finance#zhong-zheng-wang-zi-xun">docs</a>');
}
const currentUrl = url.resolve(rootUrl, cfg.link);
+4 -4
View File
@@ -67,7 +67,7 @@ module.exports = async (ctx) => {
const cache = await ctx.cache.get(itemUrl);
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const response = await got({
method: 'get',
@@ -81,13 +81,13 @@ module.exports = async (ctx) => {
link: itemUrl,
description: $('.contents')
.html()
.replace(/src="\//g, `src="${url.resolve(baseUrl, '.')}`)
.replace(/href="\//g, `href="${url.resolve(baseUrl, '.')}`)
.replaceAll('src="/', `src="${url.resolve(baseUrl, '.')}`)
.replaceAll('href="/', `href="${url.resolve(baseUrl, '.')}`)
.trim(),
pubDate: dateList[index],
};
ctx.cache.set(itemUrl, JSON.stringify(single));
return Promise.resolve(single);
return single;
})
);
+2 -2
View File
@@ -19,7 +19,7 @@ module.exports = async (ctx) => {
feed.items.map(async (item) => {
const cache = await ctx.cache.get(item.link);
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const description = await ProcessFeed(item.link);
@@ -32,7 +32,7 @@ module.exports = async (ctx) => {
author: item.author,
};
ctx.cache.set(item.link, JSON.stringify(single));
return Promise.resolve(single);
return single;
})
);
+1 -1
View File
@@ -27,7 +27,7 @@ module.exports = async (ctx) => {
return {
title: name,
author: '低端影视',
description: `<img src="${poster}" style="max-width: 100%;" >${text ? text : ''}`,
description: `<img src="${poster}" style="max-width: 100%;" >${text ?? ''}`,
link: item.find('.post-box-title a').attr('href'),
pubDate: time,
guid: md5(name),
+1 -1
View File
@@ -21,7 +21,7 @@ module.exports = async (ctx) => {
description: data[key],
link: `${currentUrl}/${date}`,
title: data['post_title_' + date],
pubDate: new Date(`${date.substr(0, 4)}-${date.substr(4, 2)}-${date.substr(6, 2)}`).toUTCString(),
pubDate: new Date(`${date.slice(0, 4)}-${date.slice(4, 6)}-${date.slice(6, 8)}`).toUTCString(),
});
}
}
+2 -2
View File
@@ -20,10 +20,10 @@ module.exports = async (ctx) => {
const $ = cheerio.load(html);
$('div.crayons-story__body').each(function () {
const post = {
author: $('.crayons-story__secondary', this).text().trim().replace(/\s\s+/g, ', '),
author: $('.crayons-story__secondary', this).text().trim().replaceAll(/\s\s+/g, ', '),
title: $('.crayons-story__title a', this).text().trim(),
link: `https://dev.to${$('.crayons-story__title a', this).attr('href')}`,
description: $('.crayons-story__tags', this).text().trim().replace(/\s\s+/g, ' '),
description: $('.crayons-story__tags', this).text().trim().replaceAll(/\s\s+/g, ' '),
pubDate: new Date($('.time-ago-indicator-initial-placeholder', this).attr('data-seconds') * 1000).toUTCString(),
};
+2 -2
View File
@@ -37,14 +37,14 @@ module.exports = async (ctx) => {
});
}
return Promise.resolve({
return {
title,
description,
pubDate: new Date(item.send_at * 1000).toUTCString(),
link: olink,
category,
author: item.author.username,
});
};
})
);
+2 -1
View File
@@ -1,4 +1,5 @@
const got = require('@/utils/got');
const sanitizeHtml = require('sanitize-html');
module.exports = async (ctx) => {
const keyword = ctx.params.keyword;
@@ -19,7 +20,7 @@ module.exports = async (ctx) => {
title: `数字尾巴 - 闲置 - ${keyword}`,
link: url,
item: list.map((item) => ({
title: item.title.replace(/<.*?>/g, ''),
title: sanitizeHtml(item.title, { allowedTags: [], allowedAttributes: {} }),
author: item.author.username,
description: `<p>价格: ¥${item.price}</p><p>地址: ${item.address}</p><p>${item.content}</p><img src="${item.cover}" style="max-width: 100%;"/>`,
pubDate: new Date(item.created_at * 1000),
+2 -2
View File
@@ -13,7 +13,7 @@ const type_names = {
};
module.exports = async (ctx) => {
const typeId = ctx.params.typeId ? ctx.params.typeId : '0';
const typeId = ctx.params.typeId ?? '0';
const url = 'https://www.dgtle.com/sale';
@@ -25,7 +25,7 @@ module.exports = async (ctx) => {
},
});
const type_name = type_names[typeId] ? type_names[typeId] : typeId;
const type_name = type_names[typeId] ?? typeId;
const list = response.data.data.dataList;
ctx.state.data = {
+8 -7
View File
@@ -34,9 +34,9 @@ module.exports = async (ctx) => {
const habits = habitsRes.data;
const paramsList = [];
habits.forEach((item) => {
for (const item of habits) {
paramsList.push(['habitIds', item.id]);
});
}
const searchParams = new URLSearchParams(paramsList);
const habitCheckinsRes = await got.get({
@@ -55,8 +55,9 @@ module.exports = async (ctx) => {
let list = [];
for (const habitId in checkins.checkins) {
const info = habits.find((item) => item.id === habitId);
list = list.concat(
checkins.checkins[habitId]
list = [
...list,
...checkins.checkins[habitId]
.sort((a, b) => a.checkinStamp - b.checkinStamp)
.filter((checkin) => checkin.value)
.map((checkin, index) => {
@@ -68,8 +69,8 @@ module.exports = async (ctx) => {
link: `https://dida365.com/webapp/#q/all/habit/${checkin.habitId}`,
guid: checkin.id,
};
})
);
}),
];
}
ctx.state.data = {
@@ -78,6 +79,6 @@ module.exports = async (ctx) => {
item: list,
};
} else {
throw Error('Login required');
throw new Error('Login required');
}
};
+1 -1
View File
@@ -45,7 +45,7 @@ module.exports = async (ctx) => {
const cache = await ctx.cache.get(itemUrl);
// 判断缓存
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const res = await got.get(itemUrl);
const $ = cheerio.load(res.data);
+1 -1
View File
@@ -16,7 +16,7 @@ module.exports = async (ctx) => {
const cache = await ctx.cache.get(itemUrl);
// 判断缓存
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const res = await got.get(itemUrl);
const $ = cheerio.load(res.data);
+1 -1
View File
@@ -29,7 +29,7 @@ module.exports = async (ctx) => {
const cache = await ctx.cache.get(itemUrl);
// 判断缓存
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const res = await got.get(itemUrl);
const $ = cheerio.load(res.data);
+8 -8
View File
@@ -17,7 +17,7 @@ module.exports = async (ctx) => {
const $ = cheerio.load(response.data);
const list = $('li a')
.slice(0, ctx.query.limit ? parseInt(ctx.query.limit) : 15)
.slice(0, ctx.query.limit ? Number.parseInt(ctx.query.limit) : 15)
.map((_, item) => {
item = $(item);
@@ -37,13 +37,13 @@ module.exports = async (ctx) => {
});
const data = detailResponse.data
.replace(/\[img\]https:\/\/www\.discuss\.com\.hk\/images\/common\/back\.gif\[\/img\]/g, '')
.replace(/\[url=(.*?)\]/gm, '<a href="$1">')
.replace(/\[(\w+)=(.*?)\]/gm, '<span style="$1: $2;">')
.replace(/\[\/(color|size)\]/gm, '</span>')
.replace(/\[\/url\]/gm, '</a>')
.replace(/\[(\w+)\]/gm, '<$1>')
.replace(/\[\/(\w+)\]/gm, '</$1>');
.replaceAll('[img]https://www.discuss.com.hk/images/common/back.gif[/img]', '')
.replaceAll(/\[url=(.*?)]/gm, '<a href="$1">')
.replaceAll(/\[(\w+)=(.*?)]/gm, '<span style="$1: $2;">')
.replaceAll(/\[\/(color|size)]/gm, '</span>')
.replaceAll(/\[\/url]/gm, '</a>')
.replaceAll(/\[(\w+)]/gm, '<$1>')
.replaceAll(/\[\/(\w+)]/gm, '</$1>');
const content = cheerio.load(data);
+5 -5
View File
@@ -18,13 +18,13 @@ module.exports = async (ctx) => {
const data = response.data.response;
const threadsObj = {};
data.forEach((item) => {
for (const item of data) {
threadsObj[item.thread] = 1;
});
}
let threadsQuery = '';
Object.keys(threadsObj).forEach((item) => {
for (const item of Object.keys(threadsObj)) {
threadsQuery += `&thread=${item}`;
});
}
const responseThreads = await got({
method: 'get',
@@ -41,7 +41,7 @@ module.exports = async (ctx) => {
link: `https://disqus.com/home/forums/${forum}`,
description: `${forum} 的 disqus 评论`,
item: data.map((item) => {
const thread = threads.filter((i) => i.id === item.thread)[0];
const thread = threads.find((i) => i.id === item.thread);
return {
title: `${item.author.name}: ${item.raw_message}`,
description: `${item.author.name} 在《${thread.clean_title}》中发表评论: ${item.message}`,
+2 -2
View File
@@ -1,7 +1,7 @@
const parser = require('@/utils/rss-parser');
const got = require('@/utils/got');
const cheerio = require('cheerio');
const dateParser = require('@/utils/dateParser');
const dateParser = require('@/utils/date-parser');
const domain = 'https://www.dongmanmanhua.cn';
module.exports = async (ctx) => {
@@ -23,7 +23,7 @@ module.exports = async (ctx) => {
description: `<a href=${x.link} target="_blank">${x.title}</a>`,
})),
};
} catch (error) {
} catch {
const { body } = await got.get(comicLink);
const $ = cheerio.load(body);
rss = {
+3 -6
View File
@@ -29,11 +29,8 @@ module.exports = async (ctx) => {
single.pubDate = value.pubDate;
} else {
const temp = await got(link);
single.description = $(temp.data)
.find('.subject-content')
.html()
.replace(/alt="\\"/g, '');
single.pubDate = new Date($(temp.data).find('.subject-meta').text().trim().substr(0, 18)).toUTCString();
single.description = $(temp.data).find('.subject-content').html().replaceAll('alt="\\"', '');
single.pubDate = new Date($(temp.data).find('.subject-meta').text().trim().slice(0, 18)).toUTCString();
ctx.cache.set(key, {
description: single.description,
@@ -41,7 +38,7 @@ module.exports = async (ctx) => {
});
}
return Promise.resolve(single);
return single;
})
);
ctx.state.data = { title: '多知网', link: 'http://www.duozhi.com/', description: '独立商业视角 新锐教育观察', item: result };
+3 -7
View File
@@ -70,13 +70,9 @@ module.exports = async (ctx) => {
const lang = ctx.params.lang || 'CN';
const price = ctx.params.price || '1';
let currentUrl;
if (ctx.params.search) {
currentUrl = `https://masterapi.edrawsoft.cn/api/publish?offset=0&count=30&order=PV&sort=DESC&search=${search}&lang=CN&price=1`;
} else {
currentUrl = `https://masterapi.edrawsoft.cn/api/publish${classId === '' ? '' : '2'}?offset=0&count=30${classId}&order=${order}&sort=${sort}&lang=${lang}&price=${price}`;
}
const currentUrl = ctx.params.search
? `https://masterapi.edrawsoft.cn/api/publish?offset=0&count=30&order=PV&sort=DESC&search=${search}&lang=CN&price=1`
: `https://masterapi.edrawsoft.cn/api/publish${classId === '' ? '' : '2'}?offset=0&count=30${classId}&order=${order}&sort=${sort}&lang=${lang}&price=${price}`;
const response = await got({
method: 'get',
+1 -5
View File
@@ -31,11 +31,7 @@ module.exports = async (ctx) => {
const rootUrl = 'http://www.eeo.com.cn';
let currentUrl = rootUrl;
if (parseInt(column)) {
currentUrl += legacyUrls[parseInt(column)];
} else {
currentUrl += `/${column}/${category}`;
}
currentUrl += Number.parseInt(column) ? legacyUrls[Number.parseInt(column)] : `/${column}/${category}`;
const response = await got({
method: 'get',
+2 -7
View File
@@ -19,20 +19,15 @@ const config = {
};
const get_date = (o) => {
let date;
const match = /(\d{4}\.\d+\.\d+)/.exec(o.text().trim());
if (match) {
date = match[1];
} else {
date = o.attr('datetime');
}
const date = match ? match[1] : o.attr('datetime');
return new Date(date + ' GMT+9').toUTCString();
};
module.exports = async (ctx) => {
const cfg = config[ctx.params.type];
if (!cfg) {
throw Error('Bad type');
throw new Error('Bad type');
}
const response = await got({
+4 -5
View File
@@ -15,9 +15,8 @@ module.exports = async (ctx) => {
).data.result.category;
let category_name, description;
for (let i = 0; i < categorys.length; i++) {
const item = categorys[i];
if (item.cateId === parseInt(id)) {
for (const item of categorys) {
if (item.cateId === Number.parseInt(id)) {
category_name = item.cateName;
description = item.cateDescription;
break;
@@ -43,7 +42,7 @@ module.exports = async (ctx) => {
const cache = await ctx.cache.get(itemUrl);
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const response = await got({
@@ -64,7 +63,7 @@ module.exports = async (ctx) => {
pubDate: new Date(date * 1000).toUTCString(),
};
ctx.cache.set(itemUrl, JSON.stringify(single));
return Promise.resolve(single);
return single;
})
);
+1 -1
View File
@@ -25,7 +25,7 @@ module.exports = async (ctx) => {
const cache = await ctx.cache.get(link);
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const itemReponse = await got.get(link);
+1 -1
View File
@@ -25,7 +25,7 @@ module.exports = async (ctx) => {
const cache = await ctx.cache.get(link);
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const itemReponse = await got.get(link);
+5 -5
View File
@@ -1,12 +1,12 @@
const got = require('@/utils/got');
const cheerio = require('cheerio');
const parser = require('@/utils/rss-parser');
const allowLang = ['chinese', 'cn', 'us', 'japanese', 'www'];
const allowLang = new Set(['chinese', 'cn', 'us', 'japanese', 'www']);
module.exports = async (ctx) => {
const lang = ctx.params.lang === 'us' ? 'www' : ctx.params.lang || 'cn';
if (!allowLang.includes(lang)) {
throw Error('Invalid lang');
if (!allowLang.has(lang)) {
throw new Error('Invalid lang');
}
const rssUrl = `https://${lang}.engadget.com/rss.xml`;
const feed = await parser.parseURL(rssUrl);
@@ -39,7 +39,7 @@ module.exports = async (ctx) => {
feed.items.map(async (item) => {
const cache = await ctx.cache.get(item.link);
if (cache) {
return Promise.resolve(JSON.parse(cache));
return JSON.parse(cache);
}
const response = await got.get(item.link);
@@ -53,7 +53,7 @@ module.exports = async (ctx) => {
author: item.author,
};
ctx.cache.set(item.link, JSON.stringify(single));
return Promise.resolve(single);
return single;
})
);
+1 -1
View File
@@ -20,7 +20,7 @@ module.exports = async (ctx) => {
list &&
list.map((item) => {
const title = ` TransactionHash: ${item.hash} `;
const value = (parseFloat(item.value) / 10 ** 18).toFixed(8);
const value = (Number.parseFloat(item.value) / 10 ** 18).toFixed(8);
const description = `
From: ${item.from} <br> To: ${item.to} <br> Value: ${value} <br> Block: ${item.blockNumber}`;
const link = `https://etherscan.io/tx/${item.hash}`;

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