mirror of
https://github.com/DIYgod/RSSHub.git
synced 2026-10-13 08:48:59 +08:00
chore(deps-dev): bump eslint-plugin-unicorn from 74.0.0 to 75.0.0 (#23338)
* chore(deps-dev): bump eslint-plugin-unicorn from 74.0.0 to 75.0.0 Bumps [eslint-plugin-unicorn](https://github.com/sindresorhus/eslint-plugin-unicorn) from 74.0.0 to 75.0.0. - [Release notes](https://github.com/sindresorhus/eslint-plugin-unicorn/releases) - [Commits](https://github.com/sindresorhus/eslint-plugin-unicorn/compare/v74.0.0...v75.0.0) --- updated-dependencies: - dependency-name: eslint-plugin-unicorn dependency-version: 75.0.0 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> * style: fix unicorn-js/prefer-combined-guards * style: fix prefer-smaller-scope * style: fix prefer-continue * style: fix prefer-early-return * style: fix prefer-iterator-helpers * style: add v75 recommended preset --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Tony <TonyRL@users.noreply.github.com>
This commit is contained in:
+8
-1
@@ -195,6 +195,7 @@
|
||||
"unicorn-js/no-array-sort-for-min-max": "error",
|
||||
"unicorn-js/no-array-splice": "error",
|
||||
"unicorn-js/no-async-promise-finally": "error",
|
||||
"unicorn-js/no-async-iterator-callback": "error",
|
||||
// "unicorn/no-await-expression-member": "error",
|
||||
"unicorn/no-await-in-promise-methods": "error",
|
||||
// "unicorn-js/no-blob-to-file": "error", // unused
|
||||
@@ -292,7 +293,8 @@
|
||||
"unicorn-js/no-unsafe-property-key": "error",
|
||||
// "unicorn-js/no-unsafe-sqlite-interpolation": "error", // unused
|
||||
"unicorn-js/no-unsafe-string-replacement": "error",
|
||||
"unicorn-js/no-unused-array-method-return": "error",
|
||||
"unicorn-js/no-unused-builtin-method-return": "error",
|
||||
"unicorn-js/no-unused-iterator-helper": "error",
|
||||
"unicorn-js/no-useless-boolean-cast": "error",
|
||||
"unicorn-js/no-useless-coercion": "error",
|
||||
"unicorn/no-useless-collection-argument": "error",
|
||||
@@ -311,9 +313,11 @@
|
||||
"unicorn-js/no-useless-re-export": "error",
|
||||
// "unicorn-js/no-useless-recursion": "error", unopinionated
|
||||
"unicorn/no-useless-spread": "error",
|
||||
"unicorn-js/no-useless-set-construction": "error",
|
||||
// "unicorn/no-useless-switch-case": "error",
|
||||
"unicorn-js/no-useless-template-literals": "error",
|
||||
// "unicorn/no-useless-undefined": "error",
|
||||
"unicorn-js/no-using-resource-escape": "error",
|
||||
"unicorn-js/no-xor-as-exponentiation": "error",
|
||||
"unicorn/no-zero-fractions": "error",
|
||||
// "unicorn/number-literal-case": "error",
|
||||
@@ -342,6 +346,7 @@
|
||||
"unicorn-js/prefer-block-statement-over-iife": "error",
|
||||
"unicorn-js/prefer-boolean-return": "error",
|
||||
"unicorn/prefer-class-fields": "error",
|
||||
"unicorn-js/prefer-combined-guards": "error",
|
||||
// "unicorn/prefer-classlist-toggle": "error", // unused
|
||||
// "unicorn/prefer-code-point": "error",
|
||||
"unicorn-js/prefer-continue": "error",
|
||||
@@ -372,6 +377,7 @@
|
||||
"unicorn-js/prefer-iterable-in-constructor": "error",
|
||||
"unicorn-js/prefer-iterator-helpers": "error",
|
||||
"unicorn-js/prefer-iterator-to-array": "error",
|
||||
"unicorn-js/prefer-iterator-zip": "error",
|
||||
// "unicorn-js/prefer-iterator-to-array-at-end": "error",
|
||||
// "unicorn/prefer-keyboard-event-key": "error", // unused
|
||||
"unicorn-js/prefer-location-assign": "error",
|
||||
@@ -431,6 +437,7 @@
|
||||
// "unicorn/prefer-string-starts-ends-with": "error", use typescript/prefer-string-starts-ends-with
|
||||
"unicorn/prefer-string-trim-start-end": "error",
|
||||
"unicorn/prefer-structured-clone": "error",
|
||||
"unicorn-js/prefer-temporal-conversion": "error",
|
||||
// "unicorn/prefer-switch": "error",
|
||||
"unicorn/prefer-ternary": "error",
|
||||
"unicorn-js/prefer-then-catch": "error",
|
||||
|
||||
+58
-56
@@ -141,71 +141,73 @@ export default eslintCompatPlugin({
|
||||
const routeDeclaration = node.declaration.declarations[0];
|
||||
const routeObject = routeDeclaration.init;
|
||||
|
||||
if (routeObject && routeObject.type === 'ObjectExpression') {
|
||||
let featuresProperty = null;
|
||||
let nsfwProperty = null;
|
||||
if (!routeObject || routeObject.type !== 'ObjectExpression') {
|
||||
return;
|
||||
}
|
||||
|
||||
// 查找 features 属性
|
||||
for (const prop of routeObject.properties) {
|
||||
if (!(prop.type === 'Property' && prop.key && prop.key.name === 'features')) {
|
||||
continue;
|
||||
}
|
||||
let featuresProperty = null;
|
||||
let nsfwProperty = null;
|
||||
|
||||
featuresProperty = prop;
|
||||
// 查找 features 属性
|
||||
for (const prop of routeObject.properties) {
|
||||
if (!(prop.type === 'Property' && prop.key && prop.key.name === 'features')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 在 features 中查找 nsfw 属性
|
||||
if (prop.value && prop.value.type === 'ObjectExpression') {
|
||||
for (const featureProp of prop.value.properties) {
|
||||
if (!(featureProp.type === 'Property' && featureProp.key && featureProp.key.name === 'nsfw')) {
|
||||
continue;
|
||||
}
|
||||
featuresProperty = prop;
|
||||
|
||||
nsfwProperty = featureProp;
|
||||
break;
|
||||
// 在 features 中查找 nsfw 属性
|
||||
if (prop.value && prop.value.type === 'ObjectExpression') {
|
||||
for (const featureProp of prop.value.properties) {
|
||||
if (!(featureProp.type === 'Property' && featureProp.key && featureProp.key.name === 'nsfw')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsfwProperty = featureProp;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// 检查是否需要添加或修复 nsfw 标志
|
||||
if (!featuresProperty) {
|
||||
// 没有 features 属性,需要添加整个 features 对象
|
||||
context.report({
|
||||
node: routeObject,
|
||||
messageId: 'missingNsfwFlag',
|
||||
fix(fixer) {
|
||||
// 在对象的最后添加 features 属性
|
||||
const lastProperty = routeObject.properties.at(-1);
|
||||
// 检查是否需要添加或修复 nsfw 标志
|
||||
if (!featuresProperty) {
|
||||
// 没有 features 属性,需要添加整个 features 对象
|
||||
context.report({
|
||||
node: routeObject,
|
||||
messageId: 'missingNsfwFlag',
|
||||
fix(fixer) {
|
||||
// 在对象的最后添加 features 属性
|
||||
const lastProperty = routeObject.properties.at(-1);
|
||||
|
||||
return lastProperty
|
||||
? fixer.insertTextAfter(lastProperty, ',\n features: {\n nsfw: true,\n }')
|
||||
: // 空对象的情况
|
||||
fixer.insertTextAfter(routeObject.properties.length > 0 ? routeObject.properties.at(-1) : routeObject, '\n features: {\n nsfw: true,\n }\n');
|
||||
},
|
||||
});
|
||||
} else if (!nsfwProperty) {
|
||||
// 有 features 属性但没有 nsfw 属性
|
||||
context.report({
|
||||
node: featuresProperty.value,
|
||||
messageId: 'missingNsfwFlag',
|
||||
fix(fixer) {
|
||||
const featuresObject = featuresProperty.value;
|
||||
if (featuresObject.properties.length > 0) {
|
||||
const lastFeatureProp = featuresObject.properties.at(-1);
|
||||
return fixer.insertTextAfter(lastFeatureProp, ',\n nsfw: true');
|
||||
}
|
||||
// features 是空对象
|
||||
return fixer.replaceTextRange([featuresObject.range[0] + 1, featuresObject.range[1] - 1], '\n nsfw: true,\n ');
|
||||
},
|
||||
});
|
||||
} else if (nsfwProperty.value && (nsfwProperty.value.type !== 'Literal' || nsfwProperty.value.value !== true)) {
|
||||
// nsfw 属性存在但不是 true
|
||||
context.report({
|
||||
node: nsfwProperty.value,
|
||||
messageId: 'missingNsfwFlag',
|
||||
fix: (fixer) => fixer.replaceText(nsfwProperty.value, 'true'),
|
||||
});
|
||||
}
|
||||
return lastProperty
|
||||
? fixer.insertTextAfter(lastProperty, ',\n features: {\n nsfw: true,\n }')
|
||||
: // 空对象的情况
|
||||
fixer.insertTextAfter(routeObject.properties.length > 0 ? routeObject.properties.at(-1) : routeObject, '\n features: {\n nsfw: true,\n }\n');
|
||||
},
|
||||
});
|
||||
} else if (!nsfwProperty) {
|
||||
// 有 features 属性但没有 nsfw 属性
|
||||
context.report({
|
||||
node: featuresProperty.value,
|
||||
messageId: 'missingNsfwFlag',
|
||||
fix(fixer) {
|
||||
const featuresObject = featuresProperty.value;
|
||||
if (featuresObject.properties.length > 0) {
|
||||
const lastFeatureProp = featuresObject.properties.at(-1);
|
||||
return fixer.insertTextAfter(lastFeatureProp, ',\n nsfw: true');
|
||||
}
|
||||
// features 是空对象
|
||||
return fixer.replaceTextRange([featuresObject.range[0] + 1, featuresObject.range[1] - 1], '\n nsfw: true,\n ');
|
||||
},
|
||||
});
|
||||
} else if (nsfwProperty.value && (nsfwProperty.value.type !== 'Literal' || nsfwProperty.value.value !== true)) {
|
||||
// nsfw 属性存在但不是 true
|
||||
context.report({
|
||||
node: nsfwProperty.value,
|
||||
messageId: 'missingNsfwFlag',
|
||||
fix: (fixer) => fixer.replaceText(nsfwProperty.value, 'true'),
|
||||
});
|
||||
}
|
||||
},
|
||||
}),
|
||||
|
||||
@@ -21,25 +21,26 @@ export const getRadarRules = async (): Promise<Record<string, RadarDomain>> => {
|
||||
const parsedDomain = parse(new URL('https://' + radarItem.source[0]).hostname);
|
||||
const subdomain = parsedDomain.subdomain || '.';
|
||||
const domain = parsedDomain.domain;
|
||||
if (domain) {
|
||||
if (!Object.hasOwn(rules, domain)) {
|
||||
rules[domain] = {
|
||||
_name: namespaces[namespace].name,
|
||||
} as RadarDomain;
|
||||
}
|
||||
if (!Object.hasOwn(rules[domain], subdomain)) {
|
||||
rules[domain][subdomain] = [];
|
||||
}
|
||||
rules[domain][subdomain].push({
|
||||
title: radarItem.title || data.name,
|
||||
docs: `https://docs.rsshub.app/routes/${data.categories?.[0] || 'other'}`,
|
||||
source: radarItem.source.map((source) => {
|
||||
const sourceURL = new URL('https://' + source);
|
||||
return sourceURL.pathname + sourceURL.search + sourceURL.hash;
|
||||
}),
|
||||
target: radarItem.target ? `/${namespace}${radarItem.target}` : realPath,
|
||||
});
|
||||
if (!domain) {
|
||||
continue;
|
||||
}
|
||||
if (!Object.hasOwn(rules, domain)) {
|
||||
rules[domain] = {
|
||||
_name: namespaces[namespace].name,
|
||||
} as RadarDomain;
|
||||
}
|
||||
if (!Object.hasOwn(rules[domain], subdomain)) {
|
||||
rules[domain][subdomain] = [];
|
||||
}
|
||||
rules[domain][subdomain].push({
|
||||
title: radarItem.title || data.name,
|
||||
docs: `https://docs.rsshub.app/routes/${data.categories?.[0] || 'other'}`,
|
||||
source: radarItem.source.map((source) => {
|
||||
const sourceURL = new URL('https://' + source);
|
||||
return sourceURL.pathname + sourceURL.search + sourceURL.hash;
|
||||
}),
|
||||
target: radarItem.target ? `/${namespace}${radarItem.target}` : realPath,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,12 +64,14 @@ const replaceUrl = (template?: string, url?: string) => {
|
||||
const replaceUrls = ($: CheerioAPI, selector: string, template: string, attribute = 'src') => {
|
||||
$(selector).each((_, el) => {
|
||||
const oldSrc = $(el).attr(attribute);
|
||||
if (oldSrc) {
|
||||
const url = parseUrl(oldSrc);
|
||||
if (url && url.protocol !== 'data:') {
|
||||
// Cheerio will do the right thing to prohibit XSS.
|
||||
$(el).attr(attribute, interpolate(template, url));
|
||||
}
|
||||
if (!oldSrc) {
|
||||
return;
|
||||
}
|
||||
|
||||
const url = parseUrl(oldSrc);
|
||||
if (url && url.protocol !== 'data:') {
|
||||
// Cheerio will do the right thing to prohibit XSS.
|
||||
$(el).attr(attribute, interpolate(template, url));
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -137,37 +139,39 @@ const middleware: MiddlewareHandler = async (ctx, next) => {
|
||||
// Use Cheerio to load the description as html and filter all
|
||||
// image link
|
||||
const data: Data = ctx.get('data');
|
||||
if (data) {
|
||||
if (data.image) {
|
||||
data.image = replaceUrl(imageHotlinkTemplate, data.image);
|
||||
}
|
||||
if (data.description) {
|
||||
data.description = process(data.description, imageHotlinkTemplate, multimediaHotlinkTemplate);
|
||||
}
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (data.item) {
|
||||
for (const item of data.item) {
|
||||
if (item.description) {
|
||||
item.description = process(item.description, imageHotlinkTemplate, multimediaHotlinkTemplate);
|
||||
}
|
||||
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)) {
|
||||
item.enclosure_url = replaceUrl(multimediaHotlinkTemplate, item.enclosure_url);
|
||||
}
|
||||
}
|
||||
if (item.image) {
|
||||
item.image = replaceUrl(imageHotlinkTemplate, item.image);
|
||||
}
|
||||
if (item.itunes_item_image) {
|
||||
item.itunes_item_image = replaceUrl(imageHotlinkTemplate, item.itunes_item_image);
|
||||
if (data.image) {
|
||||
data.image = replaceUrl(imageHotlinkTemplate, data.image);
|
||||
}
|
||||
if (data.description) {
|
||||
data.description = process(data.description, imageHotlinkTemplate, multimediaHotlinkTemplate);
|
||||
}
|
||||
|
||||
if (data.item) {
|
||||
for (const item of data.item) {
|
||||
if (item.description) {
|
||||
item.description = process(item.description, imageHotlinkTemplate, multimediaHotlinkTemplate);
|
||||
}
|
||||
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)) {
|
||||
item.enclosure_url = replaceUrl(multimediaHotlinkTemplate, item.enclosure_url);
|
||||
}
|
||||
}
|
||||
if (item.image) {
|
||||
item.image = replaceUrl(imageHotlinkTemplate, item.image);
|
||||
}
|
||||
if (item.itunes_item_image) {
|
||||
item.itunes_item_image = replaceUrl(imageHotlinkTemplate, item.itunes_item_image);
|
||||
}
|
||||
}
|
||||
|
||||
ctx.set('data', data);
|
||||
}
|
||||
|
||||
ctx.set('data', data);
|
||||
};
|
||||
|
||||
export default middleware;
|
||||
|
||||
+12
-11
@@ -79,17 +79,18 @@ const middleware: MiddlewareHandler = async (ctx, next) => {
|
||||
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') {
|
||||
try {
|
||||
item.pubDate &&= convertDateToISO8601(item.pubDate) || '';
|
||||
} catch {
|
||||
item.pubDate = '';
|
||||
}
|
||||
try {
|
||||
item.updated &&= convertDateToISO8601(item.updated) || '';
|
||||
} catch {
|
||||
item.updated = '';
|
||||
}
|
||||
if (outputType === 'rss') {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
item.pubDate &&= convertDateToISO8601(item.pubDate) || '';
|
||||
} catch {
|
||||
item.pubDate = '';
|
||||
}
|
||||
try {
|
||||
item.updated &&= convertDateToISO8601(item.updated) || '';
|
||||
} catch {
|
||||
item.updated = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+17
-15
@@ -174,22 +174,24 @@ export function registerRssRoutes(app: Hono, namespaces: NamespacesType): void {
|
||||
for (const [path, routeData] of sortedRoutes) {
|
||||
const wrappedHandler: Handler = async (ctx) => {
|
||||
logger.debug(`Matched route: ${routePath(ctx)}`);
|
||||
if (!ctx.get('data')) {
|
||||
if (!routeData.handler) {
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
const { route } = await import(`./routes/${namespace}/${routeData.location}`);
|
||||
routeData.handler = route.handler;
|
||||
} else if (routeData.module) {
|
||||
const { route } = await routeData.module();
|
||||
routeData.handler = route.handler;
|
||||
}
|
||||
}
|
||||
const response = await routeData.handler(ctx);
|
||||
if (response instanceof Response) {
|
||||
return response;
|
||||
}
|
||||
ctx.set('data', response);
|
||||
if (ctx.get('data')) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!routeData.handler) {
|
||||
if (process.env.NODE_ENV === 'test') {
|
||||
const { route } = await import(`./routes/${namespace}/${routeData.location}`);
|
||||
routeData.handler = route.handler;
|
||||
} else if (routeData.module) {
|
||||
const { route } = await routeData.module();
|
||||
routeData.handler = route.handler;
|
||||
}
|
||||
}
|
||||
const response = await routeData.handler(ctx);
|
||||
if (response instanceof Response) {
|
||||
return response;
|
||||
}
|
||||
ctx.set('data', response);
|
||||
};
|
||||
subApp.get(path, wrappedHandler);
|
||||
}
|
||||
|
||||
@@ -8,10 +8,12 @@ const processImages = ($) => {
|
||||
$('a').each((_, elem) => {
|
||||
const $elem = $(elem);
|
||||
const largePhotoUrl = $elem.attr('href')?.replace('i0.wp.com', '').replace('pic.4khd.com', 'yt4.googleusercontent.com').replace('AsHYQ', 'AsYHQ').replace('l/AAA', 'I/AAA');
|
||||
if (largePhotoUrl) {
|
||||
$elem.attr('href', largePhotoUrl);
|
||||
$elem.find('img').attr('src', largePhotoUrl);
|
||||
if (!largePhotoUrl) {
|
||||
return;
|
||||
}
|
||||
|
||||
$elem.attr('href', largePhotoUrl);
|
||||
$elem.find('img').attr('src', largePhotoUrl);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -45,12 +45,8 @@ export async function processItems(ctx, baseURL, exclude) {
|
||||
const pubDate = timezone(parseDate($(item).find('span').text().replaceAll(/[[\]]/g, ''), 'MM-DD'), 8);
|
||||
const text = link.text();
|
||||
|
||||
if (href === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (exclude && exclude.some((e) => e.test(text))) {
|
||||
// 过滤掉满足正则的标题条目
|
||||
// 过滤掉满足正则的标题条目
|
||||
if (href === undefined || (exclude && exclude.some((e) => e.test(text)))) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+14
-12
@@ -97,19 +97,21 @@ export const handler = async (ctx: Context): Promise<Data> => {
|
||||
const mediaUrl: string | undefined = $$el.prop('src');
|
||||
const mediaType: string | undefined = mediaUrl?.split(/\./).pop();
|
||||
|
||||
if (mediaType && mediaUrl) {
|
||||
media[mediaType] = { url: mediaUrl };
|
||||
|
||||
pEl.replaceWith(
|
||||
renderDescription({
|
||||
images: [
|
||||
{
|
||||
src: mediaUrl,
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
if (!(mediaType && mediaUrl)) {
|
||||
return;
|
||||
}
|
||||
|
||||
media[mediaType] = { url: mediaUrl };
|
||||
|
||||
pEl.replaceWith(
|
||||
renderDescription({
|
||||
images: [
|
||||
{
|
||||
src: mediaUrl,
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ async function handler(ctx) {
|
||||
const response = await got.get(pageUrl);
|
||||
const $ = load(response.data);
|
||||
let title = '';
|
||||
const titleLinks = $('.container .regsiter a').toArray().slice(1); // what a typo... drop "首页"
|
||||
const titleLinks = $('.container .regsiter a').slice(1).toArray(); // what a typo... drop "首页"
|
||||
for (const link of titleLinks) {
|
||||
const linkText = $(link).text();
|
||||
title = title ? `${title} - ${linkText}` : linkText;
|
||||
|
||||
@@ -54,8 +54,8 @@ async function handler(ctx: Context) {
|
||||
|
||||
// get rest ul article links
|
||||
const restItems: DataItem[] = $('.threecol li')
|
||||
.toArray()
|
||||
.slice(0, 10)
|
||||
.toArray()
|
||||
.map((article) => {
|
||||
const $article = load(article);
|
||||
|
||||
|
||||
@@ -295,10 +295,11 @@ const renderEmbedImages = (block: Block, index: number): JSX.Element | null => {
|
||||
const rawImageBlock = findBlocksByType(imageBlock.model?.blocks ?? imageBlock.blocks ?? imageBlock.items, 'rawImage')[0];
|
||||
const width = rawImageBlock?.model?.width;
|
||||
|
||||
if (width && width > maxWidth) {
|
||||
maxWidth = width;
|
||||
largestImage = imageBlock;
|
||||
if (!(width && width > maxWidth)) {
|
||||
continue;
|
||||
}
|
||||
maxWidth = width;
|
||||
largestImage = imageBlock;
|
||||
}
|
||||
|
||||
if (!largestImage) {
|
||||
|
||||
@@ -170,8 +170,8 @@ const getMonthlyRankings = (year: string, month: string): Promise<RankingItem[]>
|
||||
// Additional info (contributors, created date)
|
||||
const additionalInfo = $tr
|
||||
.find('td:nth-child(3) > div')
|
||||
.toArray()
|
||||
.slice(1)
|
||||
.toArray()
|
||||
.map((el) => $(el).text().trim())
|
||||
.join('; ');
|
||||
return {
|
||||
|
||||
@@ -28,10 +28,11 @@ const getConfiguredCookie = () => {
|
||||
// Update b_lsid in cookies
|
||||
for (const key of Object.keys(config.bilibili.cookies)) {
|
||||
const cookie = config.bilibili.cookies[key];
|
||||
if (cookie) {
|
||||
const updatedCookie = cookie.replace(/b_lsid=[0-9A-F]+_[0-9A-F]+/, () => `b_lsid=${utils.lsid()}`);
|
||||
config.bilibili.cookies[key] = updatedCookie;
|
||||
if (!cookie) {
|
||||
continue;
|
||||
}
|
||||
const updatedCookie = cookie.replace(/b_lsid=[0-9A-F]+_[0-9A-F]+/, () => `b_lsid=${utils.lsid()}`);
|
||||
config.bilibili.cookies[key] = updatedCookie;
|
||||
}
|
||||
|
||||
return config.bilibili.cookies[Object.keys(config.bilibili.cookies)[Math.floor(Math.random() * Object.keys(config.bilibili.cookies).length)]] || '';
|
||||
|
||||
@@ -392,12 +392,14 @@
|
||||
sp >>>= 0;
|
||||
const id = this.mem.getUint32(sp + 8, true);
|
||||
this._goRefCounts[id]--;
|
||||
if (this._goRefCounts[id] === 0) {
|
||||
const v = this._values[id];
|
||||
this._values[id] = null;
|
||||
this._ids.delete(v);
|
||||
this._idPool.push(id);
|
||||
if (this._goRefCounts[id] !== 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const v = this._values[id];
|
||||
this._values[id] = null;
|
||||
this._ids.delete(v);
|
||||
this._idPool.push(id);
|
||||
},
|
||||
|
||||
// func stringVal(value string) ref
|
||||
|
||||
@@ -287,18 +287,20 @@ const processLedeMedia = async (story_json) => {
|
||||
}
|
||||
return '';
|
||||
}
|
||||
if (story_json.type === 'Lede') {
|
||||
const props = story_json.props;
|
||||
|
||||
const media = {
|
||||
kind: props.media,
|
||||
caption: props.caption?.replaceAll(capRegex, '') ?? '',
|
||||
description: props.dek?.replaceAll(capRegex, '') ?? '',
|
||||
credit: props.credit?.replaceAll(capRegex, '') ?? '',
|
||||
src: props.url,
|
||||
};
|
||||
return renderLedeMedia(media);
|
||||
if (story_json.type !== 'Lede') {
|
||||
return;
|
||||
}
|
||||
|
||||
const props = story_json.props;
|
||||
|
||||
const media = {
|
||||
kind: props.media,
|
||||
caption: props.caption?.replaceAll(capRegex, '') ?? '',
|
||||
description: props.dek?.replaceAll(capRegex, '') ?? '',
|
||||
credit: props.credit?.replaceAll(capRegex, '') ?? '',
|
||||
src: props.url,
|
||||
};
|
||||
return renderLedeMedia(media);
|
||||
};
|
||||
|
||||
const processBody = async (body_html, story_json) => {
|
||||
|
||||
@@ -17,7 +17,7 @@ async function handler() {
|
||||
const rootUrl = 'https://www.blowstudio.es';
|
||||
const response = await ofetch(`${rootUrl}/work/`);
|
||||
const $ = load(response);
|
||||
const list = $('.portfolios.normal > ul > li').toArray().slice(0, 10);
|
||||
const list = $('.portfolios.normal > ul > li').slice(0, 10).toArray();
|
||||
|
||||
const videostyle = 'width="640" height="360"';
|
||||
const imgstyle = 'style="max-width: 650px; height: auto; object-fit: contain; flex: 0 0 auto;"';
|
||||
|
||||
@@ -66,8 +66,8 @@ async function getList(url) {
|
||||
const { data } = await got(url);
|
||||
const $ = load(data);
|
||||
const title = $('.nytit .fr a')
|
||||
.toArray()
|
||||
.slice(1)
|
||||
.toArray()
|
||||
.map((item) => $(item).text().trim())
|
||||
.join(' - ');
|
||||
const list = $("div[class='Newslist'] > ul > li")
|
||||
|
||||
@@ -27,8 +27,8 @@ async function handler() {
|
||||
|
||||
const $ = load(response);
|
||||
const list = $('div[class=subPage] div ul li')
|
||||
.toArray()
|
||||
.slice(0, 25)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
const $item = $(item);
|
||||
const aTag = $item.find('a');
|
||||
|
||||
@@ -11,10 +11,7 @@ const rsaPrivateKey =
|
||||
'-----BEGIN PRIVATE KEY-----MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCLci8q2u3NGFyFlMUwjCP91PsvGjHdRAq9fmqZLxvue+n+RhzNxnKKYOv35pLgFKWXsGq2TV+5Xrv6xZgNx36IUkqbmrO+eCa8NFmti04wvMfG3DCNdKA7Lue880daNiK3BOhlQlZPykUXt1NftMNS/z+e70W+Vpv1ZxCx5BipqZkdoceM3uin0vUQmqmHqjxi5qKUuov90dXLaMxypCA0TDsIDnX8RPvPtqKff1p2TMW2a0XYe7CPYhRggaQMpmo0TcFutgrM1Vywyr2TPxYR+H/tpuuWRET7tUIQykBYoO1WKfL2dX6cxarjAJfnYnod3sMzppHouyp8Pt7gHVG7AgMBAAECggEAEFshSy6IrADKgWSUyH/3jMNZfwnchW6Ar/9O847CAPQJ2yhQIpa/Qpnhs58Y5S2myqcHrUBgFPcWp3BbyGn43naAh8XahWHEcVjWl/N6BV9vM1UKYN0oGikDR3dljCBDbCIoPBBO3WcFOaXoIpaqPmbwCG1aSdwQyPUA0UzG08eDbuHK6L5jvbe3xv5kLpWTVddrocW+SakbZRAX1Ykp7IujOce235nM7GOfoq4b8jmK5CLg6VIZGQV20wnn9YxuFOndRSjneFberzfzBMhVLpPsQ16M2xDLpZaDTggZnq2L6nZygds8Hda++ga3WbD3TcgjJNYuENu1S88IowYhSQKBgQDFqRA+38mo6KsxVDCNWcuEk2hSq8NEUzRHJpS7/QjZmEIYpFzDXgSGwhZJ0WNsQtaxJeBbc7B/OOqh8TL1reLl5AdTimS1OLHWVf/MUsLVS7Y82hx/hpYWxZnRSq41oI3P8FO/53FiQMYo2wbwqF6uQjB1y8h58aqL3OYpTH/5xQKBgQC0mobALJ+bU4nCPzkVDZuD6RyNWPwS1aE3+925wDSN2rJ0iLIb4N5czWZmHb66VlAtfGbp2q+amsCV4r6UR19A/y8k9SFB0mdtxix6mjEfaGhVJm4B1mkvsn0OHMAanKkohUvCjROQc3sziyp2gqSEQ98G7//VMPx/3dhgyQpVfwKBgQCycsqu6N0n+D6t/0MCKiJaI7bYhCd7JN8aqVM4UN5PjG2Hz8PLwbK2cr0qkbaAA+vN7NMb3Vtn0FvMLnUCZqVlRTP0EQqQrYmoZuXUcpdhd8QkNgnqe/g+wND4qcKTucquA1uo8mtj9/Su5+bhGDC6hBk6D+uDZFHDiX/loyIavQKBgQCXF6AcLjjpDZ52b8Yloti0JtXIOuXILAlQeNoqiG5vLsOVUrcPM7VUFlLQo5no8kTpiOXgRyAaS9VKkAO4sW0zR0n9tUY5dvkokV6sw0rNZ9/BPQFTcDlXug99OvhMSzwJtlqHTNdNRg+QM6E2vF0+ejmf6DEz/mN/5e0cK5UFqQKBgCR2hVfbRtDz9Cm/P8chPqaWFkH5ulUxBpc704Igc6bVH5DrEoWo6akbeJixV2obAZO3sFyeJqBUqaCvqG17Xei6jn3Hc3WMz9nLrAJEI9BTCfwvuxCOyY0IxqAAYT28xYv42I4+ADT/PpCq2Dj5u43X0dapAjZBZDfVVis7q1Bw-----END PRIVATE KEY-----';
|
||||
|
||||
export async function getFulltext(url: string) {
|
||||
if (!config.caixin.cookie) {
|
||||
return;
|
||||
}
|
||||
if (!/\d+\.html/.test(url)) {
|
||||
if (!config.caixin.cookie || !/\d+\.html/.test(url)) {
|
||||
return;
|
||||
}
|
||||
const articleID = url.match(/(\d+)\.html/)![1];
|
||||
|
||||
@@ -98,14 +98,18 @@ export async function fetchArticles(path) {
|
||||
// Remove srcset attribute
|
||||
$img.removeAttr('srcset');
|
||||
|
||||
if (src && src.startsWith('/_next/image')) {
|
||||
// Extract the original URL from the Next.js image URL
|
||||
const urlMatch = src.match(/url=([^&]+)/);
|
||||
if (urlMatch && urlMatch[1]) {
|
||||
const originalUrl = decodeURIComponent(urlMatch[1]);
|
||||
$img.attr('src', originalUrl);
|
||||
}
|
||||
if (!src?.startsWith('/_next/image')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract the original URL from the Next.js image URL
|
||||
const urlMatch = src.match(/url=([^&]+)/);
|
||||
if (!urlMatch?.[1]) {
|
||||
return;
|
||||
}
|
||||
|
||||
const originalUrl = decodeURIComponent(urlMatch[1]);
|
||||
$img.attr('src', originalUrl);
|
||||
});
|
||||
return {
|
||||
title,
|
||||
|
||||
@@ -38,8 +38,8 @@ async function handler(ctx: Context) {
|
||||
link: pageUrl,
|
||||
title: category === 'all' ? baseTitle : `${baseTitle} ${$('title').text()}`,
|
||||
item: $('div[id^="wp_news_w"] a')
|
||||
.toArray()
|
||||
.slice(0, 10)
|
||||
.toArray()
|
||||
.filter((elem) => entryUrlRegex.test(elem.attribs.href))
|
||||
.map((elem) => ({
|
||||
link: new URL(elem.attribs.href, pageUrl).href,
|
||||
|
||||
@@ -35,8 +35,8 @@ async function handler(ctx: Context) {
|
||||
link: pageUrl,
|
||||
title: category === 'all' ? baseTitle : `${baseTitle} ${$('title').text()}`,
|
||||
item: $('.news_title a')
|
||||
.toArray()
|
||||
.slice(0, 10)
|
||||
.toArray()
|
||||
.filter((elem) => entryUrlRegex.test(elem.attribs.href))
|
||||
.map((elem) => ({
|
||||
link: new URL(elem.attribs.href, pageUrl).href,
|
||||
|
||||
+12
-8
@@ -245,14 +245,18 @@ function parseLinkData($: CheerioAPI) {
|
||||
|
||||
function getVideoIframe($ele: Cheerio<Element>) {
|
||||
const setup = $ele.find('video').data('setup') as VideoSetup;
|
||||
if (setup) {
|
||||
const youtubeSource = setup.sources.find((i) => i.type === 'video/youtube');
|
||||
if (youtubeSource) {
|
||||
const videoId = youtubeSource.src.match(/\?v=([^&]+)/)?.[1];
|
||||
if (videoId) {
|
||||
return `<iframe src="https://www.youtube-nocookie.com/embed/${videoId}" width="640" height="360" frameborder="0" allowfullscreen referrerpolicy="strict-origin-when-cross-origin"></iframe>`;
|
||||
}
|
||||
}
|
||||
if (!setup) {
|
||||
return;
|
||||
}
|
||||
|
||||
const youtubeSource = setup.sources.find((i) => i.type === 'video/youtube');
|
||||
if (!youtubeSource) {
|
||||
return;
|
||||
}
|
||||
|
||||
const videoId = youtubeSource.src.match(/\?v=([^&]+)/)?.[1];
|
||||
if (videoId) {
|
||||
return `<iframe src="https://www.youtube-nocookie.com/embed/${videoId}" width="640" height="360" frameborder="0" allowfullscreen referrerpolicy="strict-origin-when-cross-origin"></iframe>`;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@ async function handler() {
|
||||
$('.cg-pic').parent().remove();
|
||||
|
||||
const list = $('.cg-title h3')
|
||||
.toArray()
|
||||
.slice(0, 15)
|
||||
.toArray()
|
||||
.map((item): DataItem => {
|
||||
const a = $(item).find('a');
|
||||
return {
|
||||
|
||||
@@ -100,8 +100,8 @@ async function handler(ctx) {
|
||||
return {
|
||||
title: $('caption').text().trim(),
|
||||
items: $('.datalist tr')
|
||||
.toArray()
|
||||
.slice(1)
|
||||
.toArray()
|
||||
.map((item): DataItem => {
|
||||
const $item = $(item);
|
||||
const title = $item.find('td').eq(1).text();
|
||||
|
||||
@@ -94,10 +94,12 @@ async function handler(ctx) {
|
||||
});
|
||||
article.find('.article-a-attach-body a').each((i, ele) => {
|
||||
const $ele = $(ele);
|
||||
if ($ele.attr('onclick')?.startsWith("location.href=encodeURI($('#fileDownUrl').val()+'fileDownLoad.do")) {
|
||||
$ele.attr('href', `${baseUrl}/dqs/cm-s-notice-query/fileDownLoad.do?mode=open&contentId=${item.contentId}&priority=${i}`);
|
||||
$ele.removeAttr('onclick');
|
||||
if (!$ele.attr('onclick')?.startsWith("location.href=encodeURI($('#fileDownUrl').val()+'fileDownLoad.do")) {
|
||||
return;
|
||||
}
|
||||
|
||||
$ele.attr('href', `${baseUrl}/dqs/cm-s-notice-query/fileDownLoad.do?mode=open&contentId=${item.contentId}&priority=${i}`);
|
||||
$ele.removeAttr('onclick');
|
||||
});
|
||||
|
||||
item.description = article.html();
|
||||
|
||||
+14
-12
@@ -111,19 +111,21 @@ const fetchTargetElements = async (cleanType: string, subtype: string | undefine
|
||||
|
||||
for (const el of pageElements) {
|
||||
const $item = $(el).closest('li');
|
||||
if ($item.length > 0) {
|
||||
const rawLink = $(el).attr('href') || '';
|
||||
const rawZtzl = $(el).attr('ztzlurl') || ''; // some exhibition links have a separate detailed page, use ztzlurl to get the detailed exhibition link if available
|
||||
|
||||
// Use exhibitionLink to remove the repeat ones
|
||||
const itemLink = buildItemLink(rawLink, contextUrl, baseUrl);
|
||||
const exhibitionLink = buildExhibitionLink(rawZtzl, itemLink, baseUrl);
|
||||
|
||||
if (exhibitionLink && !seenLinks.has(exhibitionLink)) {
|
||||
seenLinks.add(exhibitionLink);
|
||||
items.push({ $item, contextUrl, itemLink, exhibitionLink, rawZtzl });
|
||||
}
|
||||
if ($item.length === 0) {
|
||||
continue;
|
||||
}
|
||||
const rawLink = $(el).attr('href') || '';
|
||||
const rawZtzl = $(el).attr('ztzlurl') || ''; // some exhibition links have a separate detailed page, use ztzlurl to get the detailed exhibition link if available
|
||||
|
||||
// Use exhibitionLink to remove the repeat ones
|
||||
const itemLink = buildItemLink(rawLink, contextUrl, baseUrl);
|
||||
const exhibitionLink = buildExhibitionLink(rawZtzl, itemLink, baseUrl);
|
||||
|
||||
if (!exhibitionLink || seenLinks.has(exhibitionLink)) {
|
||||
continue;
|
||||
}
|
||||
seenLinks.add(exhibitionLink);
|
||||
items.push({ $item, contextUrl, itemLink, exhibitionLink, rawZtzl });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -122,8 +122,8 @@ async function handler(ctx) {
|
||||
});
|
||||
const $ = load(response);
|
||||
const list = $('tr')
|
||||
.toArray()
|
||||
.slice(1)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
const title = $(item).find('a.fz14').text();
|
||||
const filename = $(item).find('a.icon-collect').attr('data-filename');
|
||||
|
||||
@@ -66,10 +66,12 @@ async function handler(ctx) {
|
||||
const header = $('.article-img-blk');
|
||||
header.find('img').each((_, ele) => {
|
||||
const $ele = $(ele);
|
||||
if ($ele.attr('src') && $ele.attr('srcset')) {
|
||||
$ele.removeAttr('srcset');
|
||||
$ele.attr('src', $ele.attr('src')!.replace(/\/\d+c\d+\//, '/0p0/'));
|
||||
if (!($ele.attr('src') && $ele.attr('srcset'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
$ele.removeAttr('srcset');
|
||||
$ele.attr('src', $ele.attr('src')!.replace(/\/\d+c\d+\//, '/0p0/'));
|
||||
});
|
||||
|
||||
item.description = header.html()! + $('article .ckec').html()!;
|
||||
|
||||
@@ -97,10 +97,12 @@ async function handler(ctx) {
|
||||
const regex = /downloads.fanbox.cc/;
|
||||
$('a').each((_, el) => {
|
||||
const link = $(el).attr('href');
|
||||
if (regex.test(link!)) {
|
||||
count++;
|
||||
$(el).replaceWith(coomerFiles[count]);
|
||||
if (!regex.test(link!)) {
|
||||
return;
|
||||
}
|
||||
|
||||
count++;
|
||||
$(el).replaceWith(coomerFiles[count]);
|
||||
});
|
||||
desc = (coomerFiles.length > 0 ? coomerFiles[0] : '') + $.html();
|
||||
const remainingCoomerFiles = coomerFiles.slice(count + 1);
|
||||
|
||||
@@ -36,8 +36,8 @@ async function handler(ctx: Context) {
|
||||
link,
|
||||
description: $('meta[name="description"]').attr('content') || '重科教务处',
|
||||
item: $('li[id^="lineu"]')
|
||||
.toArray()
|
||||
.slice(0, 10)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
const $item = $(item);
|
||||
return {
|
||||
|
||||
@@ -39,8 +39,8 @@ async function handler(ctx: Context) {
|
||||
link,
|
||||
description: $('meta[name="description"]').attr('content') || '重科图书馆公告',
|
||||
item: $('div[class="newsList"] li')
|
||||
.toArray()
|
||||
.slice(0, 10)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
const $item = $(item);
|
||||
return {
|
||||
|
||||
@@ -29,8 +29,8 @@ async function handler(ctx: Context) {
|
||||
const $ = load(response);
|
||||
|
||||
const list: DataItem[] = $('h2[itemprop="headline"] a, .post-header .archive__article__title a')
|
||||
.toArray()
|
||||
.slice(0, 15)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
const $item = $(item);
|
||||
return {
|
||||
|
||||
@@ -55,11 +55,13 @@ async function handler(ctx): Promise<Data> {
|
||||
|
||||
$('.c-lazy-image__img').each((_, img) => {
|
||||
const $img = $(img);
|
||||
if ($img.attr('data-lazy-src')) {
|
||||
$img.attr('src', $img.attr('data-lazy-src')!.split('?', 1)[0]);
|
||||
$img.removeAttr('data-lazy-src');
|
||||
$img.removeAttr('data-lazy-srcset');
|
||||
if (!$img.attr('data-lazy-src')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$img.attr('src', $img.attr('data-lazy-src')!.split('?', 1)[0]);
|
||||
$img.removeAttr('data-lazy-src');
|
||||
$img.removeAttr('data-lazy-srcset');
|
||||
});
|
||||
$('[class^="lrv-a-crop-"]').contents().unwrap();
|
||||
|
||||
|
||||
@@ -40,8 +40,8 @@ async function handler(ctx: Context) {
|
||||
link: `${host}${urlType}/index.shtml`,
|
||||
description: `东莞理工学院 ${name} ${info}`,
|
||||
item: $('#paging > ul li')
|
||||
.toArray()
|
||||
.slice(0, 10)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
const $item = $(item);
|
||||
return {
|
||||
|
||||
@@ -64,11 +64,13 @@ async function loadContent(itemLink, charset, header) {
|
||||
// fix lazyload image
|
||||
post.find('img').each((_, img) => {
|
||||
const $img = $(img);
|
||||
if ($img.attr('src')?.endsWith('none.gif') && $img.attr('file')) {
|
||||
$img.attr('src', $img.attr('file') || $img.attr('zoomfile'));
|
||||
$img.removeAttr('file');
|
||||
$img.removeAttr('zoomfile');
|
||||
if (!($img.attr('src')?.endsWith('none.gif') && $img.attr('file'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
$img.attr('src', $img.attr('file') || $img.attr('zoomfile'));
|
||||
$img.removeAttr('file');
|
||||
$img.removeAttr('zoomfile');
|
||||
});
|
||||
|
||||
// 只抓取论坛1楼消息
|
||||
|
||||
@@ -80,10 +80,11 @@ function decodeCipherText(p, a, c, k, e, d) {
|
||||
}
|
||||
while (c--) {
|
||||
const replacement = k[c];
|
||||
if (replacement) {
|
||||
const token = e(c.toString());
|
||||
p = p.replaceAll(new RegExp(String.raw`\b` + token + String.raw`\b`, 'g'), () => replacement);
|
||||
if (!replacement) {
|
||||
continue;
|
||||
}
|
||||
const token = e(c.toString());
|
||||
p = p.replaceAll(new RegExp(String.raw`\b` + token + String.raw`\b`, 'g'), () => replacement);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -41,8 +41,8 @@ async function handler(ctx) {
|
||||
const $ = load(response);
|
||||
// 列表
|
||||
const list = $('#posts-table>tbody>tr')
|
||||
.toArray()
|
||||
.slice(1)
|
||||
.toArray()
|
||||
.map((item): DataItem => {
|
||||
const $item = $(item);
|
||||
const a = $item.find('a').first();
|
||||
|
||||
@@ -34,13 +34,15 @@ async function loadContent(link) {
|
||||
const $video = $(video);
|
||||
const dataSrc = $video.attr('data-src');
|
||||
|
||||
if (!$video.attr('src') && dataSrc) {
|
||||
$video.attr('src', dataSrc);
|
||||
$video.removeAttr('data-src');
|
||||
$video.removeAttr('data-video-small');
|
||||
$video.removeAttr('data-video-medium');
|
||||
$video.removeAttr('data-video-large');
|
||||
if ($video.attr('src') || !dataSrc) {
|
||||
return;
|
||||
}
|
||||
|
||||
$video.attr('src', dataSrc);
|
||||
$video.removeAttr('data-src');
|
||||
$video.removeAttr('data-video-small');
|
||||
$video.removeAttr('data-video-medium');
|
||||
$video.removeAttr('data-video-large');
|
||||
});
|
||||
object.find('img').each((_, img) => {
|
||||
const $img = $(img);
|
||||
|
||||
@@ -63,10 +63,12 @@ const getPost = (item) =>
|
||||
$img.attr('src', hsrc);
|
||||
$img.removeAttr('data-hsrc');
|
||||
}
|
||||
if (osrc) {
|
||||
$img.attr('src', osrc);
|
||||
$img.removeAttr('data-osrc');
|
||||
if (!osrc) {
|
||||
return;
|
||||
}
|
||||
|
||||
$img.attr('src', osrc);
|
||||
$img.removeAttr('data-osrc');
|
||||
});
|
||||
|
||||
item.description = $.html();
|
||||
|
||||
+40
-36
@@ -108,36 +108,38 @@ async function parsePage(cache, data, get_bittorrent: string | boolean = false,
|
||||
thumbnail = await ehgot_thumb(cache, thumbnail);
|
||||
}
|
||||
const description = `<img src='${thumbnail}' alt='thumbnail'>`;
|
||||
if (title && link) {
|
||||
const item: DataItem & { bittorrent_page_url?: string } = {
|
||||
title,
|
||||
description,
|
||||
pubDate,
|
||||
link,
|
||||
};
|
||||
if (get_bittorrent) {
|
||||
const el_down = el.find('div.gldown');
|
||||
const bittorrent_page_url = el_down.find('a').attr('href');
|
||||
if (bittorrent_page_url) {
|
||||
const bittorrent_url = await getBittorrent(cache, bittorrent_page_url);
|
||||
if (bittorrent_url) {
|
||||
item.enclosure_url = bittorrent_url;
|
||||
item.enclosure_type = 'application/x-bittorrent';
|
||||
item.bittorrent_page_url = bittorrent_page_url;
|
||||
}
|
||||
if (!title || !link) {
|
||||
return;
|
||||
}
|
||||
|
||||
const item: DataItem & { bittorrent_page_url?: string } = {
|
||||
title,
|
||||
description,
|
||||
pubDate,
|
||||
link,
|
||||
};
|
||||
if (get_bittorrent) {
|
||||
const el_down = el.find('div.gldown');
|
||||
const bittorrent_page_url = el_down.find('a').attr('href');
|
||||
if (bittorrent_page_url) {
|
||||
const bittorrent_url = await getBittorrent(cache, bittorrent_page_url);
|
||||
if (bittorrent_url) {
|
||||
item.enclosure_url = bittorrent_url;
|
||||
item.enclosure_type = 'application/x-bittorrent';
|
||||
item.bittorrent_page_url = bittorrent_page_url;
|
||||
}
|
||||
}
|
||||
if ('le'.includes(layout)) {
|
||||
// artist tags will only show in Compact or Extended layout
|
||||
// get artist names as author
|
||||
item.author = $(el)
|
||||
.find('div.gt[title^="artist:"]')
|
||||
.toArray()
|
||||
.map((tag) => $(tag).text())
|
||||
.join(' / ');
|
||||
}
|
||||
return item;
|
||||
}
|
||||
if ('le'.includes(layout)) {
|
||||
// artist tags will only show in Compact or Extended layout
|
||||
// get artist names as author
|
||||
item.author = $(el)
|
||||
.find('div.gt[title^="artist:"]')
|
||||
.toArray()
|
||||
.map((tag) => $(tag).text())
|
||||
.join(' / ');
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
const item_Promises: Array<Promise<any>> = [];
|
||||
@@ -167,15 +169,17 @@ function getBittorrent(cache, bittorrent_page_url) {
|
||||
for (const el_form of el_forms) {
|
||||
const el_a = $(el_form).find('a');
|
||||
const onclick = el_a.attr('onclick');
|
||||
if (onclick) {
|
||||
const match = onclick.match(/'(.*?)'/);
|
||||
if (match) {
|
||||
bittorrent_url = match[1];
|
||||
const match_p = bittorrent_url.match(/torrent\?p=(.*)$/);
|
||||
if (match_p) {
|
||||
p = match_p[1];
|
||||
}
|
||||
}
|
||||
if (!onclick) {
|
||||
continue;
|
||||
}
|
||||
const match = onclick.match(/'(.*?)'/);
|
||||
if (!match) {
|
||||
continue;
|
||||
}
|
||||
bittorrent_url = match[1];
|
||||
const match_p = bittorrent_url.match(/torrent\?p=(.*)$/);
|
||||
if (match_p) {
|
||||
p = match_p[1];
|
||||
}
|
||||
}
|
||||
return bittorrent_url;
|
||||
|
||||
+12
-10
@@ -68,17 +68,19 @@ async function handler(ctx) {
|
||||
// fix lazyload image
|
||||
$('a').each((_, e) => {
|
||||
const $e = $(e);
|
||||
if ($e.attr('href') && $e.attr('href')!.endsWith('.jpg')) {
|
||||
$e.after(
|
||||
renderToString(
|
||||
<figure>
|
||||
<img src={$e.attr('href')} alt={$e.attr('title') ?? ''} title={$e.attr('title') ?? ''} />
|
||||
<figcaption>{$e.attr('title') ?? ''}</figcaption>
|
||||
</figure>
|
||||
)
|
||||
);
|
||||
$e.remove();
|
||||
if (!$e.attr('href')?.endsWith('.jpg')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$e.after(
|
||||
renderToString(
|
||||
<figure>
|
||||
<img src={$e.attr('href')} alt={$e.attr('title') ?? ''} title={$e.attr('title') ?? ''} />
|
||||
<figcaption>{$e.attr('title') ?? ''}</figcaption>
|
||||
</figure>
|
||||
)
|
||||
);
|
||||
$e.remove();
|
||||
});
|
||||
$('img').each((_, e) => {
|
||||
const $e = $(e);
|
||||
|
||||
@@ -119,15 +119,17 @@ export const route: Route = {
|
||||
if (junkPattern.test(name)) {
|
||||
$(ele).remove();
|
||||
}
|
||||
if (mediaPattern.test(name)) {
|
||||
const mediaType = name.match(mediaPattern)![1] === 'photo' ? 'images' : 'video';
|
||||
const mediaIndex = Number.parseInt(name.match(mediaPattern)![2]) - 1;
|
||||
const media = article.content[mediaType][mediaIndex];
|
||||
if (media) {
|
||||
$(ele).replaceWith(renderMedia(media));
|
||||
} else {
|
||||
$(ele).remove();
|
||||
}
|
||||
if (!mediaPattern.test(name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const mediaType = name.match(mediaPattern)![1] === 'photo' ? 'images' : 'video';
|
||||
const mediaIndex = Number.parseInt(name.match(mediaPattern)![2]) - 1;
|
||||
const media = article.content[mediaType][mediaIndex];
|
||||
if (media) {
|
||||
$(ele).replaceWith(renderMedia(media));
|
||||
} else {
|
||||
$(ele).remove();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -39,8 +39,8 @@ async function handler() {
|
||||
// 页面新闻消息列表
|
||||
const list = $('.body_zb ul .body_zb_li .zb_word')
|
||||
.find('.list_font_pic > a:first-child')
|
||||
.toArray()
|
||||
.slice(0, 30)
|
||||
.toArray()
|
||||
.map((e) => $(e).attr('href'));
|
||||
|
||||
const out = await Promise.all(
|
||||
|
||||
@@ -36,8 +36,8 @@ async function handler(ctx) {
|
||||
const $ = load(front_data);
|
||||
return [
|
||||
...$('a.brSCsc')
|
||||
.toArray()
|
||||
.slice(3) // skip Home, For you and Following
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
const $item = $(item);
|
||||
return {
|
||||
|
||||
@@ -53,8 +53,8 @@ async function handler(ctx: Context) {
|
||||
const $ = load(response);
|
||||
|
||||
const list = $('div.weinei_left_con div.weinei_left_con_line')
|
||||
.toArray()
|
||||
.slice(0, 10)
|
||||
.toArray()
|
||||
.map((item): DataItem => {
|
||||
const $item = $(item);
|
||||
const a = $item.find('a[title]');
|
||||
|
||||
@@ -58,16 +58,18 @@ export const parseNewsList = async (url, selector, ctx) => {
|
||||
const changeTrCookie = async () => {
|
||||
const cookies = await cookieJar.getCookies(rootUrl);
|
||||
const c = cookies.find((c) => c.key === 'HOY_TR');
|
||||
if (c) {
|
||||
const value = c.value;
|
||||
const tr_array = value.split(',');
|
||||
const csr = tr_array[0];
|
||||
const cnv = [...tr_array[1]];
|
||||
const otr = [...tr_array[2]];
|
||||
otr[0] = csr.charAt(Number.parseInt(cnv[0], 16));
|
||||
const nc = new Cookie({ key: 'HOY_TR', value: csr + ',' + cnv.join('') + ',' + otr.join('') + ',0' });
|
||||
await cookieJar.setCookie(nc, rootUrl);
|
||||
if (!c) {
|
||||
return;
|
||||
}
|
||||
|
||||
const value = c.value;
|
||||
const tr_array = value.split(',');
|
||||
const csr = tr_array[0];
|
||||
const cnv = [...tr_array[1]];
|
||||
const otr = [...tr_array[2]];
|
||||
otr[0] = csr.charAt(Number.parseInt(cnv[0], 16));
|
||||
const nc = new Cookie({ key: 'HOY_TR', value: csr + ',' + cnv.join('') + ',' + otr.join('') + ',0' });
|
||||
await cookieJar.setCookie(nc, rootUrl);
|
||||
};
|
||||
|
||||
export const parseArticle = async (item) => {
|
||||
|
||||
@@ -112,8 +112,8 @@ async function handler(ctx) {
|
||||
return {
|
||||
item: items,
|
||||
title: `国家自然科学基金委员会 - ${$('#ess_essBREADCRUMB_lblBreadCrumb a.break')
|
||||
.toArray()
|
||||
.slice(1)
|
||||
.toArray()
|
||||
.map((a) => $(a).text())
|
||||
.join(' - ')}`,
|
||||
link: currentUrl,
|
||||
|
||||
@@ -23,8 +23,8 @@ async function handler() {
|
||||
|
||||
const $ = load(response);
|
||||
const list = $('article.news-card')
|
||||
.toArray()
|
||||
.slice(0, 10)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
const $item = $(item);
|
||||
const a = $item.find('h2.news-title a');
|
||||
|
||||
@@ -21,12 +21,14 @@ async function handler(): Promise<Data> {
|
||||
let redirectPath = DEFAULT_REDIRECT_PATH;
|
||||
$scripts.each((_, el) => {
|
||||
const redirectScript = $entry(el).text();
|
||||
if (redirectScript !== null) {
|
||||
// Get the real index page by JS redirection href. The path may change.
|
||||
const match = redirectScript.match(/window\.location\.href\s*=\s*["']([^"']+)["']/);
|
||||
if (match) {
|
||||
redirectPath = match[1];
|
||||
}
|
||||
if (redirectScript === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the real index page by JS redirection href. The path may change.
|
||||
const match = redirectScript.match(/window\.location\.href\s*=\s*["']([^"']+)["']/);
|
||||
if (match) {
|
||||
redirectPath = match[1];
|
||||
}
|
||||
});
|
||||
const redirectURL = `${BASE_URL}${redirectPath}`;
|
||||
|
||||
@@ -36,11 +36,13 @@ async function handler(ctx: Context) {
|
||||
$('script').each((_, el) => {
|
||||
const text = $(el).text();
|
||||
const match = text.match(/\\"appID\\":\\"(\w+)\\",\\"apiKey\\":\\"(\w+)\\"/);
|
||||
if (match) {
|
||||
appId = match[1];
|
||||
apiKey = match[2];
|
||||
return false;
|
||||
if (!match) {
|
||||
return;
|
||||
}
|
||||
|
||||
appId = match[1];
|
||||
apiKey = match[2];
|
||||
return false;
|
||||
});
|
||||
if (!appId || !apiKey) {
|
||||
throw new Error('Failed to extract Algolia credentials from iapp.org');
|
||||
|
||||
@@ -50,11 +50,8 @@ export const parseJpy = (text: string | null): number | null => {
|
||||
if (/無償|なし|無し/.test(s)) {
|
||||
return 0;
|
||||
}
|
||||
if (isUnknown(s)) {
|
||||
return null;
|
||||
}
|
||||
// Without 円 / 万 only a bare number is accepted ('3ヶ月' is not an amount).
|
||||
if (!/[円万億]/.test(s) && !/^\d+(?:\.\d+)?$/.test(s)) {
|
||||
if (isUnknown(s) || (!/[円万億]/.test(s) && !/^\d+(?:\.\d+)?$/.test(s))) {
|
||||
return null;
|
||||
}
|
||||
const oku = s.match(/^(\d+(?:\.\d+)?)億(?:(\d+(?:\.\d+)?)万)?/);
|
||||
|
||||
@@ -63,10 +63,12 @@ export const handler = async (ctx) => {
|
||||
|
||||
const src = $el.prop('data-original');
|
||||
|
||||
if (src) {
|
||||
const alt = $el.prop('alt');
|
||||
$el.replaceWith(renderToString(<figure>{alt ? <img src={src} alt={alt} /> : <img src={src} />}</figure>));
|
||||
if (!src) {
|
||||
return;
|
||||
}
|
||||
|
||||
const alt = $el.prop('alt');
|
||||
$el.replaceWith(renderToString(<figure>{alt ? <img src={src} alt={alt} /> : <img src={src} />}</figure>));
|
||||
});
|
||||
|
||||
const title = $$('h1').text();
|
||||
|
||||
@@ -38,17 +38,19 @@ async function handler(ctx) {
|
||||
|
||||
const data = await constructTopicEntry(ctx, topicUrl);
|
||||
|
||||
if (data) {
|
||||
const result = data.result;
|
||||
result.item = data.posts.map((item) => {
|
||||
const date = dayjs(item.createdAt);
|
||||
return {
|
||||
title: `${data.topic.content} ${date.format('MM月DD日')}`,
|
||||
description: item.content.replaceAll('\n', '<br>'),
|
||||
pubDate: date.toDate(),
|
||||
link: `https://m.okjike.com/originalPosts/${item.id}`,
|
||||
};
|
||||
});
|
||||
return result;
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
const result = data.result;
|
||||
result.item = data.posts.map((item) => {
|
||||
const date = dayjs(item.createdAt);
|
||||
return {
|
||||
title: `${data.topic.content} ${date.format('MM月DD日')}`,
|
||||
description: item.content.replaceAll('\n', '<br>'),
|
||||
pubDate: date.toDate(),
|
||||
link: `https://m.okjike.com/originalPosts/${item.id}`,
|
||||
};
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
+33
-31
@@ -51,36 +51,38 @@ async function handler(ctx) {
|
||||
|
||||
const data = await constructTopicEntry(ctx, topicUrl);
|
||||
|
||||
if (data) {
|
||||
const result = data.result;
|
||||
result.item = topicDataHanding(data, ctx);
|
||||
if (id === '553870e8e4b0cafb0a1bef68' || id === '55963702e4b0d84d2c30ce6f') {
|
||||
result.item = await Promise.all(
|
||||
result.item.map(async (one) => {
|
||||
const item = { ...one };
|
||||
const regResult = /https:\/\/www\.okjike\.com\/medium\/[\dA-Za-z]*/.exec(item.description);
|
||||
if (regResult) {
|
||||
const newsUrl = regResult[0];
|
||||
item.description = await cache.tryGet(newsUrl, async () => {
|
||||
const { data } = await got(newsUrl);
|
||||
const $ = load(data);
|
||||
const upper = $('ul.main > li.item');
|
||||
const links = upper.find('a').map((_, ele) => $(ele).attr('href'));
|
||||
const texts = upper.find('span.text').map((_, ele) => $(ele).text());
|
||||
let description = '';
|
||||
for (let i = 0; i < links.length; i++) {
|
||||
description += `${i + 1}、<a href="${links[i]}">${texts[i]}</a><br>`;
|
||||
}
|
||||
description = description.replace(/<br>$/, '');
|
||||
return description;
|
||||
});
|
||||
}
|
||||
item.description = item.description.replaceAll(urlRegex, (url) => `<a href="${url}">${url}</a>`);
|
||||
item.title = `${data.topic.content} ${dayjs(one.pubDate).format('MM月DD日')}`;
|
||||
return item;
|
||||
})
|
||||
);
|
||||
}
|
||||
return result;
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
const result = data.result;
|
||||
result.item = topicDataHanding(data, ctx);
|
||||
if (id === '553870e8e4b0cafb0a1bef68' || id === '55963702e4b0d84d2c30ce6f') {
|
||||
result.item = await Promise.all(
|
||||
result.item.map(async (one) => {
|
||||
const item = { ...one };
|
||||
const regResult = /https:\/\/www\.okjike\.com\/medium\/[\dA-Za-z]*/.exec(item.description);
|
||||
if (regResult) {
|
||||
const newsUrl = regResult[0];
|
||||
item.description = await cache.tryGet(newsUrl, async () => {
|
||||
const { data } = await got(newsUrl);
|
||||
const $ = load(data);
|
||||
const upper = $('ul.main > li.item');
|
||||
const links = upper.find('a').map((_, ele) => $(ele).attr('href'));
|
||||
const texts = upper.find('span.text').map((_, ele) => $(ele).text());
|
||||
let description = '';
|
||||
for (let i = 0; i < links.length; i++) {
|
||||
description += `${i + 1}、<a href="${links[i]}">${texts[i]}</a><br>`;
|
||||
}
|
||||
description = description.replace(/<br>$/, '');
|
||||
return description;
|
||||
});
|
||||
}
|
||||
item.description = item.description.replaceAll(urlRegex, (url) => `<a href="${url}">${url}</a>`);
|
||||
item.title = `${data.topic.content} ${dayjs(one.pubDate).format('MM月DD日')}`;
|
||||
return item;
|
||||
})
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ async function handler() {
|
||||
const $ = load(response);
|
||||
|
||||
const items = $('.areaZslist li')
|
||||
.toArray()
|
||||
.slice(0, 10)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
const $item = $(item);
|
||||
return {
|
||||
|
||||
@@ -164,13 +164,15 @@ function generateEnclosureInfo(htmlContent: string): { enclosure_url?: string; e
|
||||
const extension = extractFileExtension(src);
|
||||
const mimeType = MIME_TYPE_MAP[extension as keyof typeof MIME_TYPE_MAP];
|
||||
|
||||
if (mimeType) {
|
||||
enclosureInfo = {
|
||||
enclosure_url: new URL(src, KEMONO_ROOT_URL).href,
|
||||
enclosure_type: mimeType,
|
||||
};
|
||||
return false;
|
||||
if (!mimeType) {
|
||||
return;
|
||||
}
|
||||
|
||||
enclosureInfo = {
|
||||
enclosure_url: new URL(src, KEMONO_ROOT_URL).href,
|
||||
enclosure_type: mimeType,
|
||||
};
|
||||
return false;
|
||||
});
|
||||
|
||||
return enclosureInfo;
|
||||
@@ -332,10 +334,12 @@ function processPosts(posts: KemonoPost[], authorName: string, limit: number) {
|
||||
const fanboxRegex = /downloads\.fanbox\.cc/;
|
||||
$('a').each((_, el) => {
|
||||
const link = $(el).attr('href');
|
||||
if (link && fanboxRegex.test(link)) {
|
||||
$(el).replaceWith(kemonoFileElements[replacementCount] || '');
|
||||
replacementCount++;
|
||||
if (!(link && fanboxRegex.test(link))) {
|
||||
return;
|
||||
}
|
||||
|
||||
$(el).replaceWith(kemonoFileElements[replacementCount] || '');
|
||||
replacementCount++;
|
||||
});
|
||||
|
||||
description = (kemonoFileElements[0] || '') + $.html();
|
||||
|
||||
@@ -63,8 +63,8 @@ async function handler(ctx: Context) {
|
||||
const $ = load(response);
|
||||
|
||||
const list = $('.entry-title a')
|
||||
.toArray()
|
||||
.slice(0, 10)
|
||||
.toArray()
|
||||
.map((item): DataItem & { link: string } => {
|
||||
const $item = $(item);
|
||||
return {
|
||||
|
||||
@@ -192,11 +192,13 @@ function getDescription($) {
|
||||
// handle lazyload image
|
||||
descriptionEl.find('img').each((_, img) => {
|
||||
const $img = $(img);
|
||||
if ($img.attr('src')?.endsWith('none.gif') && $img.attr('file')) {
|
||||
$img.attr('src', $img.attr('file'));
|
||||
$img.removeAttr('file');
|
||||
$img.removeAttr('zoomfile');
|
||||
if (!($img.attr('src')?.endsWith('none.gif') && $img.attr('file'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
$img.attr('src', $img.attr('file'));
|
||||
$img.removeAttr('file');
|
||||
$img.removeAttr('zoomfile');
|
||||
});
|
||||
|
||||
return descriptionEl.length > 0 ? descriptionEl.html() : $('div.alert_info').html();
|
||||
|
||||
@@ -58,8 +58,8 @@ export const getProductPage = (url: string): Promise<DataItem> =>
|
||||
|
||||
const category = [
|
||||
...$('.breadcrump .breadcrump-link')
|
||||
.toArray()
|
||||
.slice(1)
|
||||
.toArray()
|
||||
.map((x) => $(x).text().trim()),
|
||||
product
|
||||
.find('.addetailslist--detail')
|
||||
|
||||
@@ -23,8 +23,8 @@ async function handler() {
|
||||
|
||||
const list = $('div.article-list')
|
||||
.find('h3.article-title')
|
||||
.toArray()
|
||||
.slice(0, 20)
|
||||
.toArray()
|
||||
.map((item): DataItem & { link: string } => {
|
||||
const a = $(item).find('a');
|
||||
return {
|
||||
|
||||
@@ -78,16 +78,18 @@ const cleanHtml = (htmlString) => {
|
||||
const bvid = $(e)
|
||||
.attr('src')!
|
||||
.match(/bvid=(.*?)&/)![1];
|
||||
if (bvid) {
|
||||
const url = `https://www.bilibili.com/video/${bvid}`;
|
||||
$(e).after(
|
||||
renderToString(
|
||||
<p>
|
||||
<a href={url}>{url}</a>
|
||||
</p>
|
||||
)
|
||||
);
|
||||
if (!bvid) {
|
||||
return;
|
||||
}
|
||||
|
||||
const url = `https://www.bilibili.com/video/${bvid}`;
|
||||
$(e).after(
|
||||
renderToString(
|
||||
<p>
|
||||
<a href={url}>{url}</a>
|
||||
</p>
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
// 用户头像
|
||||
|
||||
@@ -53,8 +53,8 @@ async function handler(ctx: Context) {
|
||||
|
||||
list = $('.list-block ul li, .firstCon-r ul li')
|
||||
.find('a')
|
||||
.toArray()
|
||||
.slice(0, 10)
|
||||
.toArray()
|
||||
.map((item) => ({
|
||||
link: `https:${$(item).attr('href')}`,
|
||||
}));
|
||||
|
||||
@@ -407,11 +407,12 @@ async function fetchFeedData(communityId: number, community: string, session: st
|
||||
}
|
||||
|
||||
const existing = items.get(item.link);
|
||||
if (existing) {
|
||||
existing.category = [...new Set([...(existing.category ?? []), ...(item.category ?? [])])];
|
||||
existing.description ||= item.description;
|
||||
existing.itunes_item_image ||= item.itunes_item_image;
|
||||
if (!existing) {
|
||||
continue;
|
||||
}
|
||||
existing.category = [...new Set([...(existing.category ?? []), ...(item.category ?? [])])];
|
||||
existing.description ||= item.description;
|
||||
existing.itunes_item_image ||= item.itunes_item_image;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -161,10 +161,12 @@ async function handler(ctx) {
|
||||
article.find('.inlineImage').each((_, el) => {
|
||||
const inlineImageSrc = $(el).attr('src');
|
||||
const inlineAttachment = item.inline_attachments.find((inlineAttachment) => inlineAttachment.url === inlineImageSrc);
|
||||
if (inlineAttachment && inlineAttachment.description) {
|
||||
$(el).wrap('<figure></figure>');
|
||||
$(el).after(`<figcaption>${inlineAttachment.description}</figcaption>`);
|
||||
if (!(inlineAttachment && inlineAttachment.description)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$(el).wrap('<figure></figure>');
|
||||
$(el).after(`<figcaption>${inlineAttachment.description}</figcaption>`);
|
||||
});
|
||||
}
|
||||
item.description = renderToString(
|
||||
|
||||
@@ -27,8 +27,8 @@ export const route: Route = {
|
||||
const response = await ofetch(targetLink);
|
||||
const $ = load(response);
|
||||
const links = $('.archives-group article')
|
||||
.toArray()
|
||||
.slice(0, 10)
|
||||
.toArray()
|
||||
.map((item): DataItem => {
|
||||
const $item = $(item);
|
||||
const a = $item.find('a').first();
|
||||
|
||||
@@ -32,7 +32,7 @@ const handler = async (ctx) => {
|
||||
const data = response.body;
|
||||
|
||||
const $ = load(data);
|
||||
const list = $('.list_products > li').toArray().slice(0, 10);
|
||||
const list = $('.list_products > li').slice(0, 10).toArray();
|
||||
|
||||
const result = list.map((item) => {
|
||||
const $ = load(item);
|
||||
|
||||
@@ -99,14 +99,16 @@ export const route: Route = {
|
||||
const sudyfileAttr = ($el.attr('sudyfile-attr') || '{}').replaceAll("'", '"');
|
||||
const sudyfileAttrJson = JSON.parse(sudyfileAttr);
|
||||
const fileName = sudyfileAttrJson.title || '未命名文件.pdf';
|
||||
if (pdfSrc) {
|
||||
let pdfUrl = pdfSrc;
|
||||
if (!pdfUrl.startsWith('http')) {
|
||||
pdfUrl = `${baseUrl}${pdfUrl}`;
|
||||
}
|
||||
// 替换PDF播放器为下载链接
|
||||
$el.replaceWith(`<p><a href="${pdfUrl}" target="_blank">📄 ${fileName}</a></p>`);
|
||||
if (!pdfSrc) {
|
||||
return;
|
||||
}
|
||||
|
||||
let pdfUrl = pdfSrc;
|
||||
if (!pdfUrl.startsWith('http')) {
|
||||
pdfUrl = `${baseUrl}${pdfUrl}`;
|
||||
}
|
||||
// 替换PDF播放器为下载链接
|
||||
$el.replaceWith(`<p><a href="${pdfUrl}" target="_blank">📄 ${fileName}</a></p>`);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
+26
-18
@@ -11,32 +11,40 @@ const fixFigure = (html) => {
|
||||
html('picture source').each((_, i) => {
|
||||
const $i = html(i);
|
||||
if (
|
||||
$i.attr('srcset') &&
|
||||
($i.attr('srcset').startsWith('//media.springernature.com/lw685/') ||
|
||||
$i.attr('srcset').startsWith('//media.springernature.com/m312/') ||
|
||||
$i.attr('srcset').startsWith('//media.springernature.com/relative-r300-703_m1050/') ||
|
||||
$i.attr('srcset').startsWith('//media.springernature.com/w300/'))
|
||||
!(
|
||||
$i.attr('srcset') &&
|
||||
($i.attr('srcset').startsWith('//media.springernature.com/lw685/') ||
|
||||
$i.attr('srcset').startsWith('//media.springernature.com/m312/') ||
|
||||
$i.attr('srcset').startsWith('//media.springernature.com/relative-r300-703_m1050/') ||
|
||||
$i.attr('srcset').startsWith('//media.springernature.com/w300/'))
|
||||
)
|
||||
) {
|
||||
$i.attr('srcset', $i.attr('srcset').replace('//media.springernature.com/lw685/', '//media.springernature.com/full/'));
|
||||
$i.attr('srcset', $i.attr('srcset').replace('//media.springernature.com/m312/', '//media.springernature.com/full/'));
|
||||
$i.attr('srcset', $i.attr('srcset').replace('//media.springernature.com/relative-r300-703_m1050/', '//media.springernature.com/full/'));
|
||||
$i.attr('srcset', $i.attr('srcset').replace('//media.springernature.com/w300/', '//media.springernature.com/full/'));
|
||||
return;
|
||||
}
|
||||
|
||||
$i.attr('srcset', $i.attr('srcset').replace('//media.springernature.com/lw685/', '//media.springernature.com/full/'));
|
||||
$i.attr('srcset', $i.attr('srcset').replace('//media.springernature.com/m312/', '//media.springernature.com/full/'));
|
||||
$i.attr('srcset', $i.attr('srcset').replace('//media.springernature.com/relative-r300-703_m1050/', '//media.springernature.com/full/'));
|
||||
$i.attr('srcset', $i.attr('srcset').replace('//media.springernature.com/w300/', '//media.springernature.com/full/'));
|
||||
});
|
||||
html('img').each((_, i) => {
|
||||
const $i = html(i);
|
||||
if (
|
||||
$i.attr('src') &&
|
||||
($i.attr('src').startsWith('//media.springernature.com/lw685/') ||
|
||||
$i.attr('src').startsWith('//media.springernature.com/m312/') ||
|
||||
$i.attr('src').startsWith('//media.springernature.com/relative-r300-703_m1050/') ||
|
||||
$i.attr('src').startsWith('//media.springernature.com/w300/'))
|
||||
!(
|
||||
$i.attr('src') &&
|
||||
($i.attr('src').startsWith('//media.springernature.com/lw685/') ||
|
||||
$i.attr('src').startsWith('//media.springernature.com/m312/') ||
|
||||
$i.attr('src').startsWith('//media.springernature.com/relative-r300-703_m1050/') ||
|
||||
$i.attr('src').startsWith('//media.springernature.com/w300/'))
|
||||
)
|
||||
) {
|
||||
$i.attr('src', $i.attr('src').replace('//media.springernature.com/lw685/', '//media.springernature.com/full/'));
|
||||
$i.attr('src', $i.attr('src').replace('//media.springernature.com/m312/', '//media.springernature.com/full/'));
|
||||
$i.attr('src', $i.attr('src').replace('//media.springernature.com/relative-r300-703_m1050/', '//media.springernature.com/full/'));
|
||||
$i.attr('src', $i.attr('src').replace('//media.springernature.com/w300/', '//media.springernature.com/full/'));
|
||||
return;
|
||||
}
|
||||
|
||||
$i.attr('src', $i.attr('src').replace('//media.springernature.com/lw685/', '//media.springernature.com/full/'));
|
||||
$i.attr('src', $i.attr('src').replace('//media.springernature.com/m312/', '//media.springernature.com/full/'));
|
||||
$i.attr('src', $i.attr('src').replace('//media.springernature.com/relative-r300-703_m1050/', '//media.springernature.com/full/'));
|
||||
$i.attr('src', $i.attr('src').replace('//media.springernature.com/w300/', '//media.springernature.com/full/'));
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -170,11 +170,7 @@ function extractGenericItem(segment: string, templateId: string) {
|
||||
bodyText = cleanText(bodyMatch[1]);
|
||||
}
|
||||
|
||||
if (!title || !link) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (['더보기', '관련도순', '최신순'].includes(title)) {
|
||||
if (!title || !link || ['더보기', '관련도순', '최신순'].includes(title)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -252,11 +248,7 @@ function parseKoreanRelativeTime(timeText: string): Date | undefined {
|
||||
}
|
||||
|
||||
const match = timeText.match(/(\d+)\s*(시간|[분일주]) 전|(\d+)분 이내|(\d+)시간 이내|방금/);
|
||||
if (!match) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (match[0] === '방금') {
|
||||
if (!match || match[0] === '방금') {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -74,10 +74,12 @@ async function handler(): Promise<Data> {
|
||||
attachments.each((_, el) => {
|
||||
const href = $detail(el).attr('href');
|
||||
const text = $detail(el).text().trim();
|
||||
if (href && text) {
|
||||
const absoluteHref = href.startsWith('http') ? href : new URL(href, baseUrl).href;
|
||||
description += `<li><a href="${absoluteHref}">${text}</a></li>`;
|
||||
if (!href || !text) {
|
||||
return;
|
||||
}
|
||||
|
||||
const absoluteHref = href.startsWith('http') ? href : new URL(href, baseUrl).href;
|
||||
description += `<li><a href="${absoluteHref}">${text}</a></li>`;
|
||||
});
|
||||
description += '</ul>';
|
||||
}
|
||||
|
||||
+15
-13
@@ -120,20 +120,22 @@ const cleanEntryContent = ($) => {
|
||||
entry.find('.wp_video_player').each((_, el) => {
|
||||
const div = $(el);
|
||||
const src = div.attr('sudy-wp-src');
|
||||
if (src) {
|
||||
const videoUrl = BASE_URL + src;
|
||||
const widthMatch = div.attr('style')?.match(/width:\s*(\d+)px/);
|
||||
const width = widthMatch && widthMatch[1] ? widthMatch[1] : '600';
|
||||
const heightMatch = div.attr('style')?.match(/height:\s*(\d+)px/);
|
||||
const height = heightMatch && heightMatch[1] ? heightMatch[1] : '400';
|
||||
const videoTag = `
|
||||
<video controls width="${width}" height="${height}" style="max-width: 100%;margin-left: auto;margin-right: auto;">
|
||||
<source src="${videoUrl}" type="video/mp4">
|
||||
您的浏览器不支持 video 标签。
|
||||
</video>
|
||||
`;
|
||||
div.replaceWith(videoTag);
|
||||
if (!src) {
|
||||
return;
|
||||
}
|
||||
|
||||
const videoUrl = BASE_URL + src;
|
||||
const widthMatch = div.attr('style')?.match(/width:\s*(\d+)px/);
|
||||
const width = widthMatch && widthMatch[1] ? widthMatch[1] : '600';
|
||||
const heightMatch = div.attr('style')?.match(/height:\s*(\d+)px/);
|
||||
const height = heightMatch && heightMatch[1] ? heightMatch[1] : '400';
|
||||
const videoTag = `
|
||||
<video controls width="${width}" height="${height}" style="max-width: 100%;margin-left: auto;margin-right: auto;">
|
||||
<source src="${videoUrl}" type="video/mp4">
|
||||
您的浏览器不支持 video 标签。
|
||||
</video>
|
||||
`;
|
||||
div.replaceWith(videoTag);
|
||||
});
|
||||
return entry.html();
|
||||
};
|
||||
|
||||
@@ -12,8 +12,8 @@ const handler: Route['handler'] = async () => {
|
||||
|
||||
const item = await Promise.all(
|
||||
$('article')
|
||||
.toArray()
|
||||
.slice(0, 20)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
const $ = load(item);
|
||||
const link = `https://nextjs.org${$('a[href^="/blog"]').attr('href')}`;
|
||||
|
||||
@@ -24,8 +24,8 @@ const handler: Route['handler'] = async () => {
|
||||
// archive
|
||||
const item = await Promise.all(
|
||||
$('div[class^="releasePreviewsSection"] h3 a[href^="/releases/"]')
|
||||
.toArray()
|
||||
.slice(0, 5)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
const link = `https://notion.so${item.attribs.href}`;
|
||||
|
||||
|
||||
@@ -24,13 +24,15 @@ function generateEnclosureInfo(htmlContent: string): { enclosure_url?: string; e
|
||||
const extension = src.replace(/.*\./, '').toLowerCase();
|
||||
const mimeType = MIME_TYPE_MAP[extension as keyof typeof MIME_TYPE_MAP];
|
||||
|
||||
if (mimeType) {
|
||||
enclosureInfo = {
|
||||
enclosure_url: src,
|
||||
enclosure_type: mimeType,
|
||||
};
|
||||
return false;
|
||||
if (!mimeType) {
|
||||
return;
|
||||
}
|
||||
|
||||
enclosureInfo = {
|
||||
enclosure_url: src,
|
||||
enclosure_type: mimeType,
|
||||
};
|
||||
return false;
|
||||
});
|
||||
|
||||
return enclosureInfo;
|
||||
|
||||
@@ -89,8 +89,6 @@ async function handler(ctx) {
|
||||
const items = await Promise.all(
|
||||
list.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
let media = '';
|
||||
|
||||
if (item.slideOrVideo) {
|
||||
const page = await context.newPage();
|
||||
await page.route('**/*', (route) => {
|
||||
@@ -105,7 +103,7 @@ async function handler(ctx) {
|
||||
const html = await page.content();
|
||||
const $ = load(html);
|
||||
|
||||
media = $('.slide-item').length
|
||||
const media = $('.slide-item').length
|
||||
? $('.slide-item div:first-of-type')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
|
||||
@@ -55,11 +55,8 @@ async function handler(ctx): Promise<Data> {
|
||||
const seriesInfo: SeriesDetail = seriesInfoResponse.data;
|
||||
|
||||
// xRestrict: 0=All ages, 1=R18, 2=R18G
|
||||
if (seriesInfo.body.xRestrict > 0) {
|
||||
return await getNSFWSeriesNovels(id, limit);
|
||||
}
|
||||
// All-ages: prefer NSFW handler if authenticated
|
||||
if (hasPixivAuth()) {
|
||||
if (seriesInfo.body.xRestrict > 0 || hasPixivAuth()) {
|
||||
return await getNSFWSeriesNovels(id, limit);
|
||||
}
|
||||
return await getSFWSeriesNovels(id, limit);
|
||||
|
||||
@@ -47,17 +47,19 @@ const pixivGot = got.extend({
|
||||
logger.warn(`No IPv4 address resolved from ${config.pixiv.bypassCdnHostname}`);
|
||||
}
|
||||
}
|
||||
if (hostname) {
|
||||
const actualHost = options.url.host;
|
||||
options.headers = {
|
||||
...options.headers,
|
||||
host: actualHost,
|
||||
};
|
||||
options.url.hostname = hostname;
|
||||
options.checkServerIdentity = function (host, certificate) {
|
||||
return tls.checkServerIdentity(actualHost, certificate);
|
||||
};
|
||||
if (!hostname) {
|
||||
return;
|
||||
}
|
||||
|
||||
const actualHost = options.url.host;
|
||||
options.headers = {
|
||||
...options.headers,
|
||||
host: actualHost,
|
||||
};
|
||||
options.url.hostname = hostname;
|
||||
options.checkServerIdentity = function (host, certificate) {
|
||||
return tls.checkServerIdentity(actualHost, certificate);
|
||||
};
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@@ -58,25 +58,29 @@ export function processContent($: CheerioAPI, lang: string): string {
|
||||
const $link = $elem.find('blockquote > a');
|
||||
const href = $link.attr('href');
|
||||
|
||||
if (href) {
|
||||
const match = href.match(/\/status\/(\d+)/);
|
||||
if (match) {
|
||||
const tweetId = match[1];
|
||||
$elem.html(`
|
||||
<iframe
|
||||
scrolling="no"
|
||||
frameborder="0"
|
||||
allowtransparency="true"
|
||||
allowfullscreen="true"
|
||||
class=""
|
||||
style="position: static; visibility: visible; display: block; width: 550px; height: 1000px; flex-grow: 1;"
|
||||
title="X Post"
|
||||
src="https://platform.twitter.com/embed/Tweet.html?id=${tweetId}"
|
||||
></iframe>
|
||||
`);
|
||||
$elem.find('blockquote').remove();
|
||||
}
|
||||
if (!href) {
|
||||
return;
|
||||
}
|
||||
|
||||
const match = href.match(/\/status\/(\d+)/);
|
||||
if (!match) {
|
||||
return;
|
||||
}
|
||||
|
||||
const tweetId = match[1];
|
||||
$elem.html(`
|
||||
<iframe
|
||||
scrolling="no"
|
||||
frameborder="0"
|
||||
allowtransparency="true"
|
||||
allowfullscreen="true"
|
||||
class=""
|
||||
style="position: static; visibility: visible; display: block; width: 550px; height: 1000px; flex-grow: 1;"
|
||||
title="X Post"
|
||||
src="https://platform.twitter.com/embed/Tweet.html?id=${tweetId}"
|
||||
></iframe>
|
||||
`);
|
||||
$elem.find('blockquote').remove();
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
@@ -32,10 +32,12 @@ const getPlurk = (plurkGuid, item, author) => {
|
||||
$('img').each((_, e) => {
|
||||
const $e = $(e);
|
||||
$e.removeAttr('height').removeAttr('width');
|
||||
if ($e.attr('alt') && $e.attr('alt')!.startsWith('http')) {
|
||||
$e.attr('src', $e.attr('alt'));
|
||||
$e.removeAttr('alt');
|
||||
if (!($e.attr('alt') && $e.attr('alt')!.startsWith('http'))) {
|
||||
return;
|
||||
}
|
||||
|
||||
$e.attr('src', $e.attr('alt'));
|
||||
$e.removeAttr('alt');
|
||||
});
|
||||
|
||||
return {
|
||||
|
||||
@@ -29,8 +29,8 @@ async function handler(ctx: Context) {
|
||||
const $ = load(response);
|
||||
|
||||
const list: DataItem[] = $('.archive-item-link')
|
||||
.toArray()
|
||||
.slice(0, 15)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
const $item = $(item);
|
||||
return {
|
||||
|
||||
@@ -28,8 +28,8 @@ async function handler(ctx: Context) {
|
||||
|
||||
const $ = load(response);
|
||||
const list: DataItem[] = $('.release-notes-content__versions li')
|
||||
.toArray()
|
||||
.slice(0, 20)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
const $item = $(item);
|
||||
return {
|
||||
|
||||
@@ -32,8 +32,8 @@ async function handler(ctx: Context) {
|
||||
$('a.news-more').remove();
|
||||
|
||||
const list = $('li.clearfix div.news-right a')
|
||||
.toArray()
|
||||
.slice(0, 10)
|
||||
.toArray()
|
||||
.map((item): DataItem => {
|
||||
const $item = $(item);
|
||||
return {
|
||||
|
||||
@@ -12,8 +12,8 @@ const handler: Route['handler'] = async () => {
|
||||
|
||||
const item = await Promise.all(
|
||||
$('a[href^="/blog/"]')
|
||||
.toArray()
|
||||
.slice(0, 20)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
const link = `https://react.dev${item.attribs.href}`;
|
||||
|
||||
|
||||
@@ -77,8 +77,8 @@ Parsing of \`routeParams\` parameter:
|
||||
const rssTitle = routeParams.get('title') || $('title').text();
|
||||
const item = routeParams.get('item') || 'html';
|
||||
let items: DataItem[] = $(item)
|
||||
.toArray()
|
||||
.slice(0, 20)
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
try {
|
||||
const $item = $(item);
|
||||
|
||||
@@ -105,13 +105,15 @@ async function fetchContent(url) {
|
||||
stubS.find('img').each((_, el) => {
|
||||
const img = subind(el);
|
||||
const file = img.attr('file');
|
||||
if (file) {
|
||||
img.attr('src', file);
|
||||
img.removeAttr('zoomfile');
|
||||
img.removeAttr('file');
|
||||
img.removeAttr('onmouseover');
|
||||
img.removeAttr('onclick');
|
||||
if (!file) {
|
||||
return;
|
||||
}
|
||||
|
||||
img.attr('src', file);
|
||||
img.removeAttr('zoomfile');
|
||||
img.removeAttr('file');
|
||||
img.removeAttr('onmouseover');
|
||||
img.removeAttr('onclick');
|
||||
});
|
||||
|
||||
return stubS.html();
|
||||
|
||||
@@ -50,8 +50,8 @@ async function handler(ctx) {
|
||||
const staticUrl = new URL('/image/common/none.gif', host);
|
||||
staticUrl.hostname = `static.${staticUrl.hostname.split('.').slice(-2).join('.')}`;
|
||||
const resultItems = list
|
||||
.toArray()
|
||||
.slice(0, 20)
|
||||
.toArray()
|
||||
.map((post) => {
|
||||
const each = $(post);
|
||||
const floor = each.find('td.plc .pi a > em').text();
|
||||
|
||||
@@ -60,8 +60,8 @@ async function handler() {
|
||||
};
|
||||
});
|
||||
const paperTable = $('tbody tr')
|
||||
.toArray()
|
||||
.slice(1) // skip table header
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
const $item = $(item);
|
||||
const title = $item.find('td').eq(0).text().trim();
|
||||
|
||||
@@ -68,13 +68,15 @@ async function handler() {
|
||||
const text = span.html();
|
||||
span.remove();
|
||||
|
||||
if (spanClass !== undefined) {
|
||||
const type = spanClass.split(' ', 2)[1];
|
||||
if (type === 'empty') {
|
||||
$li.wrap('<ul></ul>');
|
||||
} else {
|
||||
$li.prepend(`<b style='color:${textColor[type]}'>${text}: </b>`);
|
||||
}
|
||||
if (spanClass === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const type = spanClass.split(' ', 2)[1];
|
||||
if (type === 'empty') {
|
||||
$li.wrap('<ul></ul>');
|
||||
} else {
|
||||
$li.prepend(`<b style='color:${textColor[type]}'>${text}: </b>`);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -38,8 +38,8 @@ async function handler(ctx: Context) {
|
||||
const threads = $('form table')
|
||||
.last()
|
||||
.find('tbody')
|
||||
.toArray()
|
||||
.slice(1) // skip first empty row
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
const $item = $(item);
|
||||
return {
|
||||
|
||||
@@ -6,11 +6,13 @@ export const parseSearchDate = (value: string, now = new Date()): Date | undefin
|
||||
if (/^\d{2}:\d{2}$/.test(value)) {
|
||||
return parseDateInTimezone(`${today}T${value}`, 8);
|
||||
}
|
||||
if (/^\d{2}-\d{2} \d{2}:\d{2}$/.test(value)) {
|
||||
// Search results omit the year; a later month/day belongs to last year.
|
||||
const year = Number(today.slice(0, 4)) - Number(value.slice(0, 5) > today.slice(5));
|
||||
return parseDateInTimezone(`${year}-${value}`, 8);
|
||||
if (!/^\d{2}-\d{2} \d{2}:\d{2}$/.test(value)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Search results omit the year; a later month/day belongs to last year.
|
||||
const year = Number(today.slice(0, 4)) - Number(value.slice(0, 5) > today.slice(5));
|
||||
return parseDateInTimezone(`${year}-${value}`, 8);
|
||||
};
|
||||
|
||||
export const getHeaders = () => ({
|
||||
|
||||
@@ -58,7 +58,7 @@ export const route: Route = {
|
||||
const configTarget = urlMap[type] || urlMap.tzgg;
|
||||
const response = await ofetch(configTarget.url);
|
||||
const $ = load(response);
|
||||
const list = $('.lunwen dl dd').toArray().slice(0, 10);
|
||||
const list = $('.lunwen dl dd').slice(0, 10).toArray();
|
||||
|
||||
const items = await Promise.all(
|
||||
list.map((item) => {
|
||||
|
||||
@@ -31,7 +31,7 @@ export const route: Route = {
|
||||
const url = 'https://www.snnu.edu.cn/tzgg.htm';
|
||||
const response = await ofetch(url);
|
||||
const $ = load(response);
|
||||
const list = $('.ul-txtq3 li').toArray().slice(0, 10);
|
||||
const list = $('.ul-txtq3 li').slice(0, 10).toArray();
|
||||
|
||||
const items = await Promise.all(
|
||||
list.map((item) => {
|
||||
|
||||
@@ -31,7 +31,7 @@ export const route: Route = {
|
||||
const url = 'https://newyjs.snnu.edu.cn/tzgg1.htm';
|
||||
const response = await ofetch(url);
|
||||
const $ = load(response);
|
||||
const list = $('.n_bt li').toArray().slice(0, 10);
|
||||
const list = $('.n_bt li').slice(0, 10).toArray();
|
||||
|
||||
const items = await Promise.all(
|
||||
list.map((item) => {
|
||||
|
||||
@@ -29,7 +29,7 @@ async function handler() {
|
||||
link: a.attr('href')!,
|
||||
};
|
||||
});
|
||||
const uniqueList = new Map(list.map((item) => [item.link, item])).values().toArray().slice(0, 15);
|
||||
const uniqueList = new Map(list.map((item) => [item.link, item])).values().take(15).toArray();
|
||||
|
||||
const items = await Promise.all(
|
||||
uniqueList.map((item) =>
|
||||
|
||||
@@ -89,10 +89,12 @@ function fetchArticle(item) {
|
||||
});
|
||||
article.find('img').each((_, e) => {
|
||||
const $e = $(e);
|
||||
if ($e.attr('data-src') && !$e.attr('src')) {
|
||||
$e.attr('src', decryptImageUrl($e.attr('data-src')));
|
||||
$e.removeAttr('data-src');
|
||||
if (!$e.attr('data-src') || $e.attr('src')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$e.attr('src', decryptImageUrl($e.attr('data-src')));
|
||||
$e.removeAttr('data-src');
|
||||
});
|
||||
|
||||
item.description = article.html();
|
||||
|
||||
@@ -5,9 +5,8 @@ import { parseDate } from '@/utils/parse-date';
|
||||
import timezone from '@/utils/timezone';
|
||||
|
||||
export default async function get_article(url) {
|
||||
const domain = 'https://www.solidot.org';
|
||||
|
||||
if (/^\/.*$/.test(url)) {
|
||||
const domain = 'https://www.solidot.org';
|
||||
url = domain + url;
|
||||
}
|
||||
const response = await got({
|
||||
|
||||
@@ -24,10 +24,12 @@ const fixImages = ($) => {
|
||||
|
||||
const hdImage = (img) => {
|
||||
img.attribs.src = img.attribs.src.replace('_thm', '').replace('_small', '');
|
||||
if (img.parentNode.name === 'a' && img.parentNode.attribs['data-width'] && img.parentNode.attribs['data-height']) {
|
||||
img.attribs.width = img.parentNode.attribs['data-width'];
|
||||
img.attribs.height = img.parentNode.attribs['data-height'];
|
||||
if (!(img.parentNode.name === 'a' && img.parentNode.attribs['data-width'] && img.parentNode.attribs['data-height'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
img.attribs.width = img.parentNode.attribs['data-width'];
|
||||
img.attribs.height = img.parentNode.attribs['data-height'];
|
||||
};
|
||||
const removeFigureStyle = (f) => {
|
||||
delete f.attribs.style;
|
||||
|
||||
@@ -50,10 +50,7 @@ function ExpandInlineBytes(bytes: Buffer) {
|
||||
}
|
||||
|
||||
function sortThumb(thumb: Api.TypePhotoSize) {
|
||||
if (thumb instanceof Api.PhotoStrippedSize) {
|
||||
return thumb.bytes.length;
|
||||
}
|
||||
if (thumb instanceof Api.PhotoCachedSize) {
|
||||
if (thumb instanceof Api.PhotoStrippedSize || thumb instanceof Api.PhotoCachedSize) {
|
||||
return thumb.bytes.length;
|
||||
}
|
||||
if (thumb instanceof Api.PhotoSize) {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user