diff --git a/docs/new-media.md b/docs/new-media.md index 5104b2b68a..c9ecc8b7c1 100644 --- a/docs/new-media.md +++ b/docs/new-media.md @@ -2980,7 +2980,7 @@ column 为 third 时可选的 category: ### 公众号(Telegram 频道来源) - + ::: warning 注意 diff --git a/lib/router.js b/lib/router.js index 774a2b8ebc..a49e1decb4 100644 --- a/lib/router.js +++ b/lib/router.js @@ -512,7 +512,7 @@ router.get('/wechat/csm/:id', lazyloadRouteHandler('./routes/tencent/wechat/csm' router.get('/wechat/ce/:id', lazyloadRouteHandler('./routes/tencent/wechat/ce')); router.get('/wechat/announce', lazyloadRouteHandler('./routes/tencent/wechat/announce')); router.get('/wechat/miniprogram/plugins', lazyloadRouteHandler('./routes/tencent/wechat/miniprogram/plugins')); -router.get('/wechat/tgchannel/:id', lazyloadRouteHandler('./routes/tencent/wechat/tgchannel')); +router.get('/wechat/tgchannel/:id/:mpName?', lazyloadRouteHandler('./routes/tencent/wechat/tgchannel')); router.get('/wechat/uread/:userid', lazyloadRouteHandler('./routes/tencent/wechat/uread')); router.get('/wechat/ershicimi/:id', lazyloadRouteHandler('./routes/tencent/wechat/ershcimi')); router.get('/wechat/wjdn/:id', lazyloadRouteHandler('./routes/tencent/wechat/wjdn')); diff --git a/lib/routes/tencent/wechat/tgchannel.js b/lib/routes/tencent/wechat/tgchannel.js index 05041caec5..6130b8e721 100644 --- a/lib/routes/tencent/wechat/tgchannel.js +++ b/lib/routes/tencent/wechat/tgchannel.js @@ -3,26 +3,62 @@ const cheerio = require('cheerio'); module.exports = async (ctx) => { const id = ctx.params.id; + const mpName = ctx.params.mpName ?? ''; const { data } = await got.get(`https://t.me/s/${id}`); const $ = cheerio.load(data); - const list = $('.tgme_widget_message_wrap').slice(-10); + const list = $('.tgme_widget_message_wrap').slice(-20); const out = await Promise.all( list .map(async (index, item) => { item = $(item); - let author; - let title = item.find('.tgme_widget_message_text > a:nth-child(5)').text() || item.find('.tgme_widget_message_text > a:nth-child(2)').text(); + // [ div.tgme_widget_message_text 格式简略说明 ] + // 若频道只订阅一个公众号: + // 第 1 个元素: ${emoji(链接)} + // 第 2 个元素: ${文章标题} + // (余下是文章简介,一般是裸文本,这里用不到) + // + // 若频道订阅多于一个公众号: + // 第 1 个元素: ${emoji(标注消息来源于什么 slave,这里是表示微信的对话气泡)} + // 第 2 个元素: ${emoji(标注对话类型,这里是表示私聊的半身人像) + // 裸文本: (半角空格)${公众号名}(半角冒号) + // 第 3 个元素:
+ // 第 4 个元素: ${emoji(链接)} + // 第 5 个元素: ${文章标题} + // (余下是文章简介,一般是裸文本,这里用不到) - const all_text = item.find('.tgme_widget_message_text').text(); - if (all_text.indexOf(':') !== -1) { - author = all_text.split(':')[0].split(' ')[1]; - title = author + ': ' + title; + const title_elem = item.find('.tgme_widget_message_text > a:nth-of-type(2)'); // 第二个 a 元素会是文章链接 + + if (title_elem.length === 0) { + // 获取不到第二个 a 元素,这可能是公众号发的服务消息,丢弃它 + return; + } + + let author; + let title = title_elem.text(); + const link = title_elem.attr('href'); + + const br_node = item.find('.tgme_widget_message_text > br:nth-of-type(1)').get(0); // 获取第一个换行 + const author_node = br_node && br_node.prev; // br_node 不为 undefined 时获取它的前一个节点 + if (author_node && author_node.type === 'text') { + // 只有这个节点是一个裸文本时它才可能是公众号名 + const spaceIndex = author_node.data.indexOf(' '); + const colonIndex = author_node.data.indexOf(':'); + if (spaceIndex !== -1 && colonIndex !== -1) { + // 找到了公众号名,说明这个频道订阅了多个公众号 + author = author_node.data.slice(spaceIndex + 1, colonIndex); // 提取作者 + if (mpName && author !== mpName) { + // 指定了要筛选的公众号名,且该文章不是该公众号发的 + return; // 丢弃 + } else if (!mpName) { + // 没有指定要筛选的公众号名 + title = author + ': ' + title; // 给标题里加上获取到的作者 + } + } } - const link = item.find('.tgme_widget_message_text > a:nth-child(5)').attr('href') || item.find('.tgme_widget_message_text > a:nth-child(2)').attr('href'); const pubDate = new Date(item.find('.tgme_widget_message_date time').attr('datetime')).toUTCString(); const single = { @@ -51,15 +87,16 @@ module.exports = async (ctx) => { } } - return Promise.resolve(single); + return single; }) .get() ); out.reverse(); ctx.state.data = { - title: $('.tgme_channel_info_header_title').text(), + title: mpName ?? $('.tgme_channel_info_header_title').text(), link: `https://t.me/s/${id}`, - item: out, + item: out.filter((item) => item), + allowEmpty: !!mpName, }; };