mirror of
https://github.com/DIYgod/RSSHub.git
synced 2026-09-01 14:57:14 +08:00
fix(route): wired (#15771)
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
import type { Namespace } from '@/types';
|
||||
|
||||
export const namespace: Namespace = {
|
||||
name: 'WIRED',
|
||||
url: 'www.wired.com',
|
||||
categories: ['traditional-media'],
|
||||
};
|
||||
@@ -0,0 +1,97 @@
|
||||
import { Route } from '@/types';
|
||||
|
||||
import cache from '@/utils/cache';
|
||||
import ofetch from '@/utils/ofetch';
|
||||
import * as cheerio from 'cheerio';
|
||||
import { Item } from './types';
|
||||
import { parseDate } from '@/utils/parse-date';
|
||||
|
||||
export const route: Route = {
|
||||
path: '/tag/:tag',
|
||||
example: '/wired/tag/facebook',
|
||||
parameters: { tag: 'Tag name' },
|
||||
radar: [
|
||||
{
|
||||
source: ['www.wired.com/tag/:tag/'],
|
||||
},
|
||||
],
|
||||
name: 'Tags',
|
||||
maintainers: ['Naiqus'],
|
||||
handler,
|
||||
};
|
||||
|
||||
async function handler(ctx) {
|
||||
const baseUrl = 'https://www.wired.com';
|
||||
const { tag } = ctx.req.param() as { tag: string };
|
||||
const link = `${baseUrl}/tag/${tag}/`;
|
||||
|
||||
const response = await ofetch(link);
|
||||
const $ = cheerio.load(response);
|
||||
const preloadedState = JSON.parse(
|
||||
$('script:contains("window.__PRELOADED_STATE__")')
|
||||
.text()
|
||||
.match(/window\.__PRELOADED_STATE__ = (.*);/)?.[1] ?? '{}'
|
||||
);
|
||||
|
||||
const list = (preloadedState.transformed.tag.items as Item[]).map((item) => ({
|
||||
title: item.dangerousHed,
|
||||
description: item.dangerousDek,
|
||||
link: `${baseUrl}${item.url}`,
|
||||
pubDate: parseDate(item.date),
|
||||
author: item.contributors.author.items.map((author) => author.name).join(', '),
|
||||
category: [item.rubric.name],
|
||||
}));
|
||||
|
||||
const items = await Promise.all(
|
||||
list.map((item) =>
|
||||
cache.tryGet(item.link, async () => {
|
||||
const response = await ofetch(item.link);
|
||||
const $ = cheerio.load(response);
|
||||
const preloadedState = JSON.parse(
|
||||
$('script:contains("window.__PRELOADED_STATE__")')
|
||||
.text()
|
||||
.match(/window\.__PRELOADED_STATE__ = (.*);/)?.[1] ?? '{}'
|
||||
);
|
||||
|
||||
const headerLeadAsset = $('div[data-testid*="ContentHeaderLeadAsset"]');
|
||||
headerLeadAsset.find('button').remove();
|
||||
// false postive: 'some' does not exist on type 'Cheerio<Element>'
|
||||
// eslint-disable-next-line unicorn/prefer-array-some
|
||||
if (headerLeadAsset.find('video')) {
|
||||
headerLeadAsset.find('video').attr('src', $('link[rel="preload"][as="video"]').attr('href'));
|
||||
headerLeadAsset.find('video').attr('controls', '');
|
||||
headerLeadAsset.find('video').attr('preload', 'metadata');
|
||||
headerLeadAsset.find('video').removeAttr('autoplay');
|
||||
}
|
||||
|
||||
const content = $('.body__inner-container')
|
||||
.toArray()
|
||||
.map((el) => {
|
||||
const $el = $(el);
|
||||
$el.find('noscript').each((_, el) => {
|
||||
const $e = $(el);
|
||||
$e.replaceWith($e.html() || '');
|
||||
});
|
||||
|
||||
return $el.html();
|
||||
})
|
||||
.join('');
|
||||
|
||||
item.description = ($('div[class^=ContentHeaderDek]').prop('outerHTML') || '') + headerLeadAsset.prop('outerHTML') + content;
|
||||
|
||||
item.category = [...new Set([...item.category, ...preloadedState.transformed.article.tagCloud.tags.map((t: { tag: string }) => t.tag)])];
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
return {
|
||||
title: preloadedState.transformed['head.title'],
|
||||
description: preloadedState.transformed['head.description'],
|
||||
link,
|
||||
image: `${baseUrl}${preloadedState.transformed.logo.sources.sm.url}`,
|
||||
language: 'en',
|
||||
item: items,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
interface ImageSource {
|
||||
aspectRatio: string;
|
||||
width: number;
|
||||
url: string;
|
||||
srcset: string;
|
||||
}
|
||||
|
||||
interface Image {
|
||||
contentType: string;
|
||||
id: string;
|
||||
altText: string;
|
||||
credit: string;
|
||||
caption: string;
|
||||
metaData: string;
|
||||
modelName: string;
|
||||
sources: {
|
||||
sm: ImageSource;
|
||||
md: ImageSource;
|
||||
lg: ImageSource;
|
||||
xl: ImageSource;
|
||||
xxl: ImageSource;
|
||||
};
|
||||
segmentedSources: {
|
||||
sm: ImageSource[];
|
||||
lg: ImageSource[];
|
||||
};
|
||||
showImageWithoutLink: boolean;
|
||||
isLazy: boolean;
|
||||
brandDetail: {
|
||||
brandIcon: string;
|
||||
brandName: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface Contributor {
|
||||
author: {
|
||||
items: { name: string }[];
|
||||
};
|
||||
photographer: {
|
||||
items: any[];
|
||||
};
|
||||
}
|
||||
|
||||
interface Rubric {
|
||||
name: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
interface RecircMostPopular {
|
||||
contentType: string;
|
||||
dangerousHed: string;
|
||||
dangerousDek: string;
|
||||
url: string;
|
||||
rubric: { name: string };
|
||||
tout: Image;
|
||||
image: Image;
|
||||
contributors: {
|
||||
author: {
|
||||
brandName: string;
|
||||
brandSlug: string;
|
||||
preamble: string;
|
||||
items: { name: string }[];
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export interface Item {
|
||||
contributors: Contributor;
|
||||
contentType: string;
|
||||
date: string;
|
||||
dangerousDek: string;
|
||||
dangerousHed: string;
|
||||
id: string;
|
||||
image: Image;
|
||||
imageLabels: any[];
|
||||
hasNoFollowOnSyndicated: boolean;
|
||||
rating: string;
|
||||
rubric: Rubric;
|
||||
url: string;
|
||||
recircMostPopular: RecircMostPopular[];
|
||||
}
|
||||
Reference in New Issue
Block a user