From 3e277afddcc5ab4618e899e4f701c09c339a7032 Mon Sep 17 00:00:00 2001 From: bdzxb <1443103348@qq.com> Date: Sat, 16 May 2026 15:11:33 +0800 Subject: [PATCH] modified: .idea/misc.xml modified: README.md modified: __pycache__/main.cpython-312.pyc modified: _conf_schema.json new file: image.png modified: main.py deleted: static/files/ceshi.txt deleted: static/img/server-icon.png new file: tools/.flask.pid new file: tools/__pycache__/mail_tool.cpython-312.pyc new file: tools/__pycache__/zhangdan_flask.cpython-312.pyc new file: tools/mail_tool.py new file: tools/zhangdan_flask.py --- .idea/misc.xml | 3 +- README.md | 46 +- __pycache__/main.cpython-312.pyc | Bin 21470 -> 17165 bytes _conf_schema.json | 22 + image.png | Bin 0 -> 45364 bytes main.py | 312 ++--- static/files/ceshi.txt | 1 - static/img/server-icon.png | Bin 32319 -> 0 bytes tools/.flask.pid | 1 + tools/__pycache__/mail_tool.cpython-312.pyc | Bin 0 -> 5448 bytes .../zhangdan_flask.cpython-312.pyc | Bin 0 -> 35827 bytes tools/mail_tool.py | 117 ++ tools/zhangdan_flask.py | 1062 +++++++++++++++++ 13 files changed, 1352 insertions(+), 212 deletions(-) create mode 100644 image.png delete mode 100644 static/files/ceshi.txt delete mode 100644 static/img/server-icon.png create mode 100644 tools/.flask.pid create mode 100644 tools/__pycache__/mail_tool.cpython-312.pyc create mode 100644 tools/__pycache__/zhangdan_flask.cpython-312.pyc create mode 100644 tools/mail_tool.py create mode 100644 tools/zhangdan_flask.py diff --git a/.idea/misc.xml b/.idea/misc.xml index d50a49f..f141e52 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,8 +1,9 @@ + - + \ No newline at end of file diff --git a/README.md b/README.md index 21e7af2..83ee549 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,47 @@ # astrbot_bdzxb_bill -astrbot插件,通过微信支付宝导出账单到邮箱,然后进行解析统计 \ No newline at end of file +astrbot插件,通过微信支付宝导出账单到邮箱,然后进行解析统计 + +## 需要导入的包 + +* sqlite3 +* numpy +* urllib.parse +* requests +* pandas +* zipfile +* os +* pyzipper +* re +* lxml +* datetime +* imaplib +* secrets +* threading +* flask +* flask_cors + +--- + +## 配置文件 + +* ![alt text](image.png) + +## 使用方法 + +1. 补充完整配置文件 +2. 导出账单到邮箱 + 1. 微信: 点击微信支付》我的账单》账单明细》点击右上角的三个点》下载账单》用于个人对账》接受方式 选择邮箱》下一步》发送 + 2. 支付宝:我的》账单》点击右上角三个点》开具交易流水证明》用于个人对账》接收方式选邮箱》发送 +3. 账单导出到邮箱后 引用内消息会推送解压密码给你 +4. 在bot中输入指令 /mm 解压密码 解压密码 此处不区分前后顺序 最终结果会放入 插件data文件夹的zhangdan.db中,/chazhang 指令可查询最后10条数据 +5. 插件提供了一个web页面展示数据(AI生成),使用/rwebui 启动服务 服务端口可根据插件配置文件修改,查看后可使用/swebui 指令关闭web服务 +6. 服务器指令均需astrbot管理员权限执行 + +## 指令列表 + +* /zdhelp 获取帮助 +* /mm 密码1 密码2 # 解压并记录数据 +* /chazhang # 查看最后10条数据 +* /rwebui 启动webui +* /swebui 关闭webui diff --git a/__pycache__/main.cpython-312.pyc b/__pycache__/main.cpython-312.pyc index c167f4775fb3128dff7de0cf5ed232d0b18644af..0a94aa919cd5410b8663f1a1fb34f168b2693447 100644 GIT binary patch delta 6609 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 delta 10413 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

