chore: add eslint-plugin-regexp (#22189)
* chore: add eslint-plugin-regexp * chore: autofix * chore: fix no-useless-flag * chore: fix optimal-lookaround-quantifier * chore: fix no-lazy-ends * chore: fix no-contradiction-with-assertion * chore: fix no-useless-assertions * chore: fix no-useless-quantifier * chore: fix remaining regexp issues * fix: regex for WFU news link validation
This commit is contained in:
parent
bedeb4edaa
commit
75d43dd086
|
|
@ -14,6 +14,7 @@
|
|||
"jsPlugins": [
|
||||
{ "name": "n", "specifier": "eslint-plugin-n" },
|
||||
{ "name": "unicorn-js", "specifier": "eslint-plugin-unicorn" },
|
||||
{ "name": "regexp", "specifier": "eslint-plugin-regexp" },
|
||||
"@stylistic/eslint-plugin",
|
||||
"eslint-plugin-simple-import-sort",
|
||||
"oxlint-plugin-eslint",
|
||||
|
|
@ -32,19 +33,19 @@
|
|||
"no-const-assign": "error",
|
||||
"no-constant-binary-expression": "error",
|
||||
"no-constant-condition": "error",
|
||||
// "no-control-regex": "error", -> off
|
||||
"no-control-regex": "error",
|
||||
"no-debugger": "error",
|
||||
"no-dupe-class-members": "error",
|
||||
"no-dupe-else-if": "error",
|
||||
"no-dupe-keys": "error",
|
||||
"no-duplicate-case": "error",
|
||||
"no-empty-character-class": "error",
|
||||
// "no-empty-character-class": "error", -> off, handled by eslint-plugin-regexp
|
||||
"no-empty-pattern": "error",
|
||||
"no-ex-assign": "error",
|
||||
"no-fallthrough": "error",
|
||||
"no-func-assign": "error",
|
||||
"no-import-assign": "error",
|
||||
"no-invalid-regexp": "error",
|
||||
// "no-invalid-regexp": "error", -> off, handled by eslint-plugin-regexp
|
||||
"no-irregular-whitespace": "error",
|
||||
"no-loss-of-precision": "error",
|
||||
"no-misleading-character-class": "error",
|
||||
|
|
@ -65,7 +66,7 @@
|
|||
"no-unsafe-optional-chaining": "error",
|
||||
"no-unused-private-class-members": "error",
|
||||
// "no-unused-vars": "error", -> off for @typescript-eslint/no-unused-vars
|
||||
"no-useless-backreference": "error",
|
||||
// "no-useless-backreference": "error", -> off, handled by eslint-plugin-regexp
|
||||
"use-isnan": "error",
|
||||
"valid-typeof": "error",
|
||||
// #endregion
|
||||
|
|
@ -289,12 +290,74 @@
|
|||
"unicorn/throw-new-error": "error",
|
||||
// #endregion
|
||||
|
||||
// #region --- regexp recommended ---
|
||||
"regexp/confusing-quantifier": "warn",
|
||||
"regexp/control-character-escape": "error",
|
||||
"regexp/match-any": "error",
|
||||
"regexp/negation": "error",
|
||||
"regexp/no-contradiction-with-assertion": "error",
|
||||
"regexp/no-dupe-characters-character-class": "error",
|
||||
"regexp/no-dupe-disjunctions": "error",
|
||||
"regexp/no-empty-alternative": "warn",
|
||||
"regexp/no-empty-capturing-group": "error",
|
||||
"regexp/no-empty-character-class": "error",
|
||||
"regexp/no-empty-group": "error",
|
||||
"regexp/no-empty-lookarounds-assertion": "error",
|
||||
"regexp/no-empty-string-literal": "error",
|
||||
"regexp/no-escape-backspace": "error",
|
||||
"regexp/no-extra-lookaround-assertions": "error",
|
||||
"regexp/no-invalid-regexp": "error",
|
||||
"regexp/no-invisible-character": "error",
|
||||
"regexp/no-lazy-ends": "warn",
|
||||
"regexp/no-legacy-features": "error",
|
||||
"regexp/no-misleading-capturing-group": "error",
|
||||
"regexp/no-misleading-unicode-character": "error",
|
||||
"regexp/no-missing-g-flag": "error",
|
||||
"regexp/no-non-standard-flag": "error",
|
||||
"regexp/no-obscure-range": "error",
|
||||
"regexp/no-optional-assertion": "error",
|
||||
"regexp/no-potentially-useless-backreference": "warn",
|
||||
"regexp/no-super-linear-backtracking": "error",
|
||||
"regexp/no-trivially-nested-assertion": "error",
|
||||
"regexp/no-trivially-nested-quantifier": "error",
|
||||
"regexp/no-unused-capturing-group": "error",
|
||||
"regexp/no-useless-assertions": "error",
|
||||
"regexp/no-useless-backreference": "error",
|
||||
"regexp/no-useless-character-class": "error",
|
||||
"regexp/no-useless-dollar-replacements": "error",
|
||||
"regexp/no-useless-escape": "error",
|
||||
"regexp/no-useless-flag": "warn",
|
||||
"regexp/no-useless-lazy": "error",
|
||||
"regexp/no-useless-non-capturing-group": "error",
|
||||
"regexp/no-useless-quantifier": "error",
|
||||
"regexp/no-useless-range": "error",
|
||||
"regexp/no-useless-set-operand": "error",
|
||||
"regexp/no-useless-string-literal": "error",
|
||||
"regexp/no-useless-two-nums-quantifier": "error",
|
||||
"regexp/no-zero-quantifier": "error",
|
||||
"regexp/optimal-lookaround-quantifier": "warn",
|
||||
"regexp/optimal-quantifier-concatenation": "error",
|
||||
"regexp/prefer-character-class": "error",
|
||||
"regexp/prefer-d": "error",
|
||||
"regexp/prefer-plus-quantifier": "error",
|
||||
"regexp/prefer-predefined-assertion": "error",
|
||||
"regexp/prefer-question-quantifier": "error",
|
||||
"regexp/prefer-range": "error",
|
||||
"regexp/prefer-set-operation": "error",
|
||||
"regexp/prefer-star-quantifier": "error",
|
||||
"regexp/prefer-unicode-codepoint-escapes": "error",
|
||||
"regexp/prefer-w": "error",
|
||||
"regexp/simplify-set-operations": "error",
|
||||
"regexp/sort-flags": "error",
|
||||
"regexp/strict": "error",
|
||||
"regexp/use-ignore-case": "error",
|
||||
// #endregion
|
||||
|
||||
// --- custom rules ---
|
||||
// #region --- possible problems ---
|
||||
"array-callback-return": ["error", { "allowImplicit": true }],
|
||||
|
||||
"no-await-in-loop": "error",
|
||||
"no-control-regex": "off",
|
||||
"no-prototype-builtins": "off",
|
||||
"no-undef": "off", // typescript/eslint-recommended, ts(2552)
|
||||
// #endregion
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import { config } from '@/config';
|
|||
import type { Data } from '@/types';
|
||||
import logger from '@/utils/logger';
|
||||
|
||||
const templateRegex = /\${([^{}]+)}/g;
|
||||
const templateRegex = /\$\{([^{}]+)\}/g;
|
||||
const allowedUrlProperties = new Set(['hash', 'host', 'hostname', 'href', 'origin', 'password', 'pathname', 'port', 'protocol', 'search', 'searchParams', 'username']);
|
||||
|
||||
// match path or sub-path
|
||||
|
|
@ -150,7 +150,7 @@ const middleware: MiddlewareHandler = async (ctx, next) => {
|
|||
if (item.enclosure_url && item.enclosure_type) {
|
||||
if (item.enclosure_type.startsWith('image/')) {
|
||||
item.enclosure_url = replaceUrl(imageHotlinkTemplate, item.enclosure_url);
|
||||
} else if (/^(video|audio)\//.test(item.enclosure_type)) {
|
||||
} else if (/^(?:video|audio)\//.test(item.enclosure_type)) {
|
||||
item.enclosure_url = replaceUrl(multimediaHotlinkTemplate, item.enclosure_url);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ const middleware: MiddlewareHandler = async (ctx, next) => {
|
|||
return ctx.json(ctx.get('json') || { message: 'plugin does not set debug json' });
|
||||
}
|
||||
|
||||
if (/(\d+)\.debug\.html$/.test(outputType)) {
|
||||
if (/\d+\.debug\.html$/.test(outputType)) {
|
||||
const index = Number.parseInt(outputType.match(/(\d+)\.debug\.html$/)?.[1] || '0');
|
||||
return ctx.html(data?.item?.[index]?.description || `data.item[${index}].description not found`);
|
||||
}
|
||||
|
|
@ -58,7 +58,8 @@ const middleware: MiddlewareHandler = async (ctx, next) => {
|
|||
// https://stackoverflow.com/questions/1497885/remove-control-characters-from-php-string/1497928#1497928
|
||||
// remove unicode control characters
|
||||
// see #14940 #14943 #15262
|
||||
item.description = item.description.replaceAll(/[\u0000-\u0009\u000B\u000C\u000E-\u001F\u007F\u200B\uFFFF]/g, '');
|
||||
// oxlint-disable-next-line no-control-regex
|
||||
item.description = item.description.replaceAll(/[\u0000-\u0009\v\f\u000E-\u001F\u007F\u200B\uFFFF]/g, '');
|
||||
}
|
||||
|
||||
if (typeof item.author === 'string') {
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ const handler = async (ctx) => {
|
|||
|
||||
const $ = cheerio.load(response.data);
|
||||
|
||||
const pattern = /item=(\[{.*?}]);/;
|
||||
const pattern = /item=(\[\{.*?\}\]);/;
|
||||
const newsList = JSON.parse($('script[language="javascript"]').text().match(pattern)?.[1].replaceAll("'", '"') || '[]');
|
||||
|
||||
const topNewsList = newsList.slice(0, limit).map((item) => ({
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ async function handler(ctx) {
|
|||
const url = `https://3g.163.com/touch/reconstruct/article/list/${type}/0-20.html`;
|
||||
const response = await got(url);
|
||||
const data = response.data;
|
||||
const matches = data.replaceAll(/\s/g, '').match(/artiList\((.*?)]}\)/);
|
||||
const matches = data.replaceAll(/\s/g, '').match(/artiList\((.*?)\]\}\)/);
|
||||
const articlelist0 = matches[1].replace(/".*?wangning/, '"articles') + ']}';
|
||||
const articlelist = JSON.parse(articlelist0);
|
||||
const articles = articlelist.articles;
|
||||
|
|
@ -112,7 +112,7 @@ async function handler(ctx) {
|
|||
let url = article.url;
|
||||
if (url === null || article.skipType === 'video') {
|
||||
const skipurl = article.skipURL;
|
||||
const vid = skipurl.match(/vid=(.*?)$/);
|
||||
const vid = skipurl.match(/vid=(.*)$/);
|
||||
if (vid !== null) {
|
||||
url = `https://3g.163.com/exclusive/video/${vid[1]}.html`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ async function handler() {
|
|||
const initialState = JSON.parse(
|
||||
$('script')
|
||||
.text()
|
||||
.match(/window\.__INITIAL_STATE__=(.*);\(function\(\){var/)[1]
|
||||
.match(/window\.__INITIAL_STATE__=(.*);\(function\(\)\{var/)[1]
|
||||
);
|
||||
|
||||
const list = Object.values(initialState.courseindex.myModules).flatMap((mod) =>
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ async function handler(ctx) {
|
|||
}
|
||||
}
|
||||
if (!item.enclosure_url) {
|
||||
const hashMatch = readTpcHtml.match(/哈希校验[^;]*;\s*([a-fA-F0-9]{40})\s*[;;]/);
|
||||
const hashMatch = readTpcHtml.match(/哈希校验[^;]*;\s*([a-f0-9]{40})\s*[;;]/i);
|
||||
const magnetFromHash = hashMatch ? `magnet:?xt=urn:btih:${hashMatch[1]}` : null;
|
||||
const magnetFromText = magnetText.match(/magnet:\?xt=urn:btih:[^\s"'<>]+/)?.[0];
|
||||
const magnetLink = magnetFromText ?? readTpcHtml.match(/magnet:\?xt=urn:btih:[^\s"'<>]+/)?.[0] ?? magnetFromHash ?? copyLink;
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ async function handler(ctx) {
|
|||
},
|
||||
});
|
||||
|
||||
const data = getProperty(JSON.parse(response.data.match(/window.initialState=({.*})/)[1]), categories[category].key);
|
||||
const data = getProperty(JSON.parse(response.data.match(/window.initialState=(\{.*\})/)[1]), categories[category].key);
|
||||
|
||||
let items = data
|
||||
.slice(0, ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 10)
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ async function handler(ctx) {
|
|||
|
||||
const $ = load(response.data);
|
||||
|
||||
const data = JSON.parse(response.data.match(/"itemList":(\[.*?])/)[1]);
|
||||
const data = JSON.parse(response.data.match(/"itemList":(\[.*?\])/)[1]);
|
||||
|
||||
let items = data
|
||||
.slice(0, ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 30)
|
||||
|
|
@ -64,7 +64,7 @@ async function handler(ctx) {
|
|||
};
|
||||
});
|
||||
|
||||
if (!/^\/(search|newsflashes)/.test(path)) {
|
||||
if (!/^\/(?:search|newsflashes)/.test(path)) {
|
||||
items = await Promise.all(items.map((item) => ProcessItem(item, cache.tryGet)));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ export const ProcessItem = (item, tryGet) =>
|
|||
tryGet(item.link, async () => {
|
||||
const detailResponse = await ofetch(item.link);
|
||||
|
||||
const cipherTextList = detailResponse.match(/{"state":"(.*)","isEncrypt":true}/) ?? [];
|
||||
const cipherTextList = detailResponse.match(/\{"state":"(.*)","isEncrypt":true\}/) ?? [];
|
||||
|
||||
if (cipherTextList.length === 0) {
|
||||
const $ = load(detailResponse);
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ const parseArticle = (item, tryGet) =>
|
|||
|
||||
if (item.link.startsWith('https://dl.3dmgame.com/')) {
|
||||
const lis = $('.patchtop .lis');
|
||||
const [, category, pubDate, author] = lis.text().match(/补丁类型:(.*?)\n.*整理时间:(.*?)\n.*补丁制作:(.*?)\n/s);
|
||||
const [, category, pubDate, author] = lis.text().match(/补丁类型:([^\n]*)\n.*整理时间:([^\n]*)\n.*补丁制作:([^\n]*)\n/s);
|
||||
|
||||
item.description = lis.html() + $('.L_title').html() + $('.GmL_1').html();
|
||||
item.category = category;
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ async function handler(ctx) {
|
|||
const scriptUrl = new URL(scriptPath, rootUrl).href;
|
||||
|
||||
const scriptResponse = await ofetch(scriptUrl);
|
||||
const key = scriptResponse.match(/{var key="(.*?)"/)?.[1];
|
||||
const key = scriptResponse.match(/\{var key="(.*?)"/)?.[1];
|
||||
const value = scriptResponse.match(/",value="(.*?)"/)?.[1];
|
||||
const getPath = scriptResponse.match(/\.get\("(.*?&key=)"/)?.[1];
|
||||
|
||||
|
|
|
|||
|
|
@ -54,8 +54,8 @@ const createItem = (url: string) =>
|
|||
cache.tryGet(url, async () => {
|
||||
const html = await get(url);
|
||||
const $ = load(html);
|
||||
const { articleid, chapterid, chaptername } = parseObject(/bookinfo\s?=\s?{[\S\s]+?}/, $('head>script:not([src])').text());
|
||||
const decryptionMap = parseObject(/_\d+\s?=\s?{[\S\s]+?}/, $('.txtnav+script').text());
|
||||
const { articleid, chapterid, chaptername } = parseObject(/bookinfo\s?=\s?\{[\s\S]+?\}/, $('head>script:not([src])').text());
|
||||
const decryptionMap = parseObject(/_\d+\s?=\s?\{[\s\S]+?\}/, $('.txtnav+script').text());
|
||||
|
||||
return {
|
||||
title: chaptername,
|
||||
|
|
@ -70,7 +70,7 @@ const parseObject = (reg: RegExp, str: string): Record<string, string> => {
|
|||
const obj = {};
|
||||
const match = reg.exec(str);
|
||||
if (match) {
|
||||
for (const line of match[0].matchAll(/(\w+):\s?["']?([\S\s]+?)["']?[\n,}]/g)) {
|
||||
for (const line of match[0].matchAll(/(\w+):\s?["']?([\s\S]+?)["']?[\n,}]/g)) {
|
||||
obj[line[1]] = line[2];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ async function handler(ctx) {
|
|||
const content = load(detailResponse.data);
|
||||
|
||||
item.title = content('title').text().replace(' -6park.com', '');
|
||||
item.author = detailResponse.data.match(/送交者: .*>(.*)<.*\[/)[1];
|
||||
item.author = detailResponse.data.match(/送交者:[^>]*>([^<]*)<\/a>/)[1].trim();
|
||||
item.pubDate = timezone(parseDate(detailResponse.data.match(/于 (.*) 已读/)[1], 'YYYY-MM-DD h:m'), +8);
|
||||
item.description = content('pre')
|
||||
.html()
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ async function handler(ctx) {
|
|||
|
||||
const content = load(detailResponse.data);
|
||||
|
||||
const matches = detailResponse.data.match(/新闻来源:(.*?)于.*(\d{4}(?:-\d{2}){2} (?:\d{1,2}:){2}\d{1,2})/);
|
||||
const matches = detailResponse.data.match(/新闻来源:([^于]*)于.*(\d{4}(?:-\d{2}){2} (?:\d{1,2}:){2}\d{1,2})/);
|
||||
|
||||
item.title = content('h2').text();
|
||||
item.author = matches[1].trim();
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ const ProcessFeed = (data) => {
|
|||
content.find('div').each((i, e) => {
|
||||
if ($(e)[0].attribs.class) {
|
||||
const classes = $(e)[0].attribs.class;
|
||||
if (/\w{10}\s\w{10}/g.test(classes)) {
|
||||
if (/\w{10}\s\w{10}/.test(classes)) {
|
||||
$(e).remove();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ async function handler(ctx) {
|
|||
const feedUrl = new URL(`news/feed/${documentId}/rss.xml`, rootUrl).href;
|
||||
|
||||
const feedResponse = await ofetch(feedUrl);
|
||||
currentUrl = feedResponse.match(/<link>([\w-./:?]+)<\/link>/)[1];
|
||||
currentUrl = feedResponse.match(/<link>([\w./:?-]+)<\/link>/)[1];
|
||||
}
|
||||
|
||||
const currentResponse = await ofetch(currentUrl);
|
||||
|
|
@ -124,7 +124,7 @@ async function handler(ctx) {
|
|||
item.title = content('meta[property="og:title"]').prop('content');
|
||||
item.description = '';
|
||||
|
||||
const enclosurePattern = String.raw`"(?:MIME|content)?Type":"([\w]+/[\w]+)".*?"(?:fileS|s)?ize":(\d+),.*?"url":"([\w-.:/?]+)"`;
|
||||
const enclosurePattern = String.raw`"(?:MIME|content)?Type":"(\w+/\w+)".*?"(?:fileS|s)?ize":(\d+),.*?"url":"([\w.:/?-]+)"`;
|
||||
|
||||
const enclosureMatches = detailResponse.match(new RegExp(enclosurePattern, 'g'));
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ async function handler(ctx) {
|
|||
const list = $('#ac-space-video-list a').toArray();
|
||||
const image = $('head style:contains("user-photo")')
|
||||
.text()
|
||||
.match(/.user-photo{\n\s*background:url\((.*)\) 0% 0% \/ 100% no-repeat;/)?.[1];
|
||||
.match(/.user-photo\{\n\s*background:url\((.*)\) 0% 0% \/ 100% no-repeat;/)?.[1];
|
||||
|
||||
return {
|
||||
title,
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ async function handler(ctx) {
|
|||
const $ = load(response);
|
||||
const jrnlName = $('meta[property="og:title"]')
|
||||
.attr('content')
|
||||
.match(/(?:[^=]*=)?\s*([^>]+)\s*/)[1];
|
||||
.match(/(?:[^=]*=)?\s*([^>]+)/)[1];
|
||||
const publication = $('.al-article-item-wrap.al-normal');
|
||||
|
||||
const list = publication.toArray().map((item) => {
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ function extractItem(a: Cheerio<any>, language: string) {
|
|||
const descEl = a.find('p').first();
|
||||
const description = descEl.text().trim();
|
||||
|
||||
const dateMatch = language === 'fr' ? description.match(/(\d{1,2} [a-zéû]+[.]? \d{4})/i) : description.match(/([A-Z][a-z]+[.]? \d{1,2}, \d{4})/);
|
||||
const dateMatch = language === 'fr' ? description.match(/(\d{1,2} [a-zéû]+\.? \d{4})/i) : description.match(/([A-Z][a-z]+\.? \d{1,2}, \d{4})/);
|
||||
|
||||
const pubDateStr = dateMatch ? dateMatch[1].trim() : '';
|
||||
const pubDate = parseDate(pubDateStr);
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ async function handler() {
|
|||
}
|
||||
}
|
||||
|
||||
const partRegex = /^([0-9a-zA-Z]+):([0-9a-zA-Z]+)?(\[.*)$/;
|
||||
const partRegex = /^([0-9a-z]+):([0-9a-z]+)?(\[.*)$/i;
|
||||
const fd = textList
|
||||
.join('')
|
||||
.split('\n')
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ async function handler(ctx) {
|
|||
const $ = load(response);
|
||||
|
||||
let items = response
|
||||
.match(/(parm\.newsTitle[\S\s]*?arr\.push\(parm\))/g)
|
||||
.match(/(parm\.newsTitle[\s\S]*?arr\.push\(parm\))/g)
|
||||
.slice(0, limit)
|
||||
.map((item) => ({
|
||||
title: item.match(/parm\.newsTitle = '(.*?)'/)[1],
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ async function handler() {
|
|||
const data = response.data;
|
||||
const $ = load(data);
|
||||
const contents = $('script:contains("window.__PRELOADED_STATE__")').text();
|
||||
const regex = /{.*}/;
|
||||
const regex = /\{.*\}/;
|
||||
let items = JSON.parse(contents.match(regex)[0]).shop.items;
|
||||
items = items.filter((item) => item.availableSizes.length !== 0);
|
||||
|
||||
|
|
|
|||
|
|
@ -355,7 +355,7 @@ export const extractInitialData = ($: CheerioAPI): any => {
|
|||
const initialDataText = JSON.parse(
|
||||
$('script:contains("window.__INITIAL_DATA__")')
|
||||
.text()
|
||||
.match(/window\.__INITIAL_DATA__\s*=\s*(.*);/)?.[1] ?? '"{}"'
|
||||
.match(/window\.__INITIAL_DATA__\s*=\s*(\S.*)?;/)?.[1] ?? '"{}"'
|
||||
);
|
||||
|
||||
return JSON.parse(initialDataText);
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ const getWbiVerifyString = () => {
|
|||
// 46, 47, 18, 2, 53, 8, 23, 32, 15, 50, 10, 31, 58, 3, 45, 35, 27, 43, 5, 49, 33, 9, 42, 19, 29, 28, 14, 39, 12, 38, 41, 13, 37, 48, 7, 16, 24, 55, 40, 61, 26, 17, 0, 1, 60, 51, 30, 4, 22, 25, 54, 21, 56, 59, 6, 63, 57,
|
||||
// 62, 11, 36, 20, 34, 44, 52,
|
||||
// ];
|
||||
const array = JSON.parse(jsResponse.match(/\[(?:\d+,){63}\d+]/));
|
||||
const array = JSON.parse(jsResponse.match(/\[(?:\d+,){63}\d+\]/));
|
||||
const o = [];
|
||||
for (const t of array) {
|
||||
r.charAt(t) && o.push(r.charAt(t));
|
||||
|
|
@ -350,7 +350,7 @@ const getArticleDataFromCvid = async (cvid, uid) => {
|
|||
const newFormatData = JSON.parse(
|
||||
$('script:contains("window.__INITIAL_STATE__")')
|
||||
.text()
|
||||
.match(/window\.__INITIAL_STATE__\s*=\s*(.*?);\(/)[1]
|
||||
.match(/window\.__INITIAL_STATE__\s*=\s*(\S.*?)?;\(/)[1]
|
||||
);
|
||||
|
||||
if (newFormatData?.readInfo?.opus?.content?.paragraphs) {
|
||||
|
|
|
|||
|
|
@ -55,7 +55,8 @@ async function handler(ctx) {
|
|||
item.description = $('.article-main').html();
|
||||
item.author = $('.info')
|
||||
.text()
|
||||
.match(/作者:(.*)\s+来源/)[1];
|
||||
.match(/作者:(.*?)来源/)[1]
|
||||
.trim();
|
||||
return item;
|
||||
})
|
||||
)
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ const getItem = (item, selector) => {
|
|||
const newsDate = item
|
||||
.find('span')
|
||||
.text()
|
||||
.match(/\d{4}(-|\/|.)\d{1,2}\1\d{1,2}/)[0];
|
||||
.match(/\d{4}(.)\d{1,2}\1\d{1,2}/)[0];
|
||||
|
||||
const infoTitle = newsInfo.text();
|
||||
const link = rootURL + newsInfo.attr('href');
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ async function handler(ctx) {
|
|||
const content = load(response.data);
|
||||
const info = content('div.info')
|
||||
.text()
|
||||
.match(/作者:(.*?)\s+发布于:(.*?\s+.*?)\s/);
|
||||
.match(/作者:(\S*)\s+发布于:(\S*\s+.*?)\s/);
|
||||
item.author = info[1];
|
||||
item.pubDate = timezone(parseDate(info[2], 'YYYY-MM-DD HH:mm:ss'), +8);
|
||||
item.description = content('div#con').html().trim().replaceAll('\n', '');
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ const apiEndpoints = {
|
|||
},
|
||||
};
|
||||
|
||||
const pageTypeRegex1 = /\/(?<page>[\w-]*?)\/(?<link>\d{4}-\d{2}-\d{2}\/.*)/;
|
||||
const pageTypeRegex1 = /\/(?<page>[\w-]*)\/(?<link>\d{4}-\d{2}-\d{2}\/.*)/;
|
||||
const pageTypeRegex2 = /(?<!news|politics)\/(?<page>features\/|graphics\/)(?<link>.*)/;
|
||||
const regex = [pageTypeRegex1, pageTypeRegex2];
|
||||
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ async function handler(ctx) {
|
|||
statisticsTages.find('li, br, strong').remove();
|
||||
const statisticsStr = statisticsTages.text();
|
||||
|
||||
const regex = /(?<key>[^\s:]+)\s*:\s*(?<value>.+)/gm;
|
||||
const regex = /(?<key>[^\s:]+)\s*:\s*(?<value>.+)/g;
|
||||
const result = {};
|
||||
for (const match of statisticsStr.matchAll(regex)) {
|
||||
const { key, value } = match.groups ?? ({} as { key: string; value: string });
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ async function handler(ctx) {
|
|||
},
|
||||
});
|
||||
|
||||
const data = JSON.parse(response.data.match(/null\(\[({.*})]\)/)[1]);
|
||||
const data = JSON.parse(response.data.match(/null\(\[(\{.*\})\]\)/)[1]);
|
||||
|
||||
let items: DataItem[];
|
||||
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ async function handler(ctx) {
|
|||
const entity = JSON.parse(
|
||||
$('script')
|
||||
.text()
|
||||
.match(/var entity = ({.*?})/)[1]
|
||||
.match(/var entity = (\{.*?\})/)[1]
|
||||
);
|
||||
|
||||
const {
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export async function getFulltext(url: string) {
|
|||
if (!config.caixin.cookie) {
|
||||
return;
|
||||
}
|
||||
if (!/(\d+)\.html/.test(url)) {
|
||||
if (!/\d+\.html/.test(url)) {
|
||||
return;
|
||||
}
|
||||
const articleID = url.match(/(\d+)\.html/)[1];
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ async function handler() {
|
|||
const $ = load(response.data);
|
||||
|
||||
const author = $('.qtinfo.hidden-lg.hidden-md.hidden-sm').text();
|
||||
const reg = /文章来源:(.*?)\|/g;
|
||||
const reg = /文章来源:(.*?)\|/;
|
||||
|
||||
item.title = $('p.wztitle').text().trim();
|
||||
item.author = reg.exec(author)[1].toString().trim();
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
|||
|
||||
const metaStr: string = $$('div.newshead p span, div.title p span').text();
|
||||
const pubDateStr: string | undefined = metaStr?.match(/(\d{4}-\d{2}-\d{2})/)?.[1];
|
||||
const authors: DataItem['author'] = metaStr?.match(/来源:(.*?)/)?.[1];
|
||||
const authors: DataItem['author'] = metaStr?.match(/来源:(.*)/)?.[1];
|
||||
const upDatedStr: string | undefined = pubDateStr;
|
||||
|
||||
let processedItem: DataItem = {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ const extractDates = (durationStr: string) => {
|
|||
return { startDate, endDate };
|
||||
}
|
||||
|
||||
const parts = durationStr.split(/——|-|—|~/).map((p) => p.trim()); // currently ——and- is used, add — or ~ for redundency
|
||||
const parts = durationStr.split(/——|[-—~]/).map((p) => p.trim()); // currently ——and- is used, add — or ~ for redundency
|
||||
const startStr = parts[0];
|
||||
const endStr = parts[1];
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ async function handler(ctx) {
|
|||
const initialState = JSON.parse(
|
||||
$('script:contains("window.__INITIAL_STATE__")')
|
||||
.text()
|
||||
.match(/window\.__INITIAL_STATE__\s*=\s*({.*?});/)?.[1] || '{}'
|
||||
.match(/window\.__INITIAL_STATE__\s*=\s*(\{.*?\});/)?.[1] || '{}'
|
||||
);
|
||||
const { dataResult, indNavLists, secondNameFilter, tagList, param } = initialState.data;
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ export const handler = async (ctx) => {
|
|||
items = await Promise.all(
|
||||
items.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
if (!/^https?:\/\/www\.cisia\.org(\/[^\s]*)?$/.test(item.link)) {
|
||||
if (!/^https?:\/\/www\.cisia\.org(?:\/\S*)?$/.test(item.link)) {
|
||||
return item;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ function extractArticlesFromDOM($: CheerioAPI): DataItem[] {
|
|||
|
||||
// Extract date and author with single regex
|
||||
const metaText = element.find('.text-sm.text-slate-500').text().trim();
|
||||
const metaMatch = metaText.match(/^([^•]+)\s*•\s*([A-Za-z]+\s+\d{1,2},?\s+\d{4})/);
|
||||
const metaMatch = metaText.match(/^([^•]+)•\s*([A-Z]+\s+\d{1,2},?\s+\d{4})/i);
|
||||
const author = metaMatch ? metaMatch[1].trim() : 'Cline Team';
|
||||
const pubDate = metaMatch ? parseDate(metaMatch[2]) : undefined;
|
||||
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ function buildUrl(rootUrl: string, type: PostType, keyword: string | undefined,
|
|||
function extractHomeList($: CheerioAPI, rootUrl: string, limit: number): DataItem[] {
|
||||
try {
|
||||
const scriptText = $('script:contains("_PageData")').text();
|
||||
const match = scriptText.match(/const\s+_PageData\s*=\s*(\[[\s\S]*?]);/);
|
||||
const match = scriptText.match(/const\s+_PageData\s*=\s*(\[[\s\S]*?\]);/);
|
||||
|
||||
if (!match?.[1]) {
|
||||
return [];
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ async function handler(ctx) {
|
|||
const $ = load(response);
|
||||
if (item.link?.includes('/videos/')) {
|
||||
const ldJson = JSON.parse($('script[type="application/ld+json"]:contains("VideoObject")').text());
|
||||
const videoId = ldJson.embedUrl.match(/embed\/([a-zA-Z0-9_-]+)/)?.[1];
|
||||
const videoId = ldJson.embedUrl.match(/embed\/([\w-]+)/)?.[1];
|
||||
|
||||
item.description =
|
||||
`<iframe id="ytplayer" type="text/html" width="640" height="360" src="https://www.youtube-nocookie.com/embed/${videoId}" frameborder="0" allowfullscreen referrerpolicy="strict-origin-when-cross-origin"></iframe><br>` +
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ function extractCategories(article: ReturnType<CheerioAPI>, $: CheerioAPI): stri
|
|||
const tagText = tagElement.text().trim();
|
||||
|
||||
// Skip summary/stats links and navigation
|
||||
if (tagHref && tagText && !tagHref.includes('article/') && !tagHref.includes('Summary') && tagText.length < 50 && !/^(Summary|stats|About|Tags|Toggle|Trending|Latest|Previous|Next)$/i.test(tagText)) {
|
||||
if (tagHref && tagText && !tagHref.includes('article/') && !tagHref.includes('Summary') && tagText.length < 50 && !/^(?:Summary|stats|About|Tags|Toggle|Trending|Latest|Previous|Next)$/i.test(tagText)) {
|
||||
return tagText;
|
||||
}
|
||||
return null;
|
||||
|
|
|
|||
|
|
@ -20,14 +20,14 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
|||
// Group 3: Trailing hyphens (unused, but for context)
|
||||
// Group 4: Update content
|
||||
// Uses global and multiline flags for all matches and line start/end anchors
|
||||
const updateRegex = /^(-+)\s*\n(.*?)\s*\n(-+)\s*\n([\s\S]*?)(?=\n-{2,}|<\/p>)/gm;
|
||||
const updateRegex = /^-+[^\S\n]*\n(.*)\r?\n-+[^\S\n]*\n([\s\S]*?)(?=\n-{2}|<\/p>)/gm;
|
||||
|
||||
const items: DataItem[] = [];
|
||||
let match: RegExpExecArray | null;
|
||||
|
||||
while ((match = updateRegex.exec(response)) !== null && items.length < limit) {
|
||||
const headerLine: string | undefined = match[2].trim();
|
||||
const description: string | undefined = match[4].trim()?.replaceAll(/(\s[+-])/g, '<br>$1');
|
||||
const headerLine: string | undefined = match[1].trim();
|
||||
const description: string | undefined = match[2].trim()?.replaceAll(/(\s[+-])/g, '<br>$1');
|
||||
|
||||
let version = 'N/A';
|
||||
let pubDateStr: string | undefined = undefined;
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ async function handler(ctx) {
|
|||
const response = await got.get(currentUrl);
|
||||
const $ = load(response.data);
|
||||
const lists = $('div.c-box > div > div.c-zx-list > ul > li');
|
||||
const reg = /日期:(.*?(\s\(.*?\))?)\s/;
|
||||
const reg = /日期:(.*?(?:\s\(.*?\))?)\s/;
|
||||
const list = lists.toArray().map((item) => {
|
||||
item = $(item).find('div');
|
||||
let date = reg.exec(item.find('div.r > p.other').text())[1];
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ const ProcessFeed = async (items, cookies, browser, limit, cache) => {
|
|||
const data = JSON.parse(response);
|
||||
let body = data.content;
|
||||
body = body.replaceAll(/(?=https?:\/\/).*?(?<=\.(jpe?g|gif|png))/gi, (m) => `<img src="${m}">`);
|
||||
body = body.replaceAll(/(?=https?:\/\/).*(?<!jpe?g"?>?)$/gim, (m) => `<a href="${m}">${m}</a>`);
|
||||
body = body.replaceAll(/(?=https?:\/\/).+(?<!jpe?g"?>?)$/gim, (m) => `<a href="${m}">${m}</a>`);
|
||||
body = body.replaceAll('\n', '<br>');
|
||||
|
||||
return body;
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ async function fetchPage() {
|
|||
link: item.post_url || item.link || '',
|
||||
description: item.post_excerpt || item.excerpt || '',
|
||||
pubDate: item.post_date ? new Date(item.post_date).toUTCString() : item.date ? new Date(item.date).toUTCString() : '',
|
||||
category: item.category_link ? item.category_link.replaceAll(/(<([^>]+)>)/gi, '') : '', // Clean HTML if category_link exists
|
||||
category: item.category_link ? item.category_link.replaceAll(/(<([^>]+)>)/g, '') : '', // Clean HTML if category_link exists
|
||||
image: item.image_url ? item.image_url.replace(/\?.*$/, '') : '', // Remove query parameters if image_url exists
|
||||
}));
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import type { Route } from '@/types';
|
|||
import got from '@/utils/got';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
|
||||
const mentionPattern = /<\u2267\u2746>{"name":"(.*?)","uid":"\d+","at":"1"}<\/\u2266\u2746>/g;
|
||||
const mentionPattern = /<\u2267\u2746>\{"name":"(.*?)","uid":"\d+","at":"1"\}<\/\u2266\u2746>/g;
|
||||
|
||||
const formatNoteText = (text = '') => text.replaceAll('\n\n', '</p><p>').replaceAll(mentionPattern, ' @$1');
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ const types = {
|
|||
12: '视频',
|
||||
};
|
||||
|
||||
const mentionPattern = /<\u2267\u2746>{"name":"(.*?)","uid":"\d+","at":"1"}<\/\u2266\u2746>/g;
|
||||
const mentionPattern = /<\u2267\u2746>\{"name":"(.*?)","uid":"\d+","at":"1"\}<\/\u2266\u2746>/g;
|
||||
|
||||
const formatNoteText = (text = '') => text.replaceAll('\n\n', '</p><p>').replaceAll(mentionPattern, ' @$1');
|
||||
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ export const handler = async (ctx) => {
|
|||
return {
|
||||
title: $('title')
|
||||
.text()
|
||||
.replace(/\|.*?$/, `| ${$('li.onthis').text()}`),
|
||||
.replace(/\|.*$/, `| ${$('li.onthis').text()}`),
|
||||
description: $('meta[name="Description"]').prop('content'),
|
||||
link: currentUrl,
|
||||
item: items,
|
||||
|
|
|
|||
|
|
@ -75,7 +75,7 @@ async function handler(ctx) {
|
|||
headerGeneratorOptions: PRESETS.MODERN_IOS,
|
||||
});
|
||||
|
||||
const nickNameReg = /window\.nickName = "(.*?)"/g;
|
||||
const nickNameReg = /window\.nickName = "(.*?)"/;
|
||||
const nickName = nickNameReg.exec(pageResponse as string)?.[1];
|
||||
|
||||
const response = await ofetch(`https://m.dianping.com/member/ajax/NobleUserFeeds?userId=${id}`, {
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@ const extractArticle = (item) =>
|
|||
const { data: response } = await got(item.link);
|
||||
const $ = load(response);
|
||||
const scriptTagContent = $('script#fusion-metadata').text();
|
||||
const jsonData = JSON.parse(scriptTagContent.match(/Fusion\.globalContent=({.*?});Fusion\.globalContentConfig/)[1]).content_elements;
|
||||
const jsonData = JSON.parse(scriptTagContent.match(/Fusion\.globalContent=(\{.*?\});Fusion\.globalContentConfig/)[1]).content_elements;
|
||||
const filteredData = [];
|
||||
for (const v of jsonData) {
|
||||
if (v.type === 'header' && v.content.includes('What we’re reading')) {
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ export async function handler(ctx) {
|
|||
.map((item) => $(item).find('a').text());
|
||||
// Process date
|
||||
const timeText = $('p.dna-update').text();
|
||||
const dateMatch = timeText.match(/Updated\s*:\s*([\w\s,:\d]+?)(?:\s*\||$)/);
|
||||
const dateMatch = timeText.match(/Updated\s*:([\w\s,:]+)/);
|
||||
let time = dateMatch ? dateMatch[1].trim() : '';
|
||||
time = time.replace(/\s+IST$/, '');
|
||||
const pubDate = timezone(parseDate(time), +5.5);
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ function getDomList($, detailUrl) {
|
|||
export function getItemList($, detailUrl, second) {
|
||||
const encoded = $('.article script[type]')
|
||||
.text()
|
||||
.match(/return p}\('(.*)',(\d+),(\d+),'(.*)'.split\(/);
|
||||
.match(/return p\}\('(.*)',(\d+),(\d+),'(.*)'.split\(/);
|
||||
// 若 script 标签没有内容,直接解析 dom
|
||||
if (!encoded) {
|
||||
return getDomList($, detailUrl);
|
||||
|
|
|
|||
|
|
@ -145,7 +145,7 @@ const ProcessFeedType3 = (item, response) => {
|
|||
const initialState = JSON.parse(
|
||||
$('script:contains("window.__INITIAL_STATE__")')
|
||||
.text()
|
||||
.match(/window\.__INITIAL_STATE__\s*=\s*(.*?);\(/)[1]
|
||||
.match(/window\.__INITIAL_STATE__\s*=\s*((?:\S.*?)??);\(/)[1]
|
||||
);
|
||||
|
||||
// filter out undefined item
|
||||
|
|
|
|||
|
|
@ -85,6 +85,6 @@ async function getContent(nextBuildId: string, contentId: string) {
|
|||
content
|
||||
.html()
|
||||
?.replaceAll(rubyRegex, '$1($2)')
|
||||
?.replaceAll(/[^\u0009\u000A\u000D\u0020-\uD7FF\uE000-\uFDCF\uFDE0-\uFFFD]/gm, '') ?? '';
|
||||
?.replaceAll(/[^\t\n\r\u0020-\uD7FF\uE000-\uFDCF\uFDE0-\uFFFD]/g, '') ?? '';
|
||||
return description;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ async function handler(ctx) {
|
|||
method: 'get',
|
||||
url: item.link,
|
||||
});
|
||||
const match = detailResponse.data.match(/'comments':(.*)}],/);
|
||||
const match = detailResponse.data.match(/'comments':(.*)\}\],/);
|
||||
|
||||
if (match.length > 1) {
|
||||
const content = load(detailResponse.data);
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ async function handler(ctx) {
|
|||
url: item.link,
|
||||
});
|
||||
|
||||
const comments = JSON.parse(detailResponse.data.match(/'comments':(.*)}],/)[1] + '}]');
|
||||
const comments = JSON.parse(detailResponse.data.match(/'comments':(.*)\}\],/)[1] + '}]');
|
||||
|
||||
for (const c of comments) {
|
||||
if (c.id === item.link.split('#')[1]) {
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ async function loadContent(link) {
|
|||
const shotData = JSON.parse(
|
||||
$('script')
|
||||
.text()
|
||||
.match(/shotData:\s({.+?}),\n/)?.[1] ?? '{}'
|
||||
.match(/shotData:\s(\{.+?\}),\n/)?.[1] ?? '{}'
|
||||
);
|
||||
|
||||
// Join multiple shots together by selecting elements with class 'media-shot' or 'main-shot' or 'block-media-wrapper'
|
||||
|
|
|
|||
|
|
@ -161,7 +161,7 @@ function getBittorrent(cache, bittorrent_page_url) {
|
|||
const match = onclick.match(/'(.*?)'/);
|
||||
if (match) {
|
||||
bittorrent_url = match[1];
|
||||
const match_p = bittorrent_url.match(/torrent\?p=(.*?)$/);
|
||||
const match_p = bittorrent_url.match(/torrent\?p=(.*)$/);
|
||||
if (match_p) {
|
||||
p = match_p[1];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ async function handler(ctx: Context): Promise<Data> {
|
|||
const initialState = JSON.parse(
|
||||
$('script:contains("window.__INITIAL_STATE__")')
|
||||
.text()
|
||||
.match(/window\.__INITIAL_STATE__\s*=\s*(.*);/)?.[1] ?? '{}'
|
||||
.match(/window\.__INITIAL_STATE__\s*=\s*(\S.*);/)?.[1] ?? '{}'
|
||||
);
|
||||
|
||||
const page = initialState.page as Page;
|
||||
|
|
|
|||
|
|
@ -29,34 +29,32 @@ export const route: Route = {
|
|||
};
|
||||
|
||||
async function handlerRoute(): Promise<Data> {
|
||||
const response = await ofetch('https://flashcat.cloud/blog/');
|
||||
const baseUrl = 'https://flashcat.cloud';
|
||||
const link = `${baseUrl}/blog/`;
|
||||
const response = await ofetch(link);
|
||||
const $ = load(response);
|
||||
|
||||
const items = $('.post-preview')
|
||||
const items = $('.fc-content-card')
|
||||
.toArray()
|
||||
.map((elem) => {
|
||||
const $elem = $(elem);
|
||||
const $item = $(elem);
|
||||
const [author, date] = $item
|
||||
.find('.fc-content-card-meta')
|
||||
.text()
|
||||
.split('·')
|
||||
.map((s) => s.trim());
|
||||
return {
|
||||
title: $elem.find('.post-title').text(),
|
||||
description: $elem.find('.post-content-preview').text(),
|
||||
link: $elem.find('a').attr('href'),
|
||||
pubDate: parseDate(
|
||||
$elem
|
||||
.find('.post-meta')
|
||||
.text()
|
||||
.match(/on\s+(\w+,\s+\w+\s+\d{1,2},\s+\d{4})/)?.[1] || ''
|
||||
),
|
||||
author:
|
||||
$elem
|
||||
.find('.post-meta')
|
||||
.text()
|
||||
.match(/by\s+(.+?)\s+on/)?.[1] || '',
|
||||
title: $item.find('.fc-content-card-title').text(),
|
||||
description: $item.find('.fc-content-card-summary').text().trim(),
|
||||
link: new URL($item.find('.fc-content-card-link').attr('href')!, baseUrl).href,
|
||||
pubDate: date ? parseDate(date, 'YYYY-MM-DD') : undefined,
|
||||
author,
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
title: 'Flashcat 快猫星云博客',
|
||||
link: 'https://flashcat.cloud/blog/',
|
||||
link,
|
||||
item: items,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ async function handler(ctx) {
|
|||
}
|
||||
|
||||
const anime = response.data.anime;
|
||||
const title = anime.title.replaceAll(/\[\d+?]$/g, '').trim();
|
||||
const title = anime.title.replaceAll(/\[\d+\]$/g, '').trim();
|
||||
|
||||
const items = anime.volumes[0]
|
||||
.map((item) => ({
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ async function handler(ctx) {
|
|||
|
||||
const { data: response } = await got(apiUrl);
|
||||
|
||||
const items = (Array.isArray(response) ? response : JSON.parse(response.match(/(\[.*])$/)[1])).slice(0, limit).map((item) => {
|
||||
const items = (Array.isArray(response) ? response : JSON.parse(response.match(/(\[.*\])$/)[1])).slice(0, limit).map((item) => {
|
||||
const terminologies = item._embedded['wp:term'];
|
||||
|
||||
const content = load(item.content?.rendered ?? item.content);
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ const getAbsoluteUrl = (path: string | undefined) => (path ? new URL(path, ROOT_
|
|||
const getArticleAuthor = ($: ReturnType<typeof load>) =>
|
||||
$('#article .items p')
|
||||
.text()
|
||||
.match(/Posted by\s+(.+)$/)?.[1]
|
||||
.match(/Posted by\s+(\S.*)$/)?.[1]
|
||||
?.trim();
|
||||
const getArticleCategories = ($: ReturnType<typeof load>) => [
|
||||
...new Set(
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ async function handler(ctx) {
|
|||
item
|
||||
.find('p.p4')
|
||||
.text()
|
||||
.match(/] (\d+\.\d+);/)[1],
|
||||
.match(/\] (\d+\.\d+);/)[1],
|
||||
],
|
||||
enclosure_url: link,
|
||||
enclosure_length:
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ async function handler(ctx) {
|
|||
|
||||
const real_url = response.request.options.url.href;
|
||||
|
||||
const info = JSON.parse(response.data.match(/AF_initDataCallback.*?data:(\[[\S\s]*])\s/m)[1]) || [];
|
||||
const info = JSON.parse(response.data.match(/AF_initDataCallback.*?data:(\[[\s\S]*\])\s/)[1]) || [];
|
||||
|
||||
const album_name = info[3][1];
|
||||
const owner_name = info[3][5][2];
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ async function handler(ctx) {
|
|||
let description = `Google Scholar Monitor Query: ${query}`;
|
||||
|
||||
if (params.includes('as_q=')) {
|
||||
const reg = /as_q=(.*?)&/g;
|
||||
const reg = /as_q=(.*?)&/;
|
||||
query = reg.exec(params)[1];
|
||||
description = `Google Scholar Monitor Advanced Query: ${query}`;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -23,10 +23,10 @@ async function handler(ctx) {
|
|||
const title = $('a.bt_link').last().text().replace('>', '');
|
||||
const dataJs = $('div.left.zhengce_right > script[language="javascript"]').html() || $('div.centent_width > script[language="javascript"]').html();
|
||||
let items = dataJs
|
||||
.match(/urls\[i]='(.*?)';headers\[i]="(.*?)";year\[i]='(\d+)';month\[i]='(\d+)';day\[i]='(\d+)';/g)
|
||||
.match(/urls\[i\]='(.*?)';headers\[i\]="(.*?)";year\[i\]='(\d+)';month\[i\]='(\d+)';day\[i\]='(\d+)';/g)
|
||||
.slice(0, ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 25)
|
||||
.map((item) => {
|
||||
const result = item.match(/urls\[i]='(.*?)';headers\[i]="(.*?)";year\[i]='(\d+)';month\[i]='(\d+)';day\[i]='(\d+)';/);
|
||||
const result = item.match(/urls\[i\]='(.*?)';headers\[i\]="(.*?)";year\[i\]='(\d+)';month\[i\]='(\d+)';day\[i\]='(\d+)';/);
|
||||
return {
|
||||
title: load(result[2])('a').attr('title') || result[2],
|
||||
link: new URL(result[1], rootUrl).href,
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ async function handler(ctx) {
|
|||
.toArray()
|
||||
.map((item) => {
|
||||
const href = $(item).attr('href');
|
||||
if (href && /(?:http:)?\/\/www\.cac\.gov\.cn(.*?)\/(A.*?\.htm)/.test(href)) {
|
||||
if (href && /(?:http:)?\/\/www\.cac\.gov\.cn.*?\/A.*?\.htm/.test(href)) {
|
||||
const matchArray = href.match(/(?:http:)?\/\/www\.cac\.gov\.cn(.*?)\/(A.*?\.htm)/);
|
||||
if (matchArray && matchArray.length > 2) {
|
||||
const path = matchArray[1];
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ const cookieJar = new CookieJar();
|
|||
|
||||
const owner = '中央纪委国家监委网站';
|
||||
const rootUrl = 'https://www.ccdi.gov.cn';
|
||||
const regex = /(?<key>[A-Z_]+)=(?<value>(?:.*?(?=; max-age)|[\dA-Fa-f]+))/gm;
|
||||
const regex = /(?<key>[A-Z_]+)=(?<value>.*?(?=; max-age)|[\dA-Fa-f]+)/g;
|
||||
|
||||
const parseCookie = async (body) => {
|
||||
let m;
|
||||
|
|
|
|||
|
|
@ -88,13 +88,13 @@ async function handler(ctx) {
|
|||
let pubDate;
|
||||
let author;
|
||||
let category;
|
||||
if (/dysMiddleResultConItemTitle/g.test(item.html())) {
|
||||
if (/dysMiddleResultConItemTitle/.test(item.html())) {
|
||||
if (contentUrl.includes('content')) {
|
||||
fullTextGet = await got.get(contentUrl);
|
||||
fullTextData = load(fullTextGet.data);
|
||||
fullTextData('.shuzi').remove(); // 移除videobg的图片
|
||||
fullTextData('#myFlash').remove(); // 移除flash
|
||||
description = /pages_content/g.test(fullTextData.html()) ? fullTextData('.pages_content').html() : fullTextData('#UCAP-CONTENT').html();
|
||||
description = /pages_content/.test(fullTextData.html()) ? fullTextData('.pages_content').html() : fullTextData('#UCAP-CONTENT').html();
|
||||
} else {
|
||||
description = item.find('a').text(); // 忽略获取吹风会的全文
|
||||
}
|
||||
|
|
@ -105,13 +105,13 @@ async function handler(ctx) {
|
|||
pubDate = timezone(parseDate(fullTextData('meta[name="firstpublishedtime"]').attr('content'), 'YYYY-MM-DD HH:mm:ss'), 8);
|
||||
author = fullTextData('meta[name="author"]').attr('content');
|
||||
category = fullTextData('meta[name="keywords"]').attr('content').split(/[,;]/);
|
||||
if (/zhengceku/g.test(contentUrl)) {
|
||||
if (/zhengceku/.test(contentUrl)) {
|
||||
// 政策文件库
|
||||
description = fullTextData('.pages_content').html();
|
||||
} else {
|
||||
fullTextData('.shuzi').remove(); // 移除videobg的图片
|
||||
fullTextData('#myFlash').remove(); // 移除flash
|
||||
description = /UCAP-CONTENT/g.test($1) ? fullTextData('#UCAP-CONTENT').html() : fullTextData('body').html();
|
||||
description = /UCAP-CONTENT/.test($1) ? fullTextData('#UCAP-CONTENT').html() : fullTextData('body').html();
|
||||
}
|
||||
} else {
|
||||
description = item.find('a').text(); // 忽略获取吹风会的全文
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ const gdgov = async (info, ctx) => {
|
|||
title: data.art_title,
|
||||
description: renderZcjdpt(data),
|
||||
pubDate: timezone(parseDate(data.pub_time), +8),
|
||||
author: /(本|本网|本站)/.test(data.pub_unite) ? authorisme : data.pub_unite,
|
||||
author: /本/.test(data.pub_unite) ? authorisme : data.pub_unite,
|
||||
};
|
||||
});
|
||||
} else if (idlink.host === 'mp.weixin.qq.com') {
|
||||
|
|
@ -217,7 +217,7 @@ const gdgov = async (info, ctx) => {
|
|||
title,
|
||||
description,
|
||||
pubDate: timezone(parseDate(pubDate, pubDate_format), +8),
|
||||
author: /本|本网|本站/.test(author) ? authorisme : author,
|
||||
author: /本/.test(author) ? authorisme : author,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ async function handler() {
|
|||
const tfxtqJsUrl = `${rootUrl}/data/gzWeather/weatherTips.js`;
|
||||
|
||||
const response = await got.get(tfxtqJsUrl);
|
||||
const data = JSON.parse(`[{${response.data.match(/Tips = {(.*?)}/)[1]}}]`);
|
||||
const data = JSON.parse(`[{${response.data.match(/Tips = \{(.*?)\}/)[1]}}]`);
|
||||
|
||||
const items = data.map((item) => ({
|
||||
title: item.title,
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ async function handler(ctx) {
|
|||
|
||||
item.description = content('#con_con')
|
||||
.html()
|
||||
?.replaceAll(/(<iframe.*?src=")(.*?)(".*?>)/g, '$1' + rootUrl + '$2$3');
|
||||
?.replaceAll(/(<iframe.*?src=")([^"]*)(".*?>)/g, '$1' + rootUrl + '$2$3');
|
||||
|
||||
return item;
|
||||
})
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ async function handler() {
|
|||
|
||||
item.description = content('#con_con')
|
||||
.html()
|
||||
?.replaceAll(/(<iframe.*?src=")(.*?)(".*?>)/g, '$1' + rootUrl + '$2$3');
|
||||
?.replaceAll(/(<iframe.*?src=")([^"]*)(".*?>)/g, '$1' + rootUrl + '$2$3');
|
||||
|
||||
return item;
|
||||
})
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ async function handler(ctx) {
|
|||
cache.tryGet(item.link, async () => {
|
||||
let responses = await got(item.link);
|
||||
// xwfb/xwlxfbh || xwfb/xwztfbh
|
||||
const redirect = responses.data.match(/_cofing1={href:"(.*)",type/) || responses.data.match(/window\.location\.href='(.*)'/);
|
||||
const redirect = responses.data.match(/_cofing1=\{href:"(.*)",type/) || responses.data.match(/window\.location\.href='(.*)'/);
|
||||
if (redirect) {
|
||||
responses = await got(redirect[1], {
|
||||
headers: {
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ async function handler(ctx) {
|
|||
url: currentUrl,
|
||||
});
|
||||
|
||||
const regex = /<!\[cdata\[([\S\s]*?)]]>(?=\s*<)/gi;
|
||||
const regex = /<!\[cdata\[([\s\S]*?)\]\]>(?=\s*<)/gi;
|
||||
const data = response.data.replaceAll(regex, '$1');
|
||||
|
||||
const $ = load(data, {
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ async function handler(ctx) {
|
|||
title: item.prop('title') ?? item.text(),
|
||||
link: new URL(item.prop('href'), rootUrl).href,
|
||||
guid: `nsfc-${item.prop('id')}`,
|
||||
pubDate: parseDate(item.next().text().replace(/\[]/g, '', ['YYYY-MM-DD', 'YY-MM-DD'])),
|
||||
pubDate: parseDate(item.next().text().replace(/\[\]/g, '', ['YYYY-MM-DD', 'YY-MM-DD'])),
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ async function handler(ctx) {
|
|||
|
||||
// articles from www.news.cn or www.gov.cn
|
||||
|
||||
if (/(news\.cn|www\.gov\.cn)/.test(item.link)) {
|
||||
if (/news\.cn|www\.gov\.cn/.test(item.link)) {
|
||||
if (content('.year').text()) {
|
||||
item.pubDate = timezone(parseDate(`${content('.year').text()}/${content('.day').text()} ${content('.time').text()}`, 'YYYY/MM/DD HH:mm:ss'), +8);
|
||||
item.author = content('.source')
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ async function handler(ctx) {
|
|||
});
|
||||
const query = `${params.toString()}&${advance}`;
|
||||
const res = await got.get(link, {
|
||||
searchParams: query.replaceAll(/([\u4E00-\u9FA5])/g, (str) => encodeURIComponent(str)),
|
||||
searchParams: query.replaceAll(/[\u4E00-\u9FA5]/g, (str) => encodeURIComponent(str)),
|
||||
});
|
||||
const $ = load(res.data);
|
||||
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ export const route: Route = {
|
|||
return {
|
||||
title: `宁波市国资委-${noticeCate}:${title.text()}`,
|
||||
link: `http://gzw.ningbo.gov.cn${title.attr('href')}`,
|
||||
pubDate: parseDate($('p').text().replaceAll(/\[|]/g, '')),
|
||||
pubDate: parseDate($('p').text().replaceAll(/\[|\]/g, '')),
|
||||
author: '宁波市国资委',
|
||||
description: title.text(),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ export const route: Route = {
|
|||
return {
|
||||
title: `宁波人社公告-${noticeCate}:${title.text()}`,
|
||||
link: `http://rsj.ningbo.gov.cn${title.attr('href')}`,
|
||||
pubDate: parseDate($('.news_date').text().replaceAll(/\[|]/g, '')),
|
||||
pubDate: parseDate($('.news_date').text().replaceAll(/\[|\]/g, '')),
|
||||
author: '宁波市人力资源和社会保障局',
|
||||
description: title.text(),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ async function handler(ctx) {
|
|||
const minuteRelativeTime = /(\d+)\s*分钟前/;
|
||||
const hourRelativeTime = /(\d+)\s*小时前/;
|
||||
const yesterdayRelativeTime = /昨天\s*(\d+):(\d+)/;
|
||||
const shortDate = /(\d+)-(\d+)\s*(\d+):(\d+)/;
|
||||
const shortDate = /(\d+)-(\d+)\s+(\d+):(\d+)/;
|
||||
|
||||
// offset to ADD for transforming China time to UTC
|
||||
const chinaToUtcOffset = -8 * 3600 * 1000;
|
||||
|
|
|
|||
|
|
@ -110,7 +110,7 @@ const ProcessItems = (items, limit, tryGet) =>
|
|||
url: item.link,
|
||||
});
|
||||
|
||||
const content = JSON.parse(detailResponse.data.match(/"__NEXT_DATA__" type="application\/json">({"props":.*})<\/script>/)[1]);
|
||||
const content = JSON.parse(detailResponse.data.match(/"__NEXT_DATA__" type="application\/json">(\{"props":.*\})<\/script>/)[1]);
|
||||
|
||||
item.description = renderDescription({
|
||||
image: content.props.initialProps.pageProps.article.originalImage.cdnUrl,
|
||||
|
|
|
|||
|
|
@ -158,7 +158,7 @@ async function handler(ctx) {
|
|||
.toArray()
|
||||
.map((e) => content(e).text().trim());
|
||||
item.description = renderDesc(articleImg, content('div#article-content').html());
|
||||
item.pubDate = timezone(/(今|昨)/.test(pubDate) ? parseRelativeDate(pubDate) : parseDate(pubDate, 'YYYY M D'), +8);
|
||||
item.pubDate = timezone(/今|昨/.test(pubDate) ? parseRelativeDate(pubDate) : parseDate(pubDate, 'YYYY M D'), +8);
|
||||
|
||||
return item;
|
||||
})
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ async function handler(ctx) {
|
|||
url: apiUrl,
|
||||
});
|
||||
|
||||
const list = JSON.parse(response.data.match(/"data":(\[{.*}])}/)[1]).map((item) => {
|
||||
const list = JSON.parse(response.data.match(/"data":(\[\{.*\}\])\}/)[1]).map((item) => {
|
||||
let link: string;
|
||||
|
||||
if (item.UrlPath_en) {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ const MAPs = {
|
|||
};
|
||||
|
||||
const ProcessFeed = async (type, id, order) => {
|
||||
let link = MAPs[type].url.replace(/{id}/, id).replace(/{order}/, order || 'add');
|
||||
let link = MAPs[type].url.replace(/\{id\}/, id).replace(/\{order\}/, order || 'add');
|
||||
let response = await got({
|
||||
method: 'get',
|
||||
url: link,
|
||||
|
|
@ -35,7 +35,7 @@ const ProcessFeed = async (type, id, order) => {
|
|||
let $ = load(response.data);
|
||||
|
||||
if (type === 'work') {
|
||||
const overviewLink = MAPs.overview.url.replace(/{id}/, id);
|
||||
const overviewLink = MAPs.overview.url.replace(/\{id\}/, id);
|
||||
const overviewResponse = await got({
|
||||
method: 'get',
|
||||
url: overviewLink,
|
||||
|
|
|
|||
|
|
@ -238,8 +238,8 @@ export function getEntryDetails(item: DataItem): Promise<DataItem> {
|
|||
// Possible formats: 10:21, 45分钟前, 09-15 19:57
|
||||
const currentYear = new Date().getFullYear();
|
||||
const currentDate = new Date();
|
||||
const monthDayTimePattern = /^(\d{2})-(\d{2}) (\d{2}):(\d{2})$/;
|
||||
const timeOnlyPattern = /^(\d{1,2}):(\d{2})$/;
|
||||
const monthDayTimePattern = /^\d{2}-\d{2} \d{2}:\d{2}$/;
|
||||
const timeOnlyPattern = /^\d{1,2}:\d{2}$/;
|
||||
let processedDateString = pubDateString;
|
||||
|
||||
if (monthDayTimePattern.test(pubDateString)) {
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ async function handler() {
|
|||
allUrlList.map(async (item) => {
|
||||
const { data: response } = await got(item);
|
||||
const $$ = load(response);
|
||||
const regVol = /(?<=Vol. )(\w+)/;
|
||||
const regVol = /(?<=Vol. )\w+/;
|
||||
const match = regVol.exec($$('div.vp-page-title').find('h1').text());
|
||||
const volume = match ? match[0] : '';
|
||||
const links = $$('div.theme-hope-content > ul a')
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ async function handler(ctx) {
|
|||
const _allData = JSON.parse(
|
||||
$('script')
|
||||
.text()
|
||||
.match(/var allData = ({.*?});/)[1]
|
||||
.match(/var allData = (\{.*?\});/)[1]
|
||||
);
|
||||
if (type === 'doc') {
|
||||
item.description = extractDoc(_allData.docData.contentData.contentList);
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ async function handler(ctx) {
|
|||
|
||||
const $ = load(response.data);
|
||||
|
||||
const newsStream = JSON.parse(response.data.match(/"newsstream":(\[.*?]),"cooperation"/)[1]);
|
||||
const newsStream = JSON.parse(response.data.match(/"newsstream":(\[.*?\]),"cooperation"/)[1]);
|
||||
|
||||
let items = newsStream.slice(0, limit).map((item) => ({
|
||||
title: item.title,
|
||||
|
|
@ -47,9 +47,9 @@ async function handler(ctx) {
|
|||
});
|
||||
|
||||
item.author = detailResponse.data.match(/"editorName":"(.*?)",/)[1];
|
||||
item.category = detailResponse.data.match(/},"keywords":"(.*?)",/)[1].split(',');
|
||||
item.category = detailResponse.data.match(/\},"keywords":"(.*?)",/)[1].split(',');
|
||||
const image = item.description;
|
||||
const description = JSON.parse(detailResponse.data.match(/"contentList":(\[.*?]),/)[1]).map((content) => content.data);
|
||||
const description = JSON.parse(detailResponse.data.match(/"contentList":(\[.*?\]),/)[1]).map((content) => content.data);
|
||||
item.description = renderToString(
|
||||
<>
|
||||
{image ? (
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ async function handler(ctx) {
|
|||
parseDate(
|
||||
$('div.editor')
|
||||
.html()
|
||||
.split(/(\s\s+)/)[2]
|
||||
.split(/(\s{2,})/)[2]
|
||||
),
|
||||
+8
|
||||
);
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export const parseThumbnail = (type: 'video' | 'image', item: any) => {
|
|||
}
|
||||
|
||||
// regex borrowed from https://stackoverflow.com/a/3726073
|
||||
const match = /https?:\/\/(?:www\.)?youtu(?:be\.com\/watch\?v=|\.be\/)([\w-]*)(&(amp;)?[\w=?]*)?/.exec(item.embedUrl);
|
||||
const match = /https?:\/\/(?:www\.)?youtu(?:be\.com\/watch\?v=|\.be\/)([\w-]*)(?:&(?:amp;)?[\w=?]*)?/.exec(item.embedUrl);
|
||||
if (match) {
|
||||
return `<img src="${imageRootUrl}/image/embed/original/youtube/${match[1]}">`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ async function handler(ctx) {
|
|||
throw new Error('Failed to find SSR_HYDRATED_DATA');
|
||||
}
|
||||
|
||||
const jsonData = JSON.parse(jsData.match(/var\s+data\s*=\s*({.*?});/s)?.[1].replaceAll('undefined', 'null') || '{}');
|
||||
const jsonData = JSON.parse(jsData.match(/var\s+data\s*=\s*(\{.*?\});/s)?.[1].replaceAll('undefined', 'null') || '{}');
|
||||
|
||||
const {
|
||||
AuthorVideoList: { videoList: videoInfos },
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ export const extractPageId = async (url: string, referer: string): Promise<strin
|
|||
|
||||
$('script').each((_, script) => {
|
||||
const content = $(script).html() || '';
|
||||
const match = content.match(/PAGE\s*=\s*{\s*id\s*:\s*(\d+)\s*}/);
|
||||
const match = content.match(/PAGE\s*=\s*\{\s*id\s*:\s*(\d+)\s*\}/);
|
||||
if (match) {
|
||||
pageId = match[1];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import got from '@/utils/got';
|
|||
import { parseDate } from '@/utils/parse-date';
|
||||
|
||||
const toSize = (raw) => {
|
||||
const matches = raw.match(/(\d+(\.\d+)?)(\w+)/);
|
||||
const matches = raw.match(/(\d+(\.\d+)?)(\D\w*)/);
|
||||
return matches[3] === 'GB' ? matches[1] * 1024 : matches[1];
|
||||
};
|
||||
|
||||
|
|
@ -154,7 +154,7 @@ async function handler(ctx) {
|
|||
// To fetch magnets.
|
||||
|
||||
try {
|
||||
const matches = detailResponse.data.match(/var gid = (\d+);[\S\s]*var uc = (\d+);[\S\s]*var img = '(.*)';/);
|
||||
const matches = detailResponse.data.match(/var gid = (\d+);[\s\S]*var uc = (\d+);[\s\S]*var img = '(.*)';/);
|
||||
|
||||
const magnetResponse = await got({
|
||||
method: 'get',
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ export const handler = async (ctx): Promise<Data> => {
|
|||
const href = item.prop('href');
|
||||
const link = href ? (href.startsWith('/') ? new URL(href, rootUrl).href : href) : undefined;
|
||||
|
||||
if (link && /\/(article|video)\/\w+\.html/.test(link)) {
|
||||
if (link && /\/(?:article|video)\/\w+\.html/.test(link)) {
|
||||
items[link] = {
|
||||
title: item.text(),
|
||||
link,
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ async function handler(ctx) {
|
|||
|
||||
const single = {
|
||||
title: `${typeMap[item.type]}了: ${shortenTitle}`,
|
||||
description: `${content}${linkTemplate}${imgTemplate}`.replace(/(<br>|\s)+$/, ''),
|
||||
description: `${content}${linkTemplate}${imgTemplate}`.replace(/(?:<br>|\s)+$/, ''),
|
||||
pubDate: parseDate(item.createdAt),
|
||||
link: getLink(item.id, item.type),
|
||||
_extra: repostContent && {
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ const topicDataHanding = (data, ctx) =>
|
|||
// default:
|
||||
// break;
|
||||
// }
|
||||
const imgUrl = /\.[\da-z]+?\?imageMogr2/.test(pic.picUrl) ? pic.picUrl.split('?imageMogr2/')[0] : pic.picUrl.replace(/thumbnail\/.+/, '');
|
||||
const imgUrl = /\.[\da-z]+\?imageMogr2/.test(pic.picUrl) ? pic.picUrl.split('?imageMogr2/')[0] : pic.picUrl.replace(/thumbnail\/.+/, '');
|
||||
description += `<br><img src="${imgUrl}">`;
|
||||
// description += `<br><picture><source srcset="${
|
||||
// pic.picUrl.split('/thumbnail/')[0]
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ async function handler(ctx) {
|
|||
const bookInfoWrap = detailPage('div.info_wrap').html() || '';
|
||||
|
||||
const processedDescription = bookDescription.replaceAll(/<img\b[^>]*>/g, (imgTag) =>
|
||||
imgTag.replaceAll(/\b(src|data-src)="(?!http|https|\/\/)([^"]*)"/g, (_, attrName, relativePath) => {
|
||||
imgTag.replaceAll(/\b(src|data-src)="(?!http|\/\/)([^"]*)"/g, (_, attrName, relativePath) => {
|
||||
const absoluteImageUrl = new URL(relativePath, baseUrl).href;
|
||||
return `${attrName}="${absoluteImageUrl}"`;
|
||||
})
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue