English | Github

Background

对于大多数 ACG 爱好者来说,在网络上收集各种画师作品、壁纸、宣传图、插画等图片想必是一件乐此不疲的事情;然而近年来图片来源不断丰富,已从最原始的 Pixiv、Danbooru、Moebooru 类图站扩展至 Twitter、Telegram Channel、QQ 群,乃至酷安酷图(?)、网易云音乐动态(??),高效的多渠道自动收图工作流已成为必需。

此外,如何在多渠道来源中获取高质量的原始数据,如何管理和安全保存数据也至关重要。例如下图,Pixiv 上删除作品的情况已不再是少数,虽说仍可通过其他手段恢复,但恢复数据的成本显然高于即时归档的成本。数据丢失对于收集控来说是无法忍受的痛苦,所以去中心化刻不容缓(

Pixiv 收藏夹中被删除的图片

Introduction

小さな小さな賢将,是一个能从多种来源收集 ACG 相关插画并完成自动化工作流的 Telegram 机器人。

(名字并不是 TYPO,只是为了避免重名)

其实这个项目 1 月份就在做了但咕到现在才写文章

Features

  • 获取多种来源的图片
  • 从支持的网站下载原图
  • 将图片添加到收藏,完成自动化工作流
  • 将图片保存在 Telegram Channel 中
  • 将图片文件上传到 MEGA 云盘、Google Drive 或保存在本地
  • 将图片的元信息(如名称、标签)保存至多种类型的数据库

Supported Sites

名称 URL Bot 命令 图片收藏功能
Pixiv https://www.pixiv.net/
Danbooru https://danbooru.donmai.us/
Safebooru https://safebooru.donmai.us/
yandere https://yande.re/
Konachan https://konachan.com/
Lolibooru https://lolibooru.moe/
Zerochan https://www.zerochan.net/
Gelbooru https://gelbooru.com/
Twitter https://twitter.com/
Bilibili 动态 https://t.bilibili.com/

Before

  • Pixiv:收藏 & 定期使用工具批量下载收藏夹
  • Danbooru & Moebooru 类图站:分别注册账号并收藏 / 直接添加书签
  • Twitter:转推 / 直接下载 / 添加书签
  • Telegram Channel:转发至私人频道

After

以上所有来源均分享 / 转发至 Telegram Bot,Bot 在云端完成以下工作:

  • 将原消息转发至 Gallery Channel 以便后续查看
  • 在来源站收藏图片(仅 Pixiv)
  • 下载“原图”,即能够获取到的最高分辨率文件
  • 将原图以文件形式发送至 Album Channel 作为备份点之一
  • 上传原图文件至 MEGA 云盘

PS: 对于其他来源的图片如已知原始地址仍可按上述方法操作,搜图功能仍在计划中

Architecture

Architecture

Telegram

项目初期设想用 Electron 构建 UI 界面,用 Python 运行后端服务器,藉此学习 Electron 和 Python 的使用,然而此架构在通讯和程序启动方面都存在一定不足;考虑到 Telegram 已成为收图的重要来源之一,且官方提供了丰富的 API 以供使用,故使用 Telegram Bot 功能、将聊天界面作为 UI 使用。

此外,Telegram 还提供了云端永久存储及多端同步功能,可作为原始文件的备份点之一。

Why Telegram

Heroku

Heroku Dynos

由于手上并没有现成的服务器,对于如此轻量的应用来说单独购买一台 VPS 又太过奢侈,于是几年前白嫖的 Heroku 平台便派上了用场。

Heroku 是基于容器的 PaaS 平台,在本地使用 Git 推送源码后,在云端完成构建,最终运行在一个轻量级的容器(Dyno)中。对于免费账户,Dyno 在闲置 30 分钟后会自动休眠,但受到网络请求后会自动启动,以节省资源。由于使用了 Webhook,这一特性对于本项目来说并无大碍;免费账户每个月 550 小时的运行时间也是绰绰有余。

MEGA

MEGA 安全性

人人的隐私与家庭、住宅、通信不得被任意干涉……。 人人有权享受法律保护,不受这种干涉或攻击……。

世界人权宣言第十二条

图片收藏工作流中重要的一环便是文件的归档存储,云端备份需要一定的稳定性和存储空间,此外还有安全性等多方面因素。MEGA 作为一家主打安全性的公司,采用了端对端加密设计,提供 15GB 的免费存储空间,官方虽没有提供 Python SDK,但有开源库可用。

Firebase

由于 Dyno 的自动休眠机制及 PixivPy 的自身设计,Pixiv API 无法保持登录状态,一段时间后使用机器人时都会重新登录,然而 Pixiv 的异地登录邮件提醒并不能关闭,一个月内将会产生几十封垃圾邮件;此外,Pixiv 的 Access Token 有效期仅为 1 小时,若 Bot 运行时间过长则登录凭据失效无法正常工作。

Pixiv 使用的是 RESTful API,为解决这些问题需要保存 Access Token 及 Refresh Token,然而 Heroku Dyno 的 Ephemeral filesystem 直接否决了本地数据库的方案。鉴于 Heroku 自身的数据库服务存在诸多限制,转而使用 Firebase——Google 的 BaaS 服务。

Cloud Firestore 是 Firebase 平台中的云托管 NoSQL 数据库服务,以集合-文档的结构存储数据,免费方案数据总量限制为 1GB,每日读取及写入次数限制均在 1 万次以上,完全满足需求。

连接了 Firebase 以后便可将 Pixiv 的登录凭据缓存到 Firestore 数据库中,省去了登录时间,如 Access Token 过期则使用 Refresh Token 进行更新;针对 MEGA 网盘每次登录及查找文件夹耗时过长的问题,同样使用此方法进行解决。粗略估算,此次优化过后 Bot 的冷启动响应时间可降低至原来的一半左右。

Firestore Cache

Deploy

Deploy on Heroku

  1. 使用 ‘Deploy to Heroku’ 按钮:Deploy to Heroku
  2. 手动部署:
    根据根目录下和 sites 目录下各来源站点的 config.py 文件,在 Heroku 后台设置所需的环境变量,克隆 Git 仓库 并 push 到 Heroku 即可开始使用,关于 Heroku 的使用见 官方文档

Deploy on your own server

Tips: 安装之前可在 requirements.txt 中注释掉不用的依赖

  1. 安装所有依赖:pip install -r requirements.txt
  2. 设置所需的环境变量,或手动修改 config.py
  3. 启动:python bot.py

Configuration

  • ENV

    默认为 production,使用 Webhook;开发环境可设置为 production 以使用轮询模式

  • TOKEN

    Telegram Bot 的 API token,可通过 @BotFather 获取

  • WEBHOOK_URL

    提交给 Telegram 服务器的 Webhook URL,详见 python-telegram-bot 的文档

  • PORT

    Webhook 端口,如果部署在 Heroku 上则无需手动设置

  • STORAGE

    字符串,由 eval 转换为 list

    使用的存储方式,默认为 [],即仅使用 DOWNLOAD_DIR 作为本地存储。设置为 ['Mega'] 以使用 MEGA。

    可通过在 storage 下创建一个文件来实现其他存储方式,文件中的对象必须有一个名为 store 的成员函数。

  • DOWNLOAD_DIR

    本地目录,用于存放下载的原图,如果不存在将自动创建

  • STORAGE_DIR

    归档存储目录,如 MEGA 云盘的远程目录,原图将被存储到这里,如果不存在将自动创建

  • ALBUM_ID

    用于存放原图文件的 Telegram Channel ID

  • GALLERY_ID

    用于存放转发消息的 Telegram Channel ID,发送给 Bot 的消息中如果带有可被识别的图站链接,则视作图片收藏请求,消息将会被转发到这个 Channel

  • ADMIN_ID

    管理员的 Telegram 用户 ID(不是用户名),Bot 的所有功能仅限管理员使用

    提示:

    1. Telegram 的 User 和 Channel ID 可通过 @GetIDs Bot 获取
    2. 需要将机器人设置为 Channel 管理员
  • DATABASE

    使用的数据库,支持的数据库类型如下:

驱动 URL 配置值 备注
TinyDB https://tinydb.readthedocs.io/en/stable/index.html Local 默认选项
Firestore https://firebase.google.com/products/firestore Firebase
MongoDB https://www.mongodb.com/ Mongo 支持 MongoDB Atlas
Cloudant https://www.ibm.com/cloud/cloudant Cloudant

也可依照 Firebase 的例子实现自己的数据库驱动,将文件放置在 database 目录下,将此选项设置为数据库驱动的类名即可。

  • GOOGLE_APPLICATION_CREDENTIALS

    Firebase SDK 的登录凭据,详见 Firebase 文档

    如果部署在 Heroku 上不希望上传 service-account-file.json,可将文件路径以文件内容代替

  • MONGO_URI

    MongoDB connection string必须指定数据库。

    eg: mongodb://username:password@localhost:27017/database,默认为 mongodb://localhost:27017/nazurin

  • CLOUDANT_USER & CLOUDANT_APIKEY & CLOUDANT_DB

    Cloudant 用户名、API key 和数据库名,使用 IAM 验证方式,默认数据库为 nazurin

  • PIXIV_USER & PIXIV_PASS

    Pixiv 登录邮箱或用户名,以及密码(理论上如果在 Firebase 中已存有 Access Token 和 Refresh Token,删去此条配置也能正常工作)

  • MEGA_USER & MEGA_PASS

    MEGA 登录邮箱及密码(备注同上)

Usage

Commands

可用命令

  • /pixiv <id> - 浏览 Pixiv 画作
  • /pixiv_download <id> - 下载 Pixiv 画作
  • /danbooru <id> - 浏览 Danbooru Post
  • /danbooru_download <id> - 下载 Danbooru Post
  • /yandere <id> - 浏览 Yandere Post
  • /yandere_download <id> - 下载 Yandere Post
  • /konachan <id> - 浏览 Konachan Post
  • /konachan_download <id> - 下载 Konachan Post
  • /zerochan <id> - 浏览 Zerochan Post
  • /zerochan_download <id> - 下载 Zerochan Post
  • /bookmark <id> - 收藏 Pixiv 画作

Collection Update

启动图片收藏自动工作流

向 Bot 发送或转发一条带有 支持的网站 链接的消息(一条消息暂时只能处理一条链接),此后这条消息将会被转发至 GALLERY Channel,随后 Bot 将从图片来源站点下载最清晰的原图文件并发送至 ALBUM Channel,最后文件会被上传至 MEGA 云盘作为备份。

Tips: 在手机上操作时可使用“分享”按钮,最后生成的分享信息带有链接即可。

MEGA Encoding Issues

猜测由于 Mega.py 的 API 方式和官方 SDK 略有不同,因此有时会出现编码问题,具体表现为文件名带有特殊字符时在 Android 和 iOS 客户端显示异常(如出现乱码或显示为 BLANK),且 MEGASync 无法同步该文件,但网页端显示正常,解决方法为:

  1. 新建一个临时文件夹
  2. 设置该临时文件夹为 STORAGE_DIR
  3. 定期登录 MEGA 网页端,将临时文件夹中的文件复制到目标文件夹完成归档

(其实不定期登录也行,只在需要同步文件时操作一遍即可,注意不能使用“移动”操作)

当然也可在源码中修改文件名格式,如设置为 pid 则无此问题

Conclusion

优点:

  • 完全白嫖完全使用免费 SaaS, PaaS 和 BaaS 服务,零成本
  • Telegram, Heroku, Firebase, MEGA 以及图片来源站点之间的网络连接稳定,不受用户本地网络影响

个人中度使用体验:

总之就是很爽、非常爽

执行命令的响应时间较短,图片收藏的平均冷启动响应时间(从发送链接到 Bot 执行完成返回)约为 20 秒,Bot 在线时平均响应时间为 10 秒;支持同时处理多个请求,但 Heroku 对线程数量有一定限制;大文件的处理与 Pixiv 下载与 MEGA 上传速度有关,如执行时间过长会被 Heroku 中断,20MB 以下的文件基本无问题;

各类云服务使用情况:

Heroku 每个月的 Dyno Usage 从未超过 100 小时,基本在 40 小时左右

Heroku Dyno Hours 使用情况

Firebase 更是不用说了,Google 给的免费配额实在慷慨,后期考虑把图片收藏信息也同步过去

Firestore 使用情况

云盘的使用情况会因人而异,就算 MEGA 的 15GB 不够用也可以自己扩展其他存储方式,当然直接把 DOWLOAD_DIR 用作本地存储也没问题。

如下图所示,STORAGE_DIR 设置为 Picturespics 为总归档文件夹,buffer 为临时缓冲区,主要是方便检查;操作时先将 Pictures 文件夹内所有内容复制到 buffer,用 Android 客户端查看无误后移动至 pics,可以确保万无一失。

pics 文件夹中大约有 3GB 文件是原先用 Pixiv 批量下载工具手动同步,其余均为自动工作流上传产生:

MEGA 使用情况

Issues & Roadmap

秉承开源精神,本项目现以 MIT 协议在 Github 开源,但仍有诸多不足之处:

  • 在桌面端的使用较为不便,未来可能考虑写个 Chrome 插件解决
  • 可灵活配置的选项较少
  • 图站 API 与 Bot 耦合过于紧密,正在构建一个插件系统来解耦(已完成)
  • 支持的存储方式和数据库类型较少(估计得引入插件系统才方便开发)(插件系统已完成)
  • 网络请求错误的处理还不够完善
  • 考虑集成智能以图搜图功能
  • 添加对 Pixiv 动图的支持(已完成)
  • 添加对 Pool 的支持

总而言之,PR is welcome

Credits

References

  1. Telegram Bot API
  2. Pricing | Heroku
  3. Dynos and the Dyno Manager - Heroku Dev Center
  4. Firebase Pricing
  5. Cloud Firestore | Firebase
  6. python-telegram-bot Wiki