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 += '
'; + + html += `

${title}

`; // 加入标题 + + // 加入文章信息 + const iconStyle = + 'display: inline-block;margin-inline: 0.25rem;width: 2.25rem; height: 1.125rem; background: #e7e7e7; border-radius: 2px; box-sizing: border-box; text-align: center; line-height: 1.0625rem; font-size: 0.75rem; color: #aaa;'; + let articleMeta = '

'; + 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 += `
${contentHtml}
`; // 正文 + + html += '
'; + itemDesc += html; + } + } + return itemDesc; + }, }; module.exports = weiboUtils;