作为一名lsp,时刻与在pixiv上关注画师的更新保持同步不失为一种重要的生活习惯。
但总觉得每天手动检查新图既费时又费力,有没有什么方便一些的方法来推送这些喜欢的图片,让每一张图都有机会展现它的光彩呢?
联想到一种常用的资讯订阅方式:RSS,我正好在RSSHub的文档中翻到了对于pixiv关注画师的新图的订阅接口。
但光是RSS订阅并不方便,还需要一个单独的阅读器,不如直接将这些资讯推送至通讯工具上吧。
之前,我使用的基于IFTTT的解决方案,简单地将RSSHub生成的内容推送至Telegram频道。但随着IFTTT的使用策略更改,非付费用户只能创建三个小程序(Applet)之后,我也就放弃了这个方案。毕竟是开发者,被商业平台束缚了手脚可不好,不如自己来写一个功能类似的处理工具,不但能锻炼代码能力,还能拥有更高的可自定义能力,岂不是更棒。
于是,就去查询各种API接口,整理资料。思路很简单:将数据通过RSS采集,整理之后通过Bot的API接口发送至Telegram频道。
又因为我习惯使用Node.JS进行开发,所以这一次也一样,使用Node.JS作为开发与部署平台。
第一步:RSS采集
首先是RSS的采集工作。为了避免费时费力的手动分析XML文件,这里直接使用了一个现成的组件:rss-parser
。这个组件能获取RSS资讯,并转化成一个Object方便后续的处理工作。
npm i rss-parser --save
自不用说,使用完成之后的传参调用方式也是非常简洁明快:
1 | rss.parseURL(item.url, (err, feed) => { |
也可以使用官方样例中的async与await异步函数处理方式,但是我比较懒,所以也就直接这样传递参数了吧。
测试时可以将获取的feed信息输出,以RSShub生成的数据为例,我们不难发现其实内部是一个对象数组:
1 | { |
因而可以直接使用相关的字段进行内容处理。
第二步:数据处理
由于RSSHub设计的初衷是为了方便阅读,因而生成的内容格式还是以方便阅读的格式,并使用了pixiv.cat的图片传递接口为主要组成部分的。不过好在获取的内容中包含了我们需要的所有信息,因而可以使用一个正则表达式来提取。
不难发现,对于那些单张图片的内容,RSSHub将其处理成形如https://pixiv.cat/*ArtworkID*.jpg
的链接;pixiv的ArtworkID目前也仅为数字,因而可以使用\d
来匹配;而对于那些多图的内容而言,ArtworkID后的-PicID
也是我们关注的关键。因而,我们可以使用这样的正则表达式来处理:
1 | const picIdReg = /https:\/\/pixiv\.cat\/(\d+)-?(\d+)?\.(jpg|png|gif)/gi; |
可以配合这条正则表达式,直接生成内容数组:
1 | const artworks = [...item.content.matchAll(picIdReg)]; |
对于单图的输入,我们能得到形如这样的输出:
1 | > Array ["https://pixiv.cat/*ArtworkID*.jpg", "*ArtworkID*", undefined, "jpg"] |
对于多图的输入,我们能得到形如这样的输出:
1 | > Array ["https://pixiv.cat/*ArtworkID*-1.jpg", "*ArtworkID*", "1", "jpg"] |
考虑到Telegram对于图片大小的限制,选择使用预览图发送、使用完整图下载的方案。
通过查看pixiv前端页面的源码,不难发现预览图的地址是由前缀、发布时间(UTC+9)、作品ID和一些固定组合搭配而成。发布时间可以由RSS item中的isoDate来手动计算获取,我们可以写一个整合表达式来完成预览图地址的装配工作:
1 | const pubTime = new Date(item.isoDate); |
pic表示一个Array(如样例中的一行);为了整合处理单图的情况,针对pic[2]
进行了额外的处理与判定:pixiv的预览图以0开始编码,单图也会保留此编码内容。
因而最终我们能组合出所需要的预览图片地址。至于下载地址,交给pixiv.cat去处理即可。
第三步:消息发送
之前IFTTT时候使用的是直接推送订阅内容、让Telegram自动获取的方式,因而导致了大图片(≥5MB)无法有效获取、图片缓存请求限制等的问题,因而此次我们加入请求缓冲队列和预览图片,尝试解决以上的问题。
本来打算使用Telegraf作为推送框架,但是想了想发现好像也就一个请求信息,所以就直接使用了got进行POST请求的发送。根据Telegram的Bot API文档,可以整理出如下的请求样式:
1 | const apiBaseUrl = `https://api.telegram.org/bot${confData.bot.token}`; |
直接调用了Telegram的sendPhoto发送图片接口来发送请求数据,其中加入了消息下的内联小键盘inline_keyboard
,为提供图片的原始链接按钮和直接下载按钮,以方便用户的操作。如有其他的好想法,也可制作成相关的功能组件。Bot API Token可以向@BotFather申请,Chat ID可以使用@频道名
,而不必纠结于一长串的频道ID。
为了避免每次启动会将所有的图片加入队列等待发送,同时考虑到这个项目提供的所有数据都是按照时间进行排序的,因而维护一个timestamp,初始化为当前时间,每次将待发送的图片时间中记录最晚值,之后查询时仅发送更新的内容并更新时间戳标记即可。
第四步:部署
为了进一步为用户提供方便,依旧加入了祖传的js-yaml组件来读取yml配置文件。并综合以上内容,最终整合的版本,已经发布到了Github上的PhanDream仓库中;您可以使用诸如pm2等方式进行运行:
1 | pm2 start bot.js --name phandream |
当一切准备完成后,过一会就能发现频道中出现新的图片啦~