9)C+Fib_{QAWd9OIz8F?c>MEO3&NyCvK3b? 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

Dqmb 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

OPNISV6QVWPxUPRL2 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 MIf}>TXj=RJ57Wa*ga7~l literal 0 HcmV?d00001 diff --git a/main.py b/main.py index 55bba06..fc8d6dd 100644 --- a/main.py +++ b/main.py @@ -1,30 +1,7 @@ - -from pathlib import Path -import astrbot.core.message.components as Comp -import datetime -import json -from astrbot.api.event import filter, AstrMessageEvent,MessageChain +from astrbot.api.event import filter, AstrMessageEvent from astrbot.api.star import Context, Star, register, StarTools from astrbot.api import logger, AstrBotConfig -from astrbot.api.message_components import Node, Plain,Video,Image,Nodes,File -from astrbot.core.utils.session_waiter import ( - session_waiter, - SessionController, -) -from typing import List -import imaplib -# 导入email库用于解析邮件内容 -import email -# 导入os库用于文件和目录操作 -import os -# 从datetime导入datetime用于日期时间处理 -from datetime import datetime -# 导入email.utils用于邮件日期解析 -import email.utils -# 导入email.header用于解码邮件头 -import email.header -from lxml import html -import re +import os import zipfile from pyzipper import AESZipFile import pandas as pd @@ -32,22 +9,38 @@ import requests from urllib.parse import urlparse import numpy as np import sqlite3 +from .tools.mail_tool import emaillog +from .tools.zhangdan_flask import runwebui,stop_server + @register("astrbot_bdzxb_bill", "bd_bill", "账单统计", "1.0.0") class MyPlugin(Star): def __init__(self, context: Context, config: AstrBotConfig): super().__init__(context) - self.ceshi = None + # 邮箱 self.email_usr = None + # 授权码 self.emcil_paswd = None + # imap服务器地址 self.emcil_imap = None - self.message_target = None + # 略过附件列表 self.no_file = None + # 发件人白名单 self.emcil_white = None + # 插件文件位置 self.file_path = "data/plugins/astrbot_bdzxb_bill" + # 配置文件 self.config = config - self.chatid = None + # 插件data文件保存位置 self.data_path = None + # sqllite Connection self.sqllitaa = None + # webui 开关 + self.rwebui = None + # webui 端口 + self.webui_port = None + # webui 密码 + self.webui_passwd = None + # 初始化插件 async def initialize(self): """可选择实现异步的插件初始化方法,当实例化该插件类之后会自动调用该方法。""" # 读取配置信息 @@ -56,9 +49,17 @@ class MyPlugin(Star): self.emcil_imap = self.config.emcil_imap self.emcil_white = self.config.emcil_white self.no_file = self.config.no_file + self.data_path = StarTools.get_data_dir("astrbot_bdzxb_bill") + self.rwebui = self.config.rwebui + # 检查端口号是否合规 不合规更新为5001 + if self.rwebui >35565 or self.rwebui<2: + self.rwebui = 5001 + self.config.save_config() # 保存配置 + self.webui_port = self.config.webui_port + self.webui_passwd = self.config.webui_passwd + # 如果data文件夹不包含db文件 则创建 并且初始化数据库 file_list = os.listdir(f"{self.data_path}") - if "zhangdan.db" not in file_list: self.sqllitaa = sqlite3.connect(f"{self.data_path}/zhangdan.db") # 创建游标对象 @@ -93,193 +94,119 @@ class MyPlugin(Star): self.sqllitaa.close() else: self.sqllitaa = sqlite3.connect(f"{self.data_path}/zhangdan.db") - - + # 读取配置文件 查看石头需要直接启动webui + if self.rwebui: + runwebui(int(self.webui_port), self.webui_passwd, f"{self.data_path}/zhangdan.db") + + def guanbiweb(): + MyPlugin.rwebui = False + MyPlugin.config.save_config() # 保存配置 + # 帮助 + @filter.permission_type(filter.PermissionType.ADMIN) @filter.command("zdhelp") async def mchelp(self, event: AstrMessageEvent): logger.info(" 开始执行 zdhelp 命令 ") - helptxt = """ """ + helptxt = "/zdhelp 获取本帮助文档\n/mm 密码1 密码2 # 解压并记录数据 \n/chazhang # 查看最后10条数据 \n/rwebui 启动webui \n/swebui 关闭webui" yield event.plain_result(f"{helptxt}") - # 获取解压密码冰进行下载解压 + # 启动webui + @filter.permission_type(filter.PermissionType.ADMIN) + @filter.command("rwebui") + async def rwebuicmd(self, event: AstrMessageEvent): + logger.info(" 开始执行 rwebui 命令 ") + + try: + self.rwebui = False + self.config.save_config() # 保存配置 + stop_server() + except Exception as e: + logger.info("准备开启服务") + + # 查看是否开启 + self.rwebui = True + self.config.save_config() # 保存配置 + runwebui(int(self.webui_port), self.webui_passwd, f"{self.data_path}/zhangdan.db") + + yield event.plain_result(f"webUI已启动 0.0.0.0:{self.webui_port}") + # 停止webui + @filter.permission_type(filter.PermissionType.ADMIN) + @filter.command("swebui") + async def swebuicmd(self, event: AstrMessageEvent): + logger.info(" 开始执行 swebui 命令 ") + # 查看是否开启 + if self.rwebui: + self.rwebui = False + self.config.save_config() # 保存配置 + stop_server() + yield event.plain_result("webdui已关闭") + + # 获取解压密码并进行下载解压 + @filter.permission_type(filter.PermissionType.ADMIN) @filter.command("mm") async def wxmm(self, event: AstrMessageEvent, wxmm: str,zfbmm: str): - # # 登录邮箱 下载文件 - yield event.plain_result(f"{self.emaillog()}") + # 登录邮箱 下载文件 + yield event.plain_result(emaillog()) logger.info("开始解压文件") - # # 解压文件 self.data_path + # 解压文件 self.data_path file_list = os.listdir(self.data_path ) - logger.info(f"{file_list}") + # logger.info(f"{file_list}") + # 解压 两个密码都试一次 for aac in file_list: self.jzip(filename=aac,mima=wxmm) self.jzip(filename=aac,mima=zfbmm) # 解析文件 file_list = os.listdir(f"{self.data_path}/zhangdan") yield event.plain_result(f"解压后文件列表:{file_list}") - self.sqllitaa = sqlite3.connect(f"{self.data_path}/zhangdan.db") cur = self.sqllitaa.cursor() try: for aaa in file_list: + # 获取sql语句列表并执行 for icc in self.exceltt(filename=str(self.data_path)+"/zhangdan/"+aaa): cur.execute(icc) self.sqllitaa.commit() cur.close() self.sqllitaa.close() - # 删除源文件 - file_list = os.listdir(f"{self.data_path}") - for nam in file_list: - if "zhangdan.db" not in nam: - try: + try: + # 删除源文件 + file_list = os.listdir(f"{self.data_path}") + for nam in file_list: + if "zhangdan" not in nam: os.remove(str(self.data_path)+"\\"+nam) - except IOError as e: - file_listaa = os.listdir(f"{self.data_path}/zhangdan/") - for namaa in file_listaa: - os.remove(str(self.data_path)+"\\zhangdan\\"+namaa) - # logger.info(f"{e}") - + file_listaa = os.listdir(f"{self.data_path}/zhangdan/") + for namaa in file_listaa: + os.remove(str(self.data_path)+"\\zhangdan\\"+namaa) + except IOError as e: + logger.error(f"文件删除失败 原因{e}") yield event.plain_result("保存完成__使用/chazhang 查询最后10条记录") - except Exception as e: yield event.plain_result(f"保存失败{e}") - logger.info(f"{e}") + logger.error(f"保存失败 原因:{e}") cur.close() self.sqllitaa.close() # 查账 + @filter.permission_type(filter.PermissionType.ADMIN) @filter.command("chazhang") async def chazhang(self, event: AstrMessageEvent): logger.info(" 开始执行 chazhang 命令 ") self.sqllitaa = sqlite3.connect(f"{self.data_path}/zhangdan.db") # 创建游标对象 cursor = self.sqllitaa.cursor() + # 返回最后10条 try: cursor.execute('SELECT * FROM zhangdan ORDER BY id DESC LIMIT 10;') jieg =cursor.fetchall() self.sqllitaa.commit() - cursor.close() - self.sqllitaa.close() yield event.plain_result(f"{jieg}") except Exception as e: yield event.plain_result(f"查询失败:{e}") - logger.info(f"查询失败{e}") + logger.error(f"查询失败{e}") self.sqllitaa.commit() - cursor.close() - self.sqllitaa.close() + cursor.close() + self.sqllitaa.close() - # 登录邮箱 下载文件 - def emaillog(self): - logger.info(f" 开始执行 登录邮箱 {self.email_usr} 命令 ") - # 邮箱登录用户名 - email_user = self.email_usr - # 邮箱授权码(非登录密码),用于IMAP协议认证 - email_password = self.emcil_paswd - # IMAP服务器地址,Foxmail使用QQ邮箱的IMAP服务器 - imap_server = self.emcil_imap - mail = imaplib.IMAP4_SSL(imap_server) - # 使用用户名和授权码登录邮箱 - # try: - mail.login(email_user, email_password) - # 查询收件箱 只读模式 - mail.select("inbox",readonly=True) - # 设定查询条件 - for emlname in self.emcil_white: - from_clause = " OR ".join([f'FROM "{sender}"' for sender in emlname]) - # 获取今天的日期,格式化为IMAP要求的格式(如"21-Jul-2025") - today = datetime.now().strftime("%d-%b-%Y") - search_criteria = f'({from_clause} SINCE "{today.encode('utf-8')}" HAS attachment)' - logger.info(f"严格模式: 只处理今天({today})收到的邮件") - logger.info(f"发件人白名单: {self.emcil_white}") - logger.info(f"搜索条件: {search_criteria}") - - # 执行IMAP搜索命令 - status, messages = mail.search(None, search_criteria) - if status != "OK": # 检查搜索是否成功 - raise Exception("邮件搜索失败") - - # 获取邮件ID列表并只取最后20个(最新的20封) - mail_ids = messages[0].split()[-20:] - logger.info(f"获取到邮件数量: {len(messages)}") - filenames = "" - for mail_id in reversed(mail_ids): - # 获取邮件完整内容(RFC822格式) - status, msg_data = mail.fetch(mail_id, "(RFC822)") - if status != "OK": # 如果获取失败则跳过 - continue - # 解析邮件内容为Message对象 - email_message = email.message_from_bytes(msg_data[0][1]) - # 验证发件人是否在白名单中 - # ======================== - from_header = email.utils.parseaddr(email_message['From'])[1] # 解析发件人邮箱 - logger.info(f"邮件发件人: {from_header}") - if from_header not in self.emcil_white: # 严格检查白名单 - logger.info(f"跳过非白名单发件人: {from_header}") - continue - - # 遍历邮件各部分 - # ============= - for part in email_message.walk(): # 递归遍历邮件所有部分 - if part.get_content_maintype() == "multipart": # 跳过multipart容器部分 - continue - filename = part.get_filename() # 获取附件文件名 - # 获取正文 - maildata = part.get_payload(decode=True) - # 微信导出文件需要点击链接下载 检测正文中是否包含链接 - etree = html.etree - tree = etree.HTML(maildata) - # logger.info(f"邮件正文{maildata}") - a_tags = tree.xpath('//a') - mail_date = email.utils.parsedate_to_datetime(email_message['Date']) if email_message['Date'] else None - mail_date = re.sub(r"[^\u4e00-\u9fa5a-zA-Z0-9]", "", str(mail_date)) - for a_tag in a_tags: - # 获取到url后下载url - urlt = a_tag.get("href") - if urlt: - try: - filenames += self.download_file(urlt=urlt,filenamett=f"{from_header}{mail_date}") - except Exception as e: - logger.debug(f"URl 文件下载失败:{e}") - # 处理无文件名的情况 - # ================ - if not filename: # 如果附件没有文件名 - # 按日期发件人生成附件名 - filename = f"{from_header}{mail_date}.zip" - # 文件名处理 - # ========= - # 解码邮件头中的文件名 - try: - decoded_name = email.header.decode_header(filename)[0][0] - if isinstance(decoded_name, bytes): - decoded_name = decoded_name.decode() - except Exception as e: - logger.info(f"{e} \n解析文件名称失败{email.header.decode_header(filename)[0][0]}") - decoded_name = f"{from_header}{datetime.now().strftime("%d-%b-%Y")}.zip" - filename = f"{from_header}{mail_date}.zip" - - - today_str = datetime.now().strftime("%Y%m%d") # 获取当前日期字符串 - base_name, ext = os.path.splitext(decoded_name) # 拆分文件名和扩展名 - # 生成新文件名格式:YYYYMMDD-原文件名.zip - new_filename = f"{today_str}-{base_name}{ext}" - if filename: - new_filename = filename - # 拼接完整的文件保存路径 - filepath = os.path.join(StarTools.get_data_dir("astrbot_bdzxb_bill"), new_filename) - if new_filename not in self.no_file: - # 附件保存处理 - # =========== - if not os.path.exists(filepath): # 检查文件是否已存在 - # 以二进制模式保存附件 - with open(filepath, "wb") as f: - f.write(part.get_payload(decode=True)) # 解码并写入附件内容 - logger.info(f"下载附件: {filename} -> {new_filename}") - filenames += new_filename+"\n" - else: # 文件已存在则跳过 - with open(filepath, "wb") as f: - f.write(part.get_payload(decode=True)) # 解码并写入附件内容 - logger.info(f"附件已存在,覆盖: {new_filename}") - return "获取成功:"+filenames - + # 分析文件并返回SQL语句 def exceltt(self,filename): yuju = [] try: @@ -309,34 +236,21 @@ class MyPlugin(Star): yuju.append(f"replace into zhangdan(id,payid,paytype,paydate,payname,payto,paysize,paystu,paybox,payqd) VALUES('{np.float64(shuju[8])}','{shuju[8]}','{shuju[1]}','{shuju[0]}','{shuju[2]+shuju[3]}','{shuju[4]}','{shuju[5]}','{shuju[7]}','{shuju[6]}','微信')") # 读取xlsx文件 return yuju - except Exception as e: - logger.info(f"{e}") + logger.error(f"解析文件失败 原因{e}") return - - # if "支付宝" in filename: - - # elif "微信" in filename: - + # 解压文件 def jzip(self,filename,mima): filename = self.data_path / f'{filename}' # 输出目录 output_path = f'{self.data_path}/zhangdan' + # 检查目录是否存在 try: os.mkdir(output_path) except Exception as e: logger.info(f"文件夹已存在开始解压{filename}") - # try: - # # 使用AESZipFile打开加密的ZIP文件 - # with AESZipFile(filename, 'r') as zf: - # # 列出ZIP文件中的所有文件和文件夹 - # logger.info(f"本次解压文件{zf.namelist()}") - # # 解压所有文件到指定目录 - # zf.extractall(path=output_path, pwd=mima.encode("bytes")) - # except Exception as e: - # logger.debug(f"解压失败:{e}") - + # 解压文件 try: with AESZipFile(filename, 'r') as zf: logger.info(f"本次解压文件{zf.namelist()}") @@ -346,15 +260,11 @@ class MyPlugin(Star): logger.error(f"解压失败,原因:{e}") # RuntimeError 常因密码错误触发 except Exception as e: logger.error(f"解压过程中出现未知错误:{e}") - - - - + # 通过url下载文件 def download_file(self,urlt,filenamett): try: response = requests.get(urlt, stream=True) response.raise_for_status() - download_dir = StarTools.get_data_dir("astrbot_bdzxb_bill") os.makedirs(download_dir, exist_ok=True) file_name = os.path.basename(urlparse(urlt).path)+filenamett @@ -372,24 +282,8 @@ class MyPlugin(Star): else: return except Exception as e: - return - - -#保存文件 - def get_json_path(self, filename: str) -> Path: - """ - 读取Jason文件 - - Args: - filename: 文件名称 - - Returns: - JSON文件的Path对象 - """ - data_path = StarTools.get_data_dir("astrbot_bdzxb_bill") - json_path = data_path / f'{filename}.json' - json_path.parent.mkdir(parents=True, exist_ok=True) - return json_path + logger.error(f"文件下载失败 原因:{e}") + return async def terminate(self): """可选择实现异步的插件销毁方法,当插件被卸载/停用时会调用。""" diff --git a/static/files/ceshi.txt b/static/files/ceshi.txt deleted file mode 100644 index 1a237b6..0000000 --- a/static/files/ceshi.txt +++ /dev/null @@ -1 +0,0 @@ -这是一个测试文件 \ No newline at end of file diff --git a/static/img/server-icon.png b/static/img/server-icon.png deleted file mode 100644 index df32239170609cfdace080053bc40bd3096ac60b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32319 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 literal 0 HcmV?d00001 diff --git a/tools/__pycache__/zhangdan_flask.cpython-312.pyc b/tools/__pycache__/zhangdan_flask.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d9e0e4606216dbe7d696a77ada9742af0e920ee4 GIT binary patch literal 35827 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 R(EE_1E~nUWG@lW`{|9`%aV!7; literal 0 HcmV?d00001 diff --git a/tools/mail_tool.py b/tools/mail_tool.py new file mode 100644 index 0000000..45a7f01 --- /dev/null +++ b/tools/mail_tool.py @@ -0,0 +1,117 @@ +import imaplib +from datetime import datetime +import email.utils +import email.header +from astrbot.api import logger +import email +from lxml import html +import re +import os +from astrbot.api.star import StarTools + + +# 登录邮箱 下载文件 +def emaillog(self): + logger.info(f" 开始执行 登录邮箱 {self.email_usr} 命令 ") + # 邮箱登录用户名 + email_user = self.email_usr + # 邮箱授权码(非登录密码),用于IMAP协议认证 + email_password = self.emcil_paswd + # IMAP服务器地址,Foxmail使用QQ邮箱的IMAP服务器 + imap_server = self.emcil_imap + mail = imaplib.IMAP4_SSL(imap_server) + # 使用用户名和授权码登录邮箱 + # try: + mail.login(email_user, email_password) + # 查询收件箱 只读模式 + mail.select("inbox",readonly=True) + # 设定查询条件 + for emlname in self.emcil_white: + from_clause = " OR ".join([f'FROM "{sender}"' for sender in emlname]) + # 获取今天的日期,格式化为IMAP要求的格式(如"21-Jul-2025") + today = datetime.now().strftime("%d-%b-%Y") + today = today.encode('utf-8') + search_criteria = f'({from_clause} SINCE "{today}" HAS attachment)' + logger.info(f"严格模式: 只处理今天({today})收到的邮件") + logger.info(f"发件人白名单: {self.emcil_white}") + logger.info(f"搜索条件: {search_criteria}") + + # 执行IMAP搜索命令 + status, messages = mail.search(None, search_criteria) + if status != "OK": # 检查搜索是否成功 + raise Exception("邮件搜索失败") + + # 获取邮件ID列表并只取最后20个(最新的20封) + mail_ids = messages[0].split()[-20:] + logger.info(f"获取到邮件数量: {len(messages)}") + filenames = "" + for mail_id in reversed(mail_ids): + # 获取邮件完整内容(RFC822格式) + status, msg_data = mail.fetch(mail_id, "(RFC822)") + if status != "OK": # 如果获取失败则跳过 + continue + # 解析邮件内容为Message对象 + email_message = email.message_from_bytes(msg_data[0][1]) + # 验证发件人是否在白名单中 + # ======================== + from_header = email.utils.parseaddr(email_message['From'])[1] # 解析发件人邮箱 + # logger.info(f"邮件发件人: {from_header}") + if from_header not in self.emcil_white: # 严格检查白名单 + # logger.info(f"跳过非白名单发件人: {from_header}") + continue + + # 遍历邮件各部分 + # ============= + for part in email_message.walk(): # 递归遍历邮件所有部分 + if part.get_content_maintype() == "multipart": # 跳过multipart容器部分 + continue + filename = part.get_filename() # 获取附件文件名 + # 获取正文 + maildata = part.get_payload(decode=True) + # 微信导出文件需要点击链接下载 检测正文中是否包含链接 解析正文内容 筛选a标签获取下载链接 + etree = html.etree + tree = etree.HTML(maildata) + # logger.info(f"邮件正文{maildata}") + a_tags = tree.xpath('//a') + mail_date = email.utils.parsedate_to_datetime(email_message['Date']) if email_message['Date'] else None + mail_date = re.sub(r"[^\u4e00-\u9fa5a-zA-Z0-9]", "", str(mail_date)) + for a_tag in a_tags: + # 获取到url后下载url + urlt = a_tag.get("href") + if urlt: + try: + filenames += self.download_file(urlt=urlt,filenamett=f"{from_header}{mail_date}") + except Exception as e: + logger.debug(f"URl 文件下载失败:{e}") + # 处理无文件名的情况 + # ================ + if not filename: # 如果附件没有文件名 + # 按日期发件人生成附件名 + filename = f"{from_header}{mail_date}.zip" + # 文件名处理 + # ========= + # 解码邮件头中的文件名 + try: + decoded_name = email.header.decode_header(filename)[0][0] + if isinstance(decoded_name, bytes): + decoded_name = decoded_name.decode() + except Exception as e: + # 文件名解析失败 自动生成新名字 + decoded_name,filename = f"{from_header}{mail_date}.zip" + today_str = datetime.now().strftime("%Y%m%d") # 获取当前日期字符串 + base_name, ext = os.path.splitext(decoded_name) # 拆分文件名和扩展名 + # 生成新文件名格式:YYYYMMDD-原文件名.zip + new_filename = f"{today_str}-{base_name}{ext}" + if filename: + new_filename = filename + # 拼接完整的文件保存路径 + filepath = os.path.join(StarTools.get_data_dir("astrbot_bdzxb_bill"), new_filename) + if new_filename not in self.no_file: + # 附件保存处理 + # 以二进制模式保存附件 + with open(filepath, "wb") as f: + f.write(part.get_payload(decode=True)) # 解码并写入附件内容 + # logger.info(f"下载附件: {filename} -> {new_filename}") + filenames += new_filename+"\n" + return "获取成功:"+filenames + \ No newline at end of file diff --git a/tools/zhangdan_flask.py b/tools/zhangdan_flask.py new file mode 100644 index 0000000..0c34f39 --- /dev/null +++ b/tools/zhangdan_flask.py @@ -0,0 +1,1062 @@ +#!/usr/bin/env python3 +""" +账单查询服务 - Flask版 +从 zhangdan.db 读取数据,提供网页展示和API接口 +""" + +import sqlite3 +import os +import secrets +import threading +from flask import Flask, render_template_string, jsonify, request, session, redirect, url_for +from flask_cors import CORS + + + +# ===== 🔧 常量 ===== +PORT = 5001 +PID_FILE = os.path.join(os.path.dirname(os.path.abspath(__file__)), ".flask.pid") + +# ===== 🔧 全局状态 ===== +_server = None # werkzeug server 实例 +_server_thread = None # 服务线程 +_server_lock = threading.Event() + +# 启动 +def runwebui(web_port,web_passwd,datadb): + global AUTH_PASSWORD,DB_PATH,AUTH_COOKIE_MAX_AGE + try: + AUTH_PASSWORD = web_passwd + AUTH_COOKIE_MAX_AGE = 86400 * 1 # 1天免登录 + DB_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), datadb) + start_server(host="0.0.0.0", port=web_port, debug=False ) + except EOFError as e: + print(e) + + +def start_server(host, port, debug): + """在子线程中启动 Flask 服务,主线程不受影响""" + global _server, _server_thread + + if _server_thread and _server_thread.is_alive(): + print("⚠️ 服务已在运行中") + return _server + + from werkzeug.serving import make_server + + _server = make_server(host, port, app, threaded=True) + _server_thread = threading.Thread(target=_server.serve_forever, daemon=True) + _server_thread.start() + _server_lock.set() + + # 写 PID + with open(PID_FILE, "w") as f: + f.write(str(os.getpid())) + + print(f"🚀 服务已启动 (子线程) → http://{host}:{port}") + return _server + + +def stop_server(): + """只关闭 Flask 子线程,主线程继续运行""" + + global _server, _server_thread + + if _server: + try: + _server.shutdown() # 优雅关闭 werkzeug server + except Exception: + pass + _server = None + + if _server_thread and _server_thread.is_alive(): + _server_thread.join(timeout=3) + _server_thread = None + + _server_lock.clear() + + # 清理 PID 文件 + if os.path.exists(PID_FILE): + try: + os.remove(PID_FILE) + except OSError: + pass + + print("🛑 Flask 服务已关闭(主线程仍在运行)") + + +def server_status(): + """检查 Flask 子线程是否在运行""" + alive = _server_thread is not None and _server_thread.is_alive() + return {"running": alive, "port": PORT} + +app = Flask(__name__) +app.secret_key = secrets.token_hex(32) +CORS(app) +def check_auth(): + """检查是否已登录""" + return session.get("authenticated") is True + + +def login_required(f): + """登录装饰器""" + from functools import wraps + @wraps(f) + def decorated(*args, **kwargs): + if not check_auth(): + return redirect(url_for("login_page")) + return f(*args, **kwargs) + return decorated + +def get_db(): + conn = sqlite3.connect(DB_PATH) + conn.row_factory = sqlite3.Row + return conn + + +@app.route("/login", methods=["GET", "POST"]) +def login_page(): + error = None + if request.method == "POST": + pwd = request.form.get("password", "") + if pwd == AUTH_PASSWORD: + session["authenticated"] = True + session.permanent = True + app.permanent_session_lifetime = __import__("datetime").timedelta(seconds=AUTH_COOKIE_MAX_AGE) + return redirect(url_for("index")) + error = "密码不对哦,再试试 🤔" + return render_template_string(LOGIN_TEMPLATE, error=error) + + +@app.route("/logout") +def logout(): + session.clear() + return redirect(url_for("login_page")) + + +# ===== 🔴 关机密令 ===== +SHUTDOWN_TOKEN = "shutdown_2026" + + +@app.route("/shutdown") +def shutdown_server(): + """通过密令关闭服务,访问 /shutdown?token=xxx 即可关机""" + token = request.args.get("token", "") + if token != SHUTDOWN_TOKEN: + return "❌ 无效密令", 403 + # 在新线程中关闭,避免阻塞当前请求 + threading.Thread(target=stop_server, daemon=True).start() + return "🛑 服务已关闭" + + +@app.route("/") +@login_required +def index(): + return render_template_string(HTML_TEMPLATE, shutdown_token=SHUTDOWN_TOKEN) + + +@app.route("/api/bills") +@login_required +def api_bills(): + """返回所有账单数据,支持排序和筛选""" + conn = get_db() + cur = conn.cursor() + + # 筛选参数 + payto = request.args.get("payto") # 收入/支出 + payqd = request.args.get("payqd") # 渠道 + paybox = request.args.get("paybox") # 钱包 + paytype = request.args.get("paytype") # 交易类型 + keyword = request.args.get("keyword") # 搜索关键词 + date_from = request.args.get("date_from") # 起始日期 + date_to = request.args.get("date_to") # 截止日期 + + # 排序参数 + sort = request.args.get("sort", "paydate") + order = request.args.get("order", "DESC") + + allowed_sorts = { + "paydate", "paysize", "paytype", "payname", + "payto", "paystu", "paybox", "payqd", "id" + } + if sort not in allowed_sorts: + sort = "paydate" + order = "ASC" if order.upper() == "ASC" else "DESC" + + query = "SELECT * FROM zhangdan WHERE 1=1" + params = [] + + if payto: + query += " AND payto = ?" + params.append(payto) + if payqd: + query += " AND payqd = ?" + params.append(payqd) + if paybox: + query += " AND paybox = ?" + params.append(paybox) + if paytype: + query += " AND paytype = ?" + params.append(paytype) + if keyword: + query += " AND (payname LIKE ? OR paytype LIKE ?)" + params.extend([f"%{keyword}%", f"%{keyword}%"]) + if date_from: + query += " AND paydate >= ?" + params.append(date_from) + if date_to: + query += " AND paydate <= ?" + params.append(date_to + " 23:59:59") + + # paysize 存的是文本,需要特殊处理排序 + if sort == "paysize": + query += f" ORDER BY CAST({sort} AS REAL) {order}" + else: + query += f" ORDER BY {sort} {order}" + + cur.execute(query, params) + rows = [dict(r) for r in cur.fetchall()] + conn.close() + return jsonify(rows) + + +@app.route("/api/summary") +@login_required +def api_summary(): + """汇总统计 — 支持与 /api/bills 相同的筛选参数""" + conn = get_db() + cur = conn.cursor() + + # 收集筛选条件(与 /api/bills 一致) + payto = request.args.get("payto") + payqd = request.args.get("payqd") + paybox = request.args.get("paybox") + paytype = request.args.get("paytype") + keyword = request.args.get("keyword") + date_from = request.args.get("date_from") + date_to = request.args.get("date_to") + + where = "WHERE 1=1" + params = [] + if payto: + where += " AND payto = ?" + params.append(payto) + if payqd: + where += " AND payqd = ?" + params.append(payqd) + if paybox: + where += " AND paybox = ?" + params.append(paybox) + if paytype: + where += " AND paytype = ?" + params.append(paytype) + if keyword: + where += " AND (payname LIKE ? OR paytype LIKE ?)" + params.extend([f"%{keyword}%", f"%{keyword}%"]) + if date_from: + where += " AND paydate >= ?" + params.append(date_from) + if date_to: + where += " AND paydate <= ?" + params.append(date_to + " 23:59:59") + + # 总收入/支出 + cur.execute(f""" + SELECT payto, + COUNT(*) as count, + SUM(CAST(paysize AS REAL)) as total + FROM zhangdan {where} + GROUP BY payto + """, params) + overview = [dict(r) for r in cur.fetchall()] + + # 按类型汇总 + cur.execute(f""" + SELECT paytype, payto, + COUNT(*) as count, + SUM(CAST(paysize AS REAL)) as total + FROM zhangdan {where} + GROUP BY paytype, payto + ORDER BY total DESC + """, params) + by_type = [dict(r) for r in cur.fetchall()] + + # 按渠道汇总 + cur.execute(f""" + SELECT payqd, payto, + COUNT(*) as count, + SUM(CAST(paysize AS REAL)) as total + FROM zhangdan {where} + GROUP BY payqd, payto + ORDER BY total DESC + """, params) + by_channel = [dict(r) for r in cur.fetchall()] + + # 按钱包汇总 + cur.execute(f""" + SELECT paybox, payto, + COUNT(*) as count, + SUM(CAST(paysize AS REAL)) as total + FROM zhangdan {where} + GROUP BY paybox, payto + ORDER BY total DESC + """, params) + by_wallet = [dict(r) for r in cur.fetchall()] + + conn.close() + return jsonify({ + "overview": overview, + "by_type": by_type, + "by_channel": by_channel, + "by_wallet": by_wallet, + }) + + +@app.route("/api/filters") +@login_required +def api_filters(): + """获取所有可选的筛选值""" + conn = get_db() + cur = conn.cursor() + result = {} + for col in ["payto", "payqd", "paybox", "paytype"]: + cur.execute(f"SELECT DISTINCT {col} FROM zhangdan ORDER BY {col}") + result[col] = [r[0] for r in cur.fetchall()] + conn.close() + return jsonify(result) + + + +LOGIN_TEMPLATE = r""" + + + + +🔐 验证身份 + + + + +

+ + + + +""" + +HTML_TEMPLATE = r""" + + + + +💰 账单查询 + + + + +
+ + + + +"""