mirror of
https://github.com/DIYgod/RSSHub.git
synced 2026-09-24 23:12:34 +08:00
fix(route): gq taiwan (#11549)
This commit is contained in:
+20
-26
@@ -540,15 +540,15 @@ Country
|
||||
|
||||
## GQ
|
||||
|
||||
### GQ 台湾
|
||||
### GQ Taiwan
|
||||
|
||||
<Route author="nczitzk" example="/gq/tw/fashion" path="/gq/tw/:caty?/:subcaty?" :paramsDesc="['分类,见下表', '子分类,见下表']">
|
||||
<Route author="nczitzk" example="/gq/tw/fashion" path="/gq/tw/:caty?/:subcaty?" :paramsDesc="['分类,见下表', '子分类,见下表']" radar="1">
|
||||
|
||||
分类
|
||||
|
||||
| Fashion | Entertainment | Life | Gadget | Better Men | Video | Tag |
|
||||
| ------- | ------------- | ---- | ------ | ---------- | ----- | --- |
|
||||
| fashion | entertainment | life | gadget | bettermen | video | tag |
|
||||
| Fashion | Shopping | Entertainment | Life | Gadget | Better Men | Video | Tag |
|
||||
| ------- | ------------- | ------------- | ---- | ------ | ---------- | ----- | --- |
|
||||
| fashion | gq-recommends | entertainment | life | gadget | bettermen | video | tag |
|
||||
|
||||
子分类
|
||||
|
||||
@@ -560,39 +560,33 @@ Fashion
|
||||
|
||||
Entertainment
|
||||
|
||||
| 最新推薦 | 電影 | 娛樂 | 名人 | 美女 | 體育 | 特別報導 |
|
||||
| ---- | ----- | ---------- | ----------- | ---- | ------ | ------- |
|
||||
| | movie | popculture | celebrities | girl | sports | special |
|
||||
| All topics | 電影 | 娛樂 | 名人 | 美女 | 體育 | 特別報導 |
|
||||
| ---------- | ----- | ---------- | ----------- | ---- | ------ | ------- |
|
||||
| | movie | popculture | celebrities | girl | sports | special |
|
||||
|
||||
Life
|
||||
|
||||
| 最新推薦 | 美食 | 微醺 | 戶外生活 | 設計生活 | 風格幕後 | 特別報導 |
|
||||
| ---- | ---- | ---- | ------- | ------ | ---------------- | ------- |
|
||||
| | food | wine | outdoor | design | lifestyleinsider | special |
|
||||
| All topics | 美食 | 微醺 | 戶外生活 | 設計生活 | 風格幕後 | 特別報導 |
|
||||
| ---------- | ---- | ---- | ------- | ------ | ---------------- | ------- |
|
||||
| | food | wine | outdoor | design | lifestyleinsider | special |
|
||||
|
||||
Gadget
|
||||
|
||||
| 最新推薦 | 3C | 車 | 腕錶 | 特別報導 |
|
||||
| ---- | -- | ---- | ----- | ------- |
|
||||
| | 3c | auto | watch | special |
|
||||
| All topics | 3C | 車 | 腕錶 | 特別報導 |
|
||||
| ---------- | -- | ---- | ----- | ------- |
|
||||
| | 3c | auto | watch | special |
|
||||
|
||||
Better Men
|
||||
|
||||
| 最新推薦 | 保養健身 | 感情關係 | 性愛 | 特別報導 |
|
||||
| ---- | --------- | ------------ | --- | ------- |
|
||||
| | wellbeing | relationship | sex | special |
|
||||
|
||||
Video
|
||||
|
||||
| 最新推薦 | 名人 | 全球娛樂 | 玩家收藏 | 穿搭 | 生活 |
|
||||
| ---- | ------ | ------------------- | ------- | ----- | ---- |
|
||||
| | people | globalentertainment | collect | style | life |
|
||||
| All topics | 保養健身 | 感情關係 | 性愛 | 特別報導 |
|
||||
| ---------- | --------- | ------------ | --- | ------- |
|
||||
| | wellbeing | relationship | sex | special |
|
||||
|
||||
Tag
|
||||
|
||||
| 奧斯卡 |
|
||||
| ------------------- |
|
||||
| `the-oscars-奧斯卡金像獎` |
|
||||
| 奧斯卡 | MOTY |
|
||||
| ------------------- | ---- |
|
||||
| `the-oscars-奧斯卡金像獎` | moty |
|
||||
|
||||
</Route>
|
||||
|
||||
|
||||
+1
-1
@@ -3179,7 +3179,7 @@ router.get('/1x/:category?', lazyloadRouteHandler('./routes/1x/index'));
|
||||
router.get('/jx3/:caty?', lazyloadRouteHandler('./routes/jx3/news'));
|
||||
|
||||
// GQ
|
||||
router.get('/gq/tw/:caty?/:subcaty?', lazyloadRouteHandler('./routes/gq/tw/index'));
|
||||
// router.get('/gq/tw/:caty?/:subcaty?', lazyloadRouteHandler('./routes/gq/tw/index'));
|
||||
|
||||
// 泉州市跨境电子商务协会
|
||||
router.get('/qzcea/:caty?', lazyloadRouteHandler('./routes/qzcea/index'));
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
ctx.params.caty = ctx.params.caty || '';
|
||||
ctx.params.subcaty = ctx.params.subcaty || '';
|
||||
|
||||
const rootUrl = 'https://www.gq.com.tw';
|
||||
const currentUrl = `${rootUrl}${ctx.params.caty === '' ? '' : '/' + ctx.params.caty}${ctx.params.subcaty === '' ? '' : '/' + ctx.params.subcaty}`;
|
||||
const response = await got({
|
||||
method: 'get',
|
||||
url: currentUrl,
|
||||
});
|
||||
|
||||
const $ = cheerio.load(response.data);
|
||||
|
||||
$('a[data-test-id="NavElement"]').remove();
|
||||
$('a[data-test-id="Link"]').remove();
|
||||
$('a[data-test-id="FooterLink"]').remove();
|
||||
|
||||
const list = $('a[data-test-id]')
|
||||
.slice(0, 10)
|
||||
.map((_, item) => {
|
||||
item = $(item);
|
||||
return {
|
||||
link: `${rootUrl}${item.attr('href')}`,
|
||||
};
|
||||
})
|
||||
.get();
|
||||
|
||||
const items = await Promise.all(
|
||||
list.map((item) =>
|
||||
ctx.cache.tryGet(item.link, async () => {
|
||||
const detailResponse = await got({
|
||||
method: 'get',
|
||||
url: item.link,
|
||||
});
|
||||
const content = cheerio.load(detailResponse.data);
|
||||
|
||||
item.title = content('h1').text();
|
||||
|
||||
const article = content('section[data-test-id="ArticleBodyContent"]').html();
|
||||
const gallery = content('section[data-test-id="GalleryImage"]').html();
|
||||
|
||||
if (ctx.params.caty === 'video') {
|
||||
item.description = content('div[data-test-id="EmbedIframe"]').html() + content('p[data-test-id="DekText"]').parent().html();
|
||||
item.pubDate = new Date(detailResponse.data.match(/pubDate":"(.*?)","channel/)[1]).toUTCString();
|
||||
} else if (gallery !== null) {
|
||||
item.description = gallery;
|
||||
item.pubDate = new Date(detailResponse.data.match(/pubDate":"(.*?)","items/)[1]).toUTCString();
|
||||
} else {
|
||||
item.description = article;
|
||||
item.pubDate = new Date(detailResponse.data.match(/pubDate":"(.*?)","publishedRevisions/)[1]).toUTCString();
|
||||
}
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
ctx.state.data = {
|
||||
title: `${$('title').eq(0).text()} - GQ Taiwan`,
|
||||
link: currentUrl,
|
||||
item: items,
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
'/tw/:caty?/:subcaty?': ['nczitzk'],
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
module.exports = {
|
||||
'gq.com.tw': {
|
||||
_name: 'GQ Taiwan',
|
||||
'.': [
|
||||
{
|
||||
title: 'GQ Taiwan',
|
||||
docs: 'https://docs.rsshub.app/new-media.html#gq',
|
||||
source: ['/*path'],
|
||||
target: '/gq/tw/:path',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,3 @@
|
||||
module.exports = (router) => {
|
||||
router.get('/tw/:caty?/:subcaty?', require('./tw/index'));
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
<a href="{{ url }}" target="_blank">{{ text }}</a>
|
||||
@@ -0,0 +1,4 @@
|
||||
{{@ img }}
|
||||
{{ productProps.dangerousHed }}<br>
|
||||
{{ if productProps.offerRetailer }}{{ productProps.offerRetailer }} {{ /if }}{{ if productProps.multipleOffers }}{{ productProps.multipleOffers[0].price }}{{ /if }}
|
||||
{{ if productProps.offerUrl }}<br><a href="{{ productProps.offerUrl }}" target="_blank">Buy It</a>{{ /if }}
|
||||
@@ -0,0 +1,4 @@
|
||||
<figure>
|
||||
<img src="{{ src }}"{{ if alt }} alt="{{@ alt }}"{{ /if }}>
|
||||
{{ if alt }}<figcaption>{{@ alt }}</figcaption>{{ /if }}
|
||||
</figure>
|
||||
@@ -0,0 +1,3 @@
|
||||
{{ if dangerousDek }}<div>{{@ dangerousDek }}</div>{{ /if }}
|
||||
{{ if lede }}{{@ lede }}{{ /if }}
|
||||
{{ if articleBody }}{{@ articleBody }}{{ /if }}
|
||||
@@ -0,0 +1,6 @@
|
||||
<video controls preload="none" poster="{{ poster }}">
|
||||
{{ each sources source }}
|
||||
<source src="{{ source.src }}" type="{{ source.contentType }}">
|
||||
{{ /each }}
|
||||
</video>
|
||||
{{@ articleBody }}
|
||||
@@ -0,0 +1,3 @@
|
||||
{{ if videoId }}
|
||||
<iframe id="ytplayer" type="text/html" width="640" height="360" src="https://www.youtube-nocookie.com/embed/{{ videoId }}" frameborder="0" allowfullscreen></iframe>
|
||||
{{ /if }}
|
||||
@@ -0,0 +1,165 @@
|
||||
const got = require('@/utils/got');
|
||||
const cheerio = require('cheerio');
|
||||
const { parseDate } = require('@/utils/parse-date');
|
||||
const md = require('markdown-it')({
|
||||
linkify: true,
|
||||
});
|
||||
const { art } = require('@/utils/render');
|
||||
const path = require('path');
|
||||
|
||||
const baseUrl = 'https://www.gq.com.tw';
|
||||
const parsePreloadedStateJSON = ($) =>
|
||||
JSON.parse(
|
||||
$('script[type="text/javascript"]')
|
||||
.text()
|
||||
.match(/window\.__PRELOADED_STATE__ = ({.*?});/)[1]
|
||||
);
|
||||
const largestImage = (sources, id) => {
|
||||
if (!id) {
|
||||
let maxWidth = 0;
|
||||
let maxUrl = '';
|
||||
Object.values(sources).forEach((size) => {
|
||||
if (size.width > maxWidth) {
|
||||
maxWidth = size.width;
|
||||
maxUrl = size.url;
|
||||
}
|
||||
});
|
||||
return maxUrl;
|
||||
}
|
||||
const url = sources[Object.keys(sources)[0]].url;
|
||||
const filename = url.substring(url.lastIndexOf('/') + 1);
|
||||
return `https://media.gq.com.tw/photos/${id}/${filename}`;
|
||||
};
|
||||
|
||||
module.exports = async (ctx) => {
|
||||
const { caty, subcaty } = ctx.params;
|
||||
const link = `${baseUrl}${caty ? `/${caty}` : ''}${subcaty ? `/${subcaty}` : ''}`;
|
||||
const { data: response } = await got(link);
|
||||
const $ = cheerio.load(response);
|
||||
const { transformed } = parsePreloadedStateJSON($);
|
||||
|
||||
const list = transformed.bundle.containers
|
||||
.filter((item) => item.items)
|
||||
.map((item) =>
|
||||
item.items.map((item) => ({
|
||||
title: item.source?.hed || item.dangerousHed,
|
||||
description: item.source?.dek || item.dangerousDek,
|
||||
link: (item.url.startsWith('http') ? item.url : `${baseUrl}${item.url}`).split('#intcid')[0],
|
||||
pubDate: parseDate(item.pubDate),
|
||||
author: item.contributors.author.items.map((item) => item.name).join(', '),
|
||||
}))
|
||||
)
|
||||
.flat();
|
||||
|
||||
const items = await Promise.all(
|
||||
list.map((item) =>
|
||||
ctx.cache.tryGet(item.link, async () => {
|
||||
const { data: response } = await got(item.link);
|
||||
const $ = cheerio.load(response);
|
||||
const data = JSON.parse($('script[type="application/ld+json"]').first().text());
|
||||
const { transformed } = parsePreloadedStateJSON($);
|
||||
const VideoObject = data['@type'] === 'VideoObject' ? true : false;
|
||||
const lede = !VideoObject ? transformed.article.headerProps.lede : null;
|
||||
|
||||
let articleBody = '';
|
||||
if (!VideoObject) {
|
||||
// typical article
|
||||
// articleBody inludes non standard markdown syntax
|
||||
articleBody = cheerio.load(md.render(data.articleBody.replace(/\{: target="_blank"\}/g, '')).replace(/\{: #link\}/g, ''), null, false);
|
||||
articleBody('a').each((_, item) => {
|
||||
item = $(item);
|
||||
if (item.text().startsWith('#video:')) {
|
||||
if (item.text().match(/youtube/)) {
|
||||
const videoId = item.text().match(/.*https:\/\/www\.youtube\.com\/embed\/(.*)\s/)[1];
|
||||
item.replaceWith(art(path.join(__dirname, '../templates/youtube.art'), { videoId }));
|
||||
}
|
||||
}
|
||||
if (item.text().startsWith('![#image:')) {
|
||||
const imageId = item.text().match(/!\[#image: \/photos\/(.*?)\]/)[1];
|
||||
const imgInfo = transformed.article.lightboxImages.find((item) => item.id === imageId);
|
||||
item.html(
|
||||
art(path.join(__dirname, '../templates/img.art'), {
|
||||
src: largestImage(imgInfo.sources, imageId),
|
||||
alt: imgInfo.dangerousCaption,
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
articleBody('p').each((_, item) => {
|
||||
item = $(item);
|
||||
if (item.text().startsWith('+++')) {
|
||||
item.remove();
|
||||
}
|
||||
if (item.text().startsWith('[#image:')) {
|
||||
const imageId = item.text().match(/\[#image: \/photos\/(.*?)\]/)[1];
|
||||
const imgInfo = transformed.article.lightboxImages.find((item) => item.id === imageId);
|
||||
item.replaceWith(
|
||||
art(path.join(__dirname, '../templates/img.art'), {
|
||||
src: largestImage(imgInfo.sources, imageId),
|
||||
alt: imgInfo.dangerousCaption,
|
||||
})
|
||||
);
|
||||
}
|
||||
if (item.text().startsWith('[#article:')) {
|
||||
const articleId = item.text().match(/\[#article: \/articles\/(.*?)\]/)[1];
|
||||
const articleProps = transformed.article.body.filter((i) => i[0] === 'inline-embed').find((i) => i[1].ref === articleId)[1].props;
|
||||
item.replaceWith(
|
||||
art(path.join(__dirname, '../templates/embed-article.art'), {
|
||||
url: `${baseUrl}${articleProps.url}`,
|
||||
text: articleProps.dangerousHed,
|
||||
})
|
||||
);
|
||||
}
|
||||
if (item.text().startsWith('[#product:')) {
|
||||
const productId = item.text().match(/\[#product: \/products\/(.*?)\]/)[1];
|
||||
const productProps = transformed.article.body.filter((i) => i[0] === 'inline-embed').find((i) => i[1].ref === productId)[1].props;
|
||||
item.replaceWith(
|
||||
art(path.join(__dirname, '../templates/embed-product.art'), {
|
||||
img: art(path.join(__dirname, '../templates/img.art'), {
|
||||
src: largestImage(productProps.image.sources),
|
||||
}),
|
||||
productProps,
|
||||
})
|
||||
);
|
||||
}
|
||||
if (item.text().startsWith('[#instagram:')) {
|
||||
const instagramHref = item.text().match(/\[#instagram: (.*?)\]/)[1];
|
||||
item.replaceWith(
|
||||
art(path.join(__dirname, '../templates/embed-article.art'), {
|
||||
url: instagramHref,
|
||||
text: instagramHref,
|
||||
})
|
||||
);
|
||||
}
|
||||
});
|
||||
item.description = art(path.join(__dirname, '../templates/tw.art'), {
|
||||
dangerousDek: transformed.article.headerProps.dangerousDek, // quote
|
||||
lede: art(path.join(__dirname, '../templates/img.art'), {
|
||||
// header image
|
||||
src: largestImage(lede.sources, lede.id),
|
||||
alt: lede.caption,
|
||||
}),
|
||||
articleBody: articleBody.html(),
|
||||
});
|
||||
} else {
|
||||
// is VideoObject
|
||||
item.description = art(path.join(__dirname, '../templates/videoObject.art'), {
|
||||
poster: transformed.video.metaImageUrl,
|
||||
sources: transformed.video.sources,
|
||||
articleBody: data.description,
|
||||
});
|
||||
}
|
||||
|
||||
return item;
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
ctx.state.data = {
|
||||
title: `${transformed.coreDataLayer.content.contentTitle} | ${transformed.coreDataLayer.content.brand}`,
|
||||
link,
|
||||
image: `${baseUrl}${transformed.logo.sources.sm.url}`,
|
||||
item: items,
|
||||
allowEmpty: true,
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user