feat(route): techpowerup (#12551)
* feat(route): techpowerup * feat(route): techpowerup
This commit is contained in:
parent
83476621d8
commit
dd2be12722
|
|
@ -772,6 +772,16 @@ Compared to the official one, this feed:
|
|||
|
||||
<RouteEn author="NavePnow" example="/techcrunch/news" path="/techcrunch/news"/>
|
||||
|
||||
## TechPowerUp
|
||||
|
||||
### Latest Content
|
||||
|
||||
<RouteEn author="TonyRL" example="/techpowerup" path="/techpowerup" radar="1" />
|
||||
|
||||
### Reviews
|
||||
|
||||
<RouteEn author="TonyRL" example="/techpowerup/review/4090" path="/techpowerup/review/:keyword?" :paramsDesc="['Search Keyword']" radar="1" />
|
||||
|
||||
## The Brain
|
||||
|
||||
### Blog
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const { baseUrl, headers, fixImages, parseReviews } = require('./utils');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const { data: response } = await got(baseUrl, {
|
||||
headers,
|
||||
});
|
||||
|
||||
const $ = cheerio.load(response);
|
||||
|
||||
const list = $('.newspost')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
const a = item.find('h1 a');
|
||||
const date = item.find('time').attr('datetime');
|
||||
return {
|
||||
title: a.text(),
|
||||
link: baseUrl + a.attr('href'),
|
||||
pubDate: date ? parseDate(date) : null, // 2023-05-21T16:05:14+00:00
|
||||
author: item.find('.byline address').text(),
|
||||
category: item
|
||||
.find('.byline .flags span')
|
||||
.toArray()
|
||||
.map((item) => $(item).text().trim()),
|
||||
};
|
||||
});
|
||||
|
||||
const items = await Promise.all(
|
||||
list.map((item) =>
|
||||
ctx.cache.tryGet(item.link, async () => {
|
||||
const { data: response } = await got(item.link, {
|
||||
headers,
|
||||
});
|
||||
const $ = cheerio.load(response);
|
||||
|
||||
fixImages($);
|
||||
|
||||
if (item.link.includes('/review/')) {
|
||||
await parseReviews($, item);
|
||||
return item;
|
||||
}
|
||||
|
||||
// news
|
||||
item.description = $('.newspost .text').html();
|
||||
item.category = [
|
||||
...new Set([
|
||||
...item.category,
|
||||
...$('.tags li a')
|
||||
.toArray()
|
||||
.map((item) => $(item).text()),
|
||||
]),
|
||||
];
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
ctx.state.data = {
|
||||
title: 'TechPowerUp',
|
||||
link: baseUrl,
|
||||
language: 'en',
|
||||
image: 'https://tpucdn.com/apple-touch-icon-v1684568903519.png',
|
||||
item: items,
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
module.exports = {
|
||||
'': ['TonyRL'],
|
||||
'/': ['TonyRL'],
|
||||
'/review/:keyword?': ['TonyRL'],
|
||||
};
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
module.exports = {
|
||||
'techpowerup.com': {
|
||||
_name: 'TechPowerUp',
|
||||
'.': [
|
||||
{
|
||||
title: 'Latest Content',
|
||||
docs: 'https://docs.rsshub.app/en/new-media.html#techpowerup',
|
||||
source: ['/'],
|
||||
target: '/techpowerup',
|
||||
},
|
||||
{
|
||||
title: 'Reviews',
|
||||
docs: 'https://docs.rsshub.app/en/new-media.html#techpowerup',
|
||||
source: ['/review/search', '/review'],
|
||||
target: (_, url) => `/techpowerup/review${new URL(url).searchParams.has('q') ? `/${new URL(url).searchParams.get('q')}` : ''}`,
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const { baseUrl, headers, fixImages, parseReviews } = require('./utils');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const { keyword } = ctx.params;
|
||||
|
||||
const url = new URL(`${baseUrl}/review/${keyword ? 'search/' : ''}`);
|
||||
if (keyword) {
|
||||
url.searchParams.set('q', keyword);
|
||||
url.searchParams.set('_', Date.now());
|
||||
}
|
||||
|
||||
const { data: response } = await got(url, {
|
||||
headers,
|
||||
});
|
||||
|
||||
const $ = cheerio.load(response);
|
||||
|
||||
const list = $('.reviewlist-bit')
|
||||
.toArray()
|
||||
.map((item) => {
|
||||
item = $(item);
|
||||
const a = item.find('.title a');
|
||||
return {
|
||||
title: a.text(),
|
||||
link: baseUrl + a.attr('href'),
|
||||
pubDate: parseDate(item.find('.date time').attr('datetime')), // 2023-05-21T16:05:14+00:00
|
||||
author: item
|
||||
.find('.author')
|
||||
.contents()
|
||||
.filter((_, c) => c.type === 'text')
|
||||
.text()
|
||||
.trim(),
|
||||
category: item
|
||||
.find('.category')
|
||||
.contents()
|
||||
.filter((_, c) => c.type === 'text')
|
||||
.text()
|
||||
.trim(),
|
||||
};
|
||||
});
|
||||
|
||||
const items = await Promise.all(
|
||||
list.map((item) =>
|
||||
ctx.cache.tryGet(item.link, async () => {
|
||||
const { data: response } = await got(item.link, {
|
||||
headers,
|
||||
});
|
||||
const $ = cheerio.load(response);
|
||||
|
||||
fixImages($);
|
||||
|
||||
await parseReviews($, item);
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
ctx.state.data = {
|
||||
title: 'Reviews | TechPowerUp',
|
||||
link: url.href,
|
||||
language: 'en',
|
||||
image: 'https://tpucdn.com/apple-touch-icon-v1684568903519.png',
|
||||
item: items,
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
module.exports = (router) => {
|
||||
router.get('/', require('./index'));
|
||||
router.get('/review/:keyword?', require('./review'));
|
||||
};
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const md5 = require('@/utils/md5');
|
||||
|
||||
const baseUrl = 'https://www.techpowerup.com';
|
||||
|
||||
const headers = {
|
||||
cookie: `botcheck=${md5(Date.now().toString())}`,
|
||||
};
|
||||
|
||||
const fixImages = ($) => {
|
||||
$('div.responsive-image-xx').each((_, d) => {
|
||||
removeResponsiveStyle(d);
|
||||
});
|
||||
$('figure').each((_, f) => {
|
||||
removeFigureStyle(f);
|
||||
});
|
||||
$('.newspost img').each((_, img) => {
|
||||
hdImage(img);
|
||||
});
|
||||
};
|
||||
|
||||
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'];
|
||||
}
|
||||
};
|
||||
const removeFigureStyle = (f) => {
|
||||
delete f.attribs.style;
|
||||
};
|
||||
|
||||
const removeResponsiveStyle = (div) => {
|
||||
delete div.attribs.style;
|
||||
};
|
||||
|
||||
const parseReviews = async ($, item) => {
|
||||
const { review } = JSON.parse($('script[type="application/ld+json"]').text());
|
||||
|
||||
const content = $('.text');
|
||||
const nextPages = $('#pagesel option')
|
||||
.toArray()
|
||||
.map((a) => `${baseUrl}${a.attribs.value}`)
|
||||
.slice(1, -1);
|
||||
|
||||
if (nextPages.length) {
|
||||
const pages = await Promise.all(
|
||||
nextPages.map(async (url) => {
|
||||
const { data: response } = await got(url, {
|
||||
headers,
|
||||
});
|
||||
const $ = cheerio.load(response);
|
||||
$('.text div.responsive-image-xx').each((_, d) => {
|
||||
removeResponsiveStyle(d);
|
||||
});
|
||||
$('.text figure').each((_, f) => {
|
||||
removeFigureStyle(f);
|
||||
});
|
||||
$('.text img').each((_, img) => {
|
||||
hdImage(img);
|
||||
});
|
||||
return $('.text').html();
|
||||
})
|
||||
);
|
||||
content.append(pages);
|
||||
}
|
||||
|
||||
item.author = review.author.name;
|
||||
item.pubDate = parseDate(review.datePublished);
|
||||
item.updated = parseDate(review.dateModified);
|
||||
item.description = content.html();
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
baseUrl,
|
||||
headers,
|
||||
fixImages,
|
||||
hdImage,
|
||||
parseReviews,
|
||||
removeFigureStyle,
|
||||
removeResponsiveStyle,
|
||||
};
|
||||
Loading…
Reference in New Issue