feat: 纽约时报添加英文原版及中英对照版 (#1657)

close #1609
This commit is contained in:
Henry Wang 2019-03-04 11:00:24 +00:00 committed by DIYgod
parent 7a89b9de5f
commit fac1541ae6
5 changed files with 150 additions and 50 deletions

View File

@ -2049,16 +2049,14 @@ Category 列表:
### 纽约时报
<route name="全球纵览" author="HenryQW" example="/nytimes" path="/nytimes/index">
::: tip 提示
由于众所周知的原因,文章内的图片在中国大陆可能无法正常显示。
:::
<route name="官方 RSS" author="HenryQW" example="/nytimes/dual" path="/nytimes/index/:lang?" :paramsDesc="['语言, 缺省中文']">
通过提取文章全文,以提供比官方源更佳的阅读体验。
| 默认中文 | 中英对照 | 英文 |
| -------- | -------- | ---- |
| (空) | dual | en |
</route>
<route name="每日简报" author="xyqfer" example="/nytimes/morning_post" path="/nytimes/morning_post"/>
@ -2099,12 +2097,6 @@ Category 列表:
<route name="BBC" author="HenryQW" example="/bbc/chinese" path="/bbc/:channel?" :paramsDesc="['频道, 缺省为热门']">
::: tip 提示
由于众所周知的原因, 文章内的图片在中国大陆可能无法正常显示.
:::
通过提取文章全文, 以提供比官方源更佳的阅读体验.
支持大部分频道, 频道名称见[官方频道 RSS](https://www.bbc.co.uk/news/10628494).
@ -2123,7 +2115,6 @@ Category 列表:
- 不支持付费文章.
- 由于未知原因 FT 中文网的 SSL 证书不被信任 (参见[SSL Labs 报告](https://www.ssllabs.com/ssltest/analyze.html?d=www.ftchinese.com&latest)), 所有文章通过 http 协议获取.
- 由于众所周知的原因, 文章内的图片在中国大陆可能无法正常显示.
:::
@ -2138,12 +2129,6 @@ Category 列表:
### 卫报 The Guardian
::: tip 提示
由于众所周知的原因,文章内的图片在中国大陆可能无法正常显示。
:::
通过提取文章全文,以提供比官方源更佳的阅读体验。
<route name="Editorial" author="HenryQW" example="/guardian/editorial" path="/guardian/editorial"/>

View File

@ -345,7 +345,7 @@ router.get('/yande.re/post/popular_recent', require('./routes/yande.re/post_popu
router.get('/yande.re/post/popular_recent/:period', require('./routes/yande.re/post_popular_recent'));
// 纽约时报
router.get('/nytimes', require('./routes/nytimes/index'));
router.get('/nytimes/:lang?', require('./routes/nytimes/index'));
router.get('/nytimes/morning_post', require('./routes/nytimes/morning_post'));
// 3dm

View File

@ -1,34 +1,100 @@
const axios = require('../../utils/axios');
const utils = require('./utils');
const cheerio = require('cheerio');
const Parser = require('rss-parser');
const parser = new Parser();
module.exports = async (ctx) => {
let { lang = '' } = ctx.params;
lang = lang.toLowerCase();
let title = '纽约时报中文网';
if (lang === 'dual') {
title += ' - 中英对照版';
} else if (lang === 'en') {
title += ' - 英文原版';
}
const feed = await parser.parseURL('https://cn.nytimes.com/rss/');
const items = await Promise.all(
feed.items.splice(0, 10).map(async (item) => {
const response = await axios({
method: 'get',
url: item.link,
});
let link = item.link;
const description = utils.ProcessFeed(response.data);
let response,
hasEnVersion = false,
dual = false;
if (lang === 'dual') {
link = link.replace('/?utm_source=RSS', '') + '/dual';
try {
response = await ctx.cache.tryGet(`nyt: ${link}`, async () => {
const response = await axios.get(link);
return response.data;
});
dual = true;
} catch (error) {
response = await ctx.cache.tryGet(`nyt: ${item.link}`, async () => {
const response = await axios.get(item.link);
return response.data;
});
}
} else {
response = await ctx.cache.tryGet(`nyt: ${item.link}`, async () => {
const response = await axios.get(item.link);
return response.data;
});
if (lang === 'en') {
const $ = cheerio.load(response);
if ($('.dual-btn').length > 0) {
hasEnVersion = true;
link = $('.dual-btn a')
.last()
.attr().href;
response = await ctx.cache.tryGet(`nyt: ${link}`, async () => {
const response = await axios.get(link);
return response.data;
});
}
}
}
const single = {
title: item.title,
description,
pubDate: item.pubDate,
link: item.link,
link,
author: item['dc:creator'],
};
const result = utils.ProcessFeed(response, hasEnVersion);
single.description = result.description;
if (hasEnVersion) {
single.title = result.title;
single.author = result.author;
}
if (dual) {
single.title = `「中英」${single.title}`;
}
return Promise.resolve(single);
})
);
ctx.state.data = {
title: '纽约时报中文网 国际纵览',
title,
link: 'https://cn.nytimes.com',
description: '纽约时报中文网 国际纵览',
description: title,
item: items,
};
};

View File

@ -26,10 +26,7 @@ module.exports = async (ctx) => {
post.map(async (item) => {
const link = item.link;
const description = await ctx.cache.tryGet(`nyt: ${link}`, async () => {
const response = await axios({
method: 'get',
url: link,
});
const response = await axios.get(link);
return utils.ProcessFeed(response.data);
});

View File

@ -1,27 +1,79 @@
const cheerio = require('cheerio');
const ProcessFeed = (data) => {
const ProcessImage = ($, e) => {
const photo = $(e).find('figure');
let cover = `<figure><img src='${photo[0].attribs.itemid}'><br><figcaption>`;
const caption = $(e).find('figcaption');
cover += `${$(caption[0])
.text()
.trim()}</figcaption></figure>`;
return cover;
};
const ProcessFeed = (data, hasEnVersion = false) => {
const $ = cheerio.load(data);
const content = $('section.article-body');
// remove useless DOMs
content.find('div.big_ad, div.article-body-aside').each((i, e) => {
$(e).remove();
});
let content;
const result = {};
if ($('figure.article-span-photo').length > 0) {
// there is a cover photo
const cover = $('figure.article-span-photo');
$(cover).insertBefore(content[0].firstChild);
// 处理 www.nytimes.com
if (hasEnVersion) {
content = $('section[name="articleBody"]');
result.title = `「英」${$('h1')
.text()
.trim()}`;
result.author = $('article#story span[itemprop="name"]').text();
// 处理封面图片
$('article#story > header')
.find('div[data-testid="photoviewer-wrapper"]')
.each((i, e) => {
const cover = ProcessImage($, e);
$(cover).insertBefore(content[0].firstChild);
});
// 处理图片
content.find('div[data-testid="photoviewer-wrapper"]').each((i, e) => {
const cover = ProcessImage($, e);
$(cover).insertBefore(e);
$(e).remove();
});
// remove useless DOMs
content.find('aside').each((i, e) => {
$(e).remove();
});
}
// 处理 cn.nytimes.com
else {
content = $('section.article-body');
// remove useless DOMs
content.find('div.big_ad, div.article-body-aside').each((i, e) => {
$(e).remove();
});
if ($('figure.article-span-photo').length > 0) {
// there is a cover photo
const cover = $('figure.article-span-photo');
$(cover).insertBefore(content[0].firstChild);
}
if ($('footer.author-info').length > 0) {
// credit to original author and translators
const footer = $('footer.author-info');
$(footer).insertAfter(content[0].lastChild);
}
}
if ($('footer.author-info').length > 0) {
// credit to original author and translators
const footer = $('footer.author-info');
$(footer).insertAfter(content[0].lastChild);
}
result.description = content.html();
return content.html();
return result;
};
module.exports = {