diff --git a/docs/social-media.md b/docs/social-media.md
index a05e0afd6f..aea3df10d6 100644
--- a/docs/social-media.md
+++ b/docs/social-media.md
@@ -1131,7 +1131,7 @@ rule
对于微博内容,在 `routeParams` 参数中以 query string 格式指定选项,可以控制输出的样式
| 键 | 含义 | 接受的值 | 默认值 |
-| -------------------------- | --------------------------------- | -------------- | ------------------------------- |
+|----------------------------|-----------------------------------|----------------|---------------------------------|
| readable | 是否开启细节排版可读性优化 | 0/1/true/false | false |
| authorNameBold | 是否加粗作者名字 | 0/1/true/false | false |
| showAuthorInTitle | 是否在标题处显示作者 | 0/1/true/false | false(`/weibo/keyword/`中为 true) |
@@ -1144,7 +1144,8 @@ rule
| widthOfPics | 微博配图宽(生效取决于阅读器) | 不指定 / 数字 | 不指定 |
| heightOfPics | 微博配图高(生效取决于阅读器) | 不指定 / 数字 | 不指定 |
| sizeOfAuthorAvatar | 作者头像大小 | 数字 | 48 |
-| displayVideo | 是否直接显示微博视频,只在博主 RSS 中有效 | 0/1/true/false | true |
+| displayVideo | 是否直接显示微博视频,只在博主或个人时间线 RSS 中有效 | 0/1/true/false | true |
+| displayArticle | 是否直接显示微博文章,只在博主或个人时间线 RSS 中有效 | 0/1/true/false | false |
| showEmojiInDescription | 是否展示正文中的 emoji 表情 | 0/1/true/false | true |
指定更多与默认值不同的参数选项可以改善 RSS 的可读性,如
diff --git a/lib/routes/weibo/timeline.js b/lib/routes/weibo/timeline.js
index d753d4ebbf..cf9b8deaba 100644
--- a/lib/routes/weibo/timeline.js
+++ b/lib/routes/weibo/timeline.js
@@ -11,12 +11,14 @@ module.exports = async (ctx) => {
const routeParams = ctx.params.routeParams || undefined;
const token = await ctx.cache.get('weibotimelineuid' + uid, false);
let displayVideo = '1';
+ let displayArticle = '0';
if (routeParams) {
if (routeParams === '1' || routeParams === '0') {
displayVideo = routeParams;
} else {
const routeParams = querystring.parse(ctx.params.routeParams);
displayVideo = fallback(undefined, queryToBoolean(routeParams.displayVideo), true) ? '1' : '0';
+ displayArticle = fallback(undefined, queryToBoolean(routeParams.displayArticle), false) ? '1' : '0';
}
}
@@ -79,6 +81,11 @@ module.exports = async (ctx) => {
description = weiboUtils.formatVideo(description, item);
}
+ // 文章的处理
+ if (displayArticle === '1') {
+ description = await weiboUtils.formatArticle(ctx, description, item);
+ }
+
return {
title,
description,
diff --git a/lib/routes/weibo/user.js b/lib/routes/weibo/user.js
index d0ab6356d7..506f50905b 100644
--- a/lib/routes/weibo/user.js
+++ b/lib/routes/weibo/user.js
@@ -8,12 +8,14 @@ const { fallback, queryToBoolean } = require('@/utils/readable-social');
module.exports = async (ctx) => {
const uid = ctx.params.uid;
let displayVideo = '1';
+ let displayArticle = '0';
if (ctx.params.routeParams) {
if (ctx.params.routeParams === '1' || ctx.params.routeParams === '0') {
displayVideo = ctx.params.routeParams;
} else {
const routeParams = querystring.parse(ctx.params.routeParams);
displayVideo = fallback(undefined, queryToBoolean(routeParams.displayVideo), true) ? '1' : '0';
+ displayArticle = fallback(undefined, queryToBoolean(routeParams.displayArticle), false) ? '1' : '0';
}
}
@@ -101,6 +103,11 @@ module.exports = async (ctx) => {
description = weiboUtils.formatVideo(description, item.mblog);
}
+ // 文章的处理
+ if (displayArticle === '1') {
+ description = await weiboUtils.formatArticle(ctx, description, item.mblog);
+ }
+
return {
title,
description,
diff --git a/lib/routes/weibo/utils.js b/lib/routes/weibo/utils.js
index 8d748816d2..15d9b140f4 100644
--- a/lib/routes/weibo/utils.js
+++ b/lib/routes/weibo/utils.js
@@ -1,5 +1,6 @@
const querystring = require('querystring');
const got = require('@/utils/got');
+const cheerio = require('cheerio');
const { fallback, queryToBoolean, queryToInteger } = require('@/utils/readable-social');
const weiboUtils = {
@@ -260,6 +261,92 @@ const weiboUtils = {
}
return itemDesc;
},
+ formatArticle: async (ctx, itemDesc, status) => {
+ const pageInfo = status.page_info;
+ if (pageInfo && pageInfo.type === 'article' && pageInfo.page_url) {
+ const pageUrl = pageInfo.page_url;
+ const articleIdMatch = pageUrl.match(/id=(\d+)/);
+ if (!articleIdMatch) {
+ return itemDesc;
+ }
+ const articleId = articleIdMatch[1];
+ const link = `https://card.weibo.com/article/m/aj/detail?id=${articleId}`;
+ const response = await ctx.cache.tryGet(link, async () => {
+ const _response = await got.get(link, {
+ headers: {
+ Referer: `https://card.weibo.com/article/m/show/id/${articleId}`,
+ 'MWeibo-Pwa': 1,
+ 'X-Requested-With': 'XMLHttpRequest',
+ 'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
+ },
+ });
+ return _response.data;
+ }); // cache it!
+ const article = response.data;
+ if (article && article.title && article.content) {
+ const title = article.title;
+ const content = article.content;
+ const summary = article.summary;
+ const createAt = article.create_at;
+ const readCount = article.read_count;
+ const isOriginal = article.is_original;
+ const isArticleNonFree = article.is_article_free; // 微博起错了字段名,它为 1 时才是收费文章
+
+ let html = '
';
+ html += '
'; + if (isArticleNonFree) { + articleMeta += `试读 `; + } + if (isOriginal) { + articleMeta += `原创 `; + } + articleMeta += `发布时间: ${createAt} `; // 发布时间 + articleMeta += `阅读量: ${readCount} `; // 阅读量 + articleMeta += '
'; + html += articleMeta; + + if (summary) { + html += `${summary}
`; // 摘要 + } + + html += ''; // 分割线 + + // 正文处理,加入一些在微博文章页的 CSS 中定义的不可或缺的样式 + const $ = cheerio.load(content); + $('p').each((_, elem) => { + elem = $(elem); + let style = elem.attr('style') || ''; + style = 'margin: 0;padding: 0;border: 0;' + style; + elem.attr('style', style); + }); + $('.image').each((_, elem) => { + elem = $(elem); + let style = elem.attr('style') || ''; + style = 'display: table;text-align: center;margin-left: auto;margin-right: auto;clear: both;min-width: 50px;' + style; + elem.attr('style', style); + }); + $('img').each((_, elem) => { + elem = $(elem); + let style = elem.attr('style') || ''; + style = 'display: block;max-width: 100%;margin-left: auto;margin-right: auto;min-width: 50px;' + style; + elem.attr('style', style); + }); + const contentHtml = $.html(); + html += `