GitHub Actions实现Z-lib与WebDAV联动
GitHub Actions实现Z-lib与WebDAV联动需求
获取到想看的书后,通常需要多装备查看,尤其盼望平板可以直接阅读,虽然有甚多平台可以同步,但是各种平台使用app差别,或者有一些需要收费。z-lib能够查到很多书,但是通常需要下载到当地。
后发现z-lib可以发送到邮箱,下载起来更为方便,但是需要开邮箱。
同时发现使用WebDAV网盘可以在平板上举行网盘文件阅读,由于博主用的是安卓平板以是这里使用的是静读天下(写的时候查到一个新的app叫安读anx-reader,转头试一下)。
以是需求就是将z-lib的书发到邮箱之后需要主动化地将文件上传到WebDAV,高大上一点也可以说是自建线上图书馆()
配置要求
[*] 一个163邮箱账号(代码写的是163邮箱的,别的邮箱也可以,改一下代码的对应部分即可)
[*] 一个Github账号
[*] 一个Z-lib账号
解决过程
最初的需求
• 从邮箱主动提取特定发件人当天的邮件附件,并将其传输到WebDAV网盘。
实验使用云服务器
• 思量过使用云服务器来运行脚本,但思量到长期租用的成本较高且利用率低,以为不划算。
探索按量付费的云函数服务
• 发现大多数平台需要企业认证或绑定信用卡,对于个人用户来说门槛过高,因此放弃。
实验IFTTT
• 理论上可以连接差别的应用程序,但在实际使用中发现对国内服务的支持不足,免费版功能受限,无法满足需求。
实验ActionFlow
• 按照示例配置订阅功能时出现错误,附件上传环节始终失败,经过多次调试未果,终极放弃。
GitHub Actions方案
Python脚本实现
• 使用imaplib连接邮箱并筛选符合条件的邮件。
• 下载附件到当地,并添加防重复上传和错误处置惩罚机制。
配置文件调解
• 触发频率从每15分钟一次改为逐日定时实行。
• 增加手动触发选项。
流程步骤
[*]拉代替码。
[*]配置Python环境。
[*]安装依赖库。
[*]运行脚本。
[*]使用现成的WebDAV上传工具传输文件。
解决的问题
• imaplib报错:通过查阅文档发现需要先选择收件箱再搜索邮件。
• WebDAV上传失败:查抄WebDAV的权限配置和路径格式,发现问题在于路径斜杠方向错误。
其他改进
• 添加上传后主动清算当地附件的功能。
总结
• 结合开源工具和云服务,以零成本方式实现了需求。
• 关键在于分步骤排查问题,并合理利用GitHub Actions等现有平台。
• 豆包在脚本编写和调试逻辑方面提供了很多实用发起,大大淘汰了试错时间。
教程
一. 准备163邮箱接口
[*]登录邮箱网页版,点击页面右上角的 “设置” 图标,选择 “POP3/SMTP/IMAP”。
[*]在 “IMAP/SMTP 服务” 处,选择开启服务,根据提示完成手机验证等操作。开启后会得到授权码,后续配置客户端时需要用到。
[*]记录为EMAIL_ADDRESS 、EMAIL_PASSWORD
二. 准备WebDAV接口
准备WebDAV网盘可以是本身配置的也可以使用坚果云等网盘
[*] 坚果云 教程 每月有上传下载流量的限定 坚果云第三方应用授权WebDAV开启方法 | 坚果云帮助中央 登岸后找到下图所示的地方设置密码
https://i-blog.csdnimg.cn/direct/631fb5f52fa041bd97269ee92ae633ac.png
[*] Infini 网盘 外网的 免费20G空间 有邀请码加5G 邀请码:8HPAP
注册登录后打开配置页面:My Page|InfiniCLOUD 翻到Apps Connection
https://i-blog.csdnimg.cn/direct/10330049534345ed85ac0b1e14f422ed.png
其他的方式就不外多赘述了,总之末了需要一个链接、一个ID和一个密码,分别记录为WEBDAV_ENDPOINT、WEBDAV_PASSWORD和WEBDAV_USERNAME。
三、配置Github Actions
1. 创建 GitHub 仓库
起首,你需要在 GitHub 上创建一个新的仓库,用于存放你的项目代码和 GitHub Actions 配置文件。
[*]登录你的 GitHub 账号。
[*]点击右上角的 “+” 号,选择 “New repository”。
[*]填写仓库名称、描述等信息,选择仓库的可见性(公开或私有),然后点击 “Create repository”。
2. 准备项目代码
准备需要运行的脚本,这里使用Python接收邮箱信息,对发件人为Z-library的邮件下载附件并上传到网盘,创建了scripts目录存放脚本 scripts/get_and_upload_emails.py
import imaplib
import email
import os
import datetime
class Email(object):
def __init__(self):
self.host = "imap.163.com"
self.account = os.getenv('EMAIL_ADDRESS')
self.password = os.getenv('EMAIL_PASSWORD')
self.server = self.login()
self.log_file = 'upload_log.txt'
self.last_check_file = 'last_check.txt'
self.attachments_folder = 'attachments'
if not os.path.exists(self.attachments_folder):
os.makedirs(self.attachments_folder)
def login(self):
server = imaplib.IMAP4_SSL(self.host)
server.login(self.account, self.password)
imaplib.Commands["ID"] = ('AUTH',)
args = ("name", self.account, "contact", self.account, "version", "1.0.0", "vendor", "myclient")
server._simple_command("ID", str(args).replace(",", "").replace("\'", "\""))
return server
def get_last_check_date(self):
if os.path.exists(self.last_check_file):
with open(self.last_check_file, 'r') as f:
try:
return datetime.datetime.strptime(f.read().strip(), "%Y-%m-%d %H:%M:%S")
except ValueError:
pass
return None
def set_last_check_date(self, date):
with open(self.last_check_file, 'w') as f:
f.write(date.strftime("%Y-%m-%d %H:%M:%S"))
def get_new_mail_attachments(self):
last_check = self.get_last_check_date()
now = datetime.datetime.now()
attachments = []
try:
self.server.select(mailbox='INBOX')
if last_check:
search_criteria = f'(SINCE "{last_check.strftime("%d-%b-%Y")}" BEFORE "{now.strftime("%d-%b-%Y")}")'
else:
search_criteria = f'(SENTSINCE "{now.strftime("%d-%b-%Y")}")'
stat, data = self.server.search(None, search_criteria)
if stat == 'OK':
mail_list = data.split()
for index in mail_list:
status, message = self.server.fetch(index, "(RFC822)")
if status == 'OK':
msg = email.message_from_bytes(message)
msg_date = email.utils.parsedate_to_datetime(msg['Date'])
if last_check and msg_date <= last_check:
continue
sender = email.header.decode_header(msg["From"])
if isinstance(sender, bytes):
charset = email.header.decode_header(msg["From"])
sender = sender.decode(charset) if charset else sender.decode()
if "Z-Library" in sender:
for part in msg.walk():
if part.get_content_maintype() == 'multipart':
continue
if part.get('Content-Disposition') is None:
continue
file_name = part.get_filename()
if file_name:
save_path = os.path.join(self.attachments_folder, file_name)
with open(save_path, 'wb') as f:
f.write(part.get_payload(decode=True))
attachments.append(save_path)
except Exception as e:
print(f"Error getting attachments: {e}")
finally:
self.set_last_check_date(now)
return attachments
def check_and_upload(self, attachments):
uploaded_files = self.read_upload_log()
for attachment in attachments:
if attachment not in uploaded_files:
print(f"Uploading {attachment}...")
self.update_upload_log(attachment)
else:
print(f"{attachment} has already been uploaded, skipping.")
def read_upload_log(self):
if os.path.exists(self.log_file):
with open(self.log_file, 'r') as f:
return f.read().splitlines()
return []
def update_upload_log(self, file_name):
with open(self.log_file, 'a') as f:
f.write(file_name + '\n')
def str_to_unicode(self, s, charset):
if charset:
return s.decode(charset)
return s
def parse_message(self, msg):
content = ""
for part in msg.walk():
if part.get_content_type() == "text/plain":
charset = part.get_content_charset()
if charset is None:
charset = "utf-8"
try:
content += part.get_payload(decode=True).decode(charset, errors='ignore')
except UnicodeDecodeError:
pass
return content
if __name__ == "__main__":
email_client = Email()
attachments = email_client.get_new_mail_attachments()
email_client.check_and_upload(attachments)
3. 准备action脚本
GitHub Actions 使用 YAML 文件来定义工作流(Workflow)。工作流包含一个或多个作业(Job),每个作业又包含一个或多个步骤(Step)。
[*] 在项目根目录下创建一个名为 .github/workflows 的文件夹
[*] 在 .github/workflows 文件夹中创建一个 YAML 文件,例如 .github/workflows/upload_email_attachments.yml,并使用文本编辑器打开它。
name: Upload Email Attachments to WebDAV
on:
schedule:
- cron: '0 0 * * *'# 每天 0 点 0 分执行
workflow_dispatch:# 允许手动触发此工作流程
# - cron: '*/15 * * * *'# 每 15 分钟检查一次
# - cron: '0 0 * * *'
# on: #点击触发
# on: # 触发工作流程的事件,这里设置为在push时触发
jobs:
upload-attachments:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: 3.x
- name: Install dependencies
run: pip install --upgrade pip
- name: Get new email attachments and check upload
env:
EMAIL_ADDRESS: ${{ secrets.EMAIL_ADDRESS }}
EMAIL_PASSWORD: ${{ secrets.EMAIL_PASSWORD }}
run: python scripts/get_and_upload_emails.py
- name: Upload to WebDAV
uses: bxb100/action-upload@main
with:
provider: webdav
provider_options: |
endpoint=${{ secrets.WEBDAV_ENDPOINT }}
username=${{ secrets.WEBDAV_USERNAME }}
password=${{ secrets.WEBDAV_PASSWORD }}
root=/reading/
include: 'attachments/*'
- name: Delete local attachments after successful upload
if: success()
run: |
if [ -d "attachments" ]; then
rm -rf attachments/*
fi
4.运行Actions
设置环境变量存储前面的账号信息密码等等
https://i-blog.csdnimg.cn/direct/3856575767d742fb8c0aa64426837abd.png
https://i-blog.csdnimg.cn/direct/e555650459424ca6a8515d89bb4efe2e.png
这里直接测试可以直接点击运行,如果需要设置定时运行,更改YAML 文件的schedule位置即可。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]