mirror of
https://github.com/ClovertaTheTrilobita/SanYeCao-Nonebot.git
synced 2026-04-01 22:04:51 +00:00
fix(ai_chat): 移除测试代码
feat(jm): 新增邮件发送功能及配置管理 feat(config): 新增jm配置文件 feat(email): 新增邮件发送模块 chore(.gitignore): 添加jm图片目录忽略 chore(requirements): 添加aiosmtplib依赖 refactor(jm_comic): 重构下载逻辑改为邮件发送 refactor(path_config): 更新jm配置路径 refactor(jm_download): 适配新下载逻辑并添加邮箱验证
This commit is contained in:
parent
c49139607e
commit
e70b262402
10 changed files with 347 additions and 41 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -27,3 +27,4 @@ bili.cookie
|
||||||
src/clover_lightnovel/wenku8.cookie
|
src/clover_lightnovel/wenku8.cookie
|
||||||
src/clover_lightnovel/output1.html
|
src/clover_lightnovel/output1.html
|
||||||
*.pyc
|
*.pyc
|
||||||
|
/src/resources/image/jm/*
|
||||||
|
|
@ -29,6 +29,7 @@ paramiko
|
||||||
commonX
|
commonX
|
||||||
jmcomic
|
jmcomic
|
||||||
natsort
|
natsort
|
||||||
|
aiosmtplib
|
||||||
|
|
||||||
requests
|
requests
|
||||||
pillow
|
pillow
|
||||||
|
|
|
||||||
191
src/clover_email/send_email.py
Normal file
191
src/clover_email/send_email.py
Normal file
|
|
@ -0,0 +1,191 @@
|
||||||
|
import os
|
||||||
|
from email.mime.multipart import MIMEMultipart
|
||||||
|
from email.mime.application import MIMEApplication
|
||||||
|
from email.mime.text import MIMEText
|
||||||
|
import aiosmtplib
|
||||||
|
from src.configs.api_config import google_smtp_server,google_email,google_password
|
||||||
|
from src.configs.api_config import qq_smtp_server,qq_email,qq_password
|
||||||
|
|
||||||
|
# 发送内容
|
||||||
|
html = """
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>健康小贴士</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', 'Microsoft YaHei', sans-serif;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
min-height: 100vh;
|
||||||
|
color: #333;
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.1);
|
||||||
|
padding: 30px;
|
||||||
|
max-width: 500px;
|
||||||
|
width: 90%;
|
||||||
|
text-align: center;
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container:hover {
|
||||||
|
transform: translateY(-5px);
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: #ff6b6b;
|
||||||
|
font-size: 2.2rem;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
bottom: -10px;
|
||||||
|
left: 50%;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
width: 60px;
|
||||||
|
height: 3px;
|
||||||
|
background: linear-gradient(90deg, #ff6b6b, #ff8e8e);
|
||||||
|
border-radius: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: 1.1rem;
|
||||||
|
margin: 25px 0;
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emoji {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin: 0 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip-box {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
border-left: 4px solid #74b9ff;
|
||||||
|
padding: 15px;
|
||||||
|
margin: 20px 0;
|
||||||
|
text-align: left;
|
||||||
|
border-radius: 0 8px 8px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
margin-top: 30px;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: #777;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
h1 {
|
||||||
|
font-size: 1.8rem;
|
||||||
|
}
|
||||||
|
p {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1>可别<span class="emoji">🦌</span>死了</h1>
|
||||||
|
<p>作案前记得洗手,适度使用手动挡,别让发动机过热抛锚。</p>
|
||||||
|
|
||||||
|
<div class="tip-box">
|
||||||
|
<strong>健康小贴士:</strong> 适度有益健康,过度可能影响日常生活。保持良好卫生习惯,合理安排时间哦~
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"""
|
||||||
|
async def send_email_by_google(receiver_email: str, file_path: str):
|
||||||
|
"""发送单个文件附件邮件(Google版)"""
|
||||||
|
msg = MIMEMultipart()
|
||||||
|
msg["From"] = google_email
|
||||||
|
msg["To"] = receiver_email
|
||||||
|
msg["Subject"] = "您的快递已送达"
|
||||||
|
msg.attach(MIMEText(html, "html", "utf-8"))
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 验证文件存在性
|
||||||
|
if not os.path.isfile(file_path):
|
||||||
|
print(f"文件不存在:{file_path}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 添加单个文件附件
|
||||||
|
file_name = os.path.basename(file_path)
|
||||||
|
with open(file_path, "rb") as f:
|
||||||
|
attachment = MIMEApplication(f.read())
|
||||||
|
attachment.add_header(
|
||||||
|
"Content-Disposition",
|
||||||
|
"attachment",
|
||||||
|
filename=file_name
|
||||||
|
)
|
||||||
|
msg.attach(attachment)
|
||||||
|
|
||||||
|
async with aiosmtplib.SMTP(
|
||||||
|
hostname=google_smtp_server,
|
||||||
|
port=465,
|
||||||
|
timeout=60,
|
||||||
|
use_tls=True
|
||||||
|
) as server:
|
||||||
|
await server.login(google_email, google_password)
|
||||||
|
await server.send_message(msg)
|
||||||
|
print("文件邮件发送成功!")
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"邮件发送失败: {str(e)}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
async def send_email_by_qq(receiver_email: str, file_path: str):
|
||||||
|
"""发送单个文件附件邮件(QQ版)"""
|
||||||
|
msg = MIMEMultipart()
|
||||||
|
msg["From"] = qq_email
|
||||||
|
msg["To"] = receiver_email
|
||||||
|
msg["Subject"] = "您的快递已送达"
|
||||||
|
msg.attach(MIMEText(html, "html", "utf-8"))
|
||||||
|
|
||||||
|
try:
|
||||||
|
if not os.path.exists(file_path):
|
||||||
|
print(f"文件不存在:{file_path}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# 添加附件
|
||||||
|
file_name = os.path.basename(file_path)
|
||||||
|
with open(file_path, "rb") as f:
|
||||||
|
attachment = MIMEApplication(f.read())
|
||||||
|
attachment.add_header(
|
||||||
|
"Content-Disposition",
|
||||||
|
"attachment",
|
||||||
|
filename=file_name
|
||||||
|
)
|
||||||
|
msg.attach(attachment)
|
||||||
|
|
||||||
|
async with aiosmtplib.SMTP(
|
||||||
|
hostname=qq_smtp_server,
|
||||||
|
port=465,
|
||||||
|
use_tls=True,
|
||||||
|
timeout=30
|
||||||
|
) as server:
|
||||||
|
await server.login(qq_email, qq_password)
|
||||||
|
await server.send_message(msg)
|
||||||
|
print("QQ文件邮件发送成功!")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"QQ邮件发送失败: {str(e)}")
|
||||||
|
return False
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import os
|
import os
|
||||||
|
import asyncio
|
||||||
import zipfile
|
import zipfile
|
||||||
|
from pathlib import Path
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
from natsort import natsorted
|
from natsort import natsorted
|
||||||
|
|
||||||
|
|
@ -16,7 +18,6 @@ async def webp_to_pdf(input_folder, output_pdf):
|
||||||
|
|
||||||
if not webp_files:
|
if not webp_files:
|
||||||
print("未找到WebP图片")
|
print("未找到WebP图片")
|
||||||
# raise ValueError("未找到WebP图片")
|
|
||||||
|
|
||||||
images = []
|
images = []
|
||||||
for webp_file in webp_files:
|
for webp_file in webp_files:
|
||||||
|
|
@ -34,20 +35,53 @@ async def webp_to_pdf(input_folder, output_pdf):
|
||||||
|
|
||||||
if not images:
|
if not images:
|
||||||
print("无有效图片")
|
print("无有效图片")
|
||||||
# raise ValueError("无有效图片")
|
|
||||||
|
|
||||||
images[0].save(
|
images[0].save(
|
||||||
output_pdf,
|
output_pdf,
|
||||||
save_all=True,
|
save_all=True,
|
||||||
append_images=images[1:],
|
append_images=images[1:],
|
||||||
optimize=True,
|
optimize=True,
|
||||||
quality=85
|
quality=80
|
||||||
)
|
)
|
||||||
return output_pdf
|
|
||||||
|
|
||||||
|
async def batch_convert_subfolders(base_dir,output_dir):
|
||||||
|
"""
|
||||||
|
批量转换指定目录下所有子文件夹中的WebP图片为独立PDF
|
||||||
|
:param base_dir: 要扫描的根目录,默认当前目录
|
||||||
|
:param output_dir: PDF输出目录
|
||||||
|
"""
|
||||||
|
subfolders = [
|
||||||
|
f for f in os.listdir(base_dir)
|
||||||
|
if os.path.isdir(os.path.join(base_dir, f))
|
||||||
|
and not f.startswith('.')
|
||||||
|
and f != os.path.basename(output_dir)
|
||||||
|
]
|
||||||
|
|
||||||
|
if not subfolders:
|
||||||
|
print("未找到有效子文件夹")
|
||||||
|
return
|
||||||
|
|
||||||
|
tasks = []
|
||||||
|
for folder in subfolders:
|
||||||
|
input_path = os.path.join(base_dir, folder)
|
||||||
|
output_pdf = os.path.join(output_dir, f"{folder}.pdf")
|
||||||
|
tasks.append(
|
||||||
|
webp_to_pdf(input_path, output_pdf)
|
||||||
|
)
|
||||||
|
|
||||||
|
results = await asyncio.gather(*tasks, return_exceptions=True)
|
||||||
|
success = 0
|
||||||
|
for folder, result in zip(subfolders, results):
|
||||||
|
if isinstance(result, Exception):
|
||||||
|
print(f"转换失败 [{folder}]: {str(result)}")
|
||||||
|
else:
|
||||||
|
print(f"成功转换: {folder} -> {result}")
|
||||||
|
success += 1
|
||||||
|
|
||||||
async def zip_pdf(pdf_path, zip_path):
|
async def zip_pdf(pdf_path, zip_path):
|
||||||
|
"""
|
||||||
|
压缩单文件
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
|
with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
|
||||||
arcname = os.path.basename(pdf_path)
|
arcname = os.path.basename(pdf_path)
|
||||||
|
|
@ -57,9 +91,46 @@ async def zip_pdf(pdf_path, zip_path):
|
||||||
|
|
||||||
|
|
||||||
async def merge_files(jpg_path, zip_path, output_path):
|
async def merge_files(jpg_path, zip_path, output_path):
|
||||||
|
"""
|
||||||
|
将PDF伪装成图片
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
with open(jpg_path, 'rb') as jpg_file, open(zip_path, 'rb') as zip_file, open(output_path,'wb') as output_file:
|
with open(jpg_path, 'rb') as jpg_file, open(zip_path, 'rb') as zip_file, open(output_path,'wb') as output_file:
|
||||||
output_file.write(jpg_file.read())
|
output_file.write(jpg_file.read())
|
||||||
output_file.write(zip_file.read())
|
output_file.write(zip_file.read())
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"合并文件时出错: {e}")
|
print(f"合并文件时出错: {e}")
|
||||||
|
|
||||||
|
async def folder_zip(folder_path, jm_zip_path):
|
||||||
|
"""
|
||||||
|
异步压缩整个文件夹到指定路径
|
||||||
|
:param folder_path: 需要压缩的文件夹路径
|
||||||
|
:param jm_zip_path: 输出的zip文件路径
|
||||||
|
:return: 压缩成功返回True,否则返回False
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
Path(jm_zip_path).parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
def sync_zip():
|
||||||
|
with zipfile.ZipFile(jm_zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
|
||||||
|
|
||||||
|
for root, dirs, files in os.walk(folder_path):
|
||||||
|
|
||||||
|
relative_path = Path(root).relative_to(folder_path)
|
||||||
|
|
||||||
|
for dir_name in dirs:
|
||||||
|
abs_dir = os.path.join(root, dir_name)
|
||||||
|
zipf.write(abs_dir, arcname=str(relative_path / dir_name))
|
||||||
|
|
||||||
|
for file in files:
|
||||||
|
file_path = os.path.join(root, file)
|
||||||
|
arcname = str(relative_path / file)
|
||||||
|
zipf.write(file_path, arcname=arcname)
|
||||||
|
|
||||||
|
loop = asyncio.get_running_loop()
|
||||||
|
await loop.run_in_executor(None, sync_zip)
|
||||||
|
print(f"成功压缩文件夹到: {jm_zip_path}")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
print(f"压缩文件夹失败: {str(e)}")
|
||||||
|
return False
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,62 @@
|
||||||
|
import yaml
|
||||||
import jmcomic
|
import jmcomic
|
||||||
from src.clover_jm.disguise_pdf import *
|
from src.clover_jm.disguise_pdf import *
|
||||||
from src.configs.path_config import jm_path
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
from src.clover_image.delete_file import delete_file_batch,delete_folder
|
from src.configs.path_config import jm_path,jm_config_path
|
||||||
|
from src.clover_image.delete_file import delete_folder,delete_file
|
||||||
|
from src.clover_email.send_email import send_email_by_google,send_email_by_qq
|
||||||
|
|
||||||
async def download_jm(album_id: str| None):
|
# 创建线程池
|
||||||
|
jm_executor = ThreadPoolExecutor(max_workers=5)
|
||||||
|
jm_executor.submit(lambda: None).result()
|
||||||
|
|
||||||
album_detail,downloader = jmcomic.download_album(album_id)
|
async def download_jm(album_id: str| None,receiver_email: str| None):
|
||||||
|
# 修改配置文件的下载路径
|
||||||
original_path = os.getcwd()+f"/{album_detail.title}"
|
source_path = await get_jm_config(receiver_email)
|
||||||
# 将图片转换为PDF
|
option = jmcomic.JmOption.from_file(jm_config_path)
|
||||||
await webp_to_pdf(original_path,jm_path +f"{album_id}.pdf")
|
# 还原配置文件
|
||||||
pdf_file = jm_path + f"{album_id}.pdf"
|
await recover_jm_config(source_path)
|
||||||
jpg_file = jm_path + 'temp.jpg'
|
#调用JM下载api
|
||||||
zip_file = jm_path + "resume.zip"
|
album_detail,downloader = await asyncio.get_event_loop().run_in_executor(jm_executor,jmcomic.download_album,album_id,option)
|
||||||
output_file = jm_path +"merged.jpg"
|
if album_detail.title is None:
|
||||||
|
return "下载失败,请检查JM ID 是否正确"
|
||||||
if os.path.exists(pdf_file) and os.path.exists(jpg_file):
|
# 创建变量
|
||||||
await zip_pdf(pdf_file, zip_file)
|
folder_path = f"{jm_path}{receiver_email}"
|
||||||
await merge_files(jpg_file, zip_file, output_file)
|
zip_path = f"{jm_path}{album_detail.title}.zip"
|
||||||
|
# 压缩文件
|
||||||
await delete_file_batch([zip_file, pdf_file])
|
zip_status = await folder_zip(folder_path,zip_path)
|
||||||
await delete_folder(original_path)
|
if not zip_status:
|
||||||
|
await delete_folder(folder_path)
|
||||||
|
return "压缩文件失败"
|
||||||
|
# 发送邮件
|
||||||
|
send_status = await send_email_by_qq(receiver_email,zip_path)
|
||||||
|
if send_status:
|
||||||
|
# 删除文件
|
||||||
|
await delete_folder(folder_path)
|
||||||
|
await delete_file(zip_path)
|
||||||
|
return "发送成功,请注意查收\n如遇邮箱接收不到,请检查发送的邮箱是否正确,或者是否在垃圾箱"
|
||||||
else:
|
else:
|
||||||
print("PDF文件或JPG文件不存在,请检查文件路径。")
|
await delete_folder(folder_path)
|
||||||
|
await delete_file(zip_path)
|
||||||
|
return "发送邮件失败,请重试!"
|
||||||
|
|
||||||
return output_file
|
|
||||||
|
|
||||||
|
async def get_jm_config(receiver_email: str):
|
||||||
|
|
||||||
|
with open(jm_config_path, 'r', encoding='utf-8') as f:
|
||||||
|
config = yaml.safe_load(f)
|
||||||
|
source_path = config['dir_rule']['base_dir']
|
||||||
|
new_base_dir = str(Path(source_path) / receiver_email)
|
||||||
|
config['dir_rule']['base_dir'] = new_base_dir
|
||||||
|
with open(jm_config_path, 'w', encoding='utf-8') as f:
|
||||||
|
yaml.dump(config, f, sort_keys=False, allow_unicode=True)
|
||||||
|
return source_path
|
||||||
|
|
||||||
|
async def recover_jm_config(source_path : str):
|
||||||
|
|
||||||
|
with open(jm_config_path, 'r', encoding='utf-8') as f:
|
||||||
|
config = yaml.safe_load(f)
|
||||||
|
new_base_dir = str(Path(source_path))
|
||||||
|
config['dir_rule']['base_dir'] = new_base_dir
|
||||||
|
with open(jm_config_path, 'w', encoding='utf-8') as f:
|
||||||
|
yaml.dump(config, f, sort_keys=False, allow_unicode=True)
|
||||||
|
|
@ -70,6 +70,3 @@ async def silicon_flow(group_openid, content):
|
||||||
|
|
||||||
await GroupChatRole.save_chat_history(group_openid, {"role": "assistant", "content": reply_content})
|
await GroupChatRole.save_chat_history(group_openid, {"role": "assistant", "content": reply_content})
|
||||||
return reply_content
|
return reply_content
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
print(deepseek_chat("你拽什么啊?"))
|
|
||||||
|
|
|
||||||
3
src/configs/jm_config.yml
Normal file
3
src/configs/jm_config.yml
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
dir_rule:
|
||||||
|
base_dir: src\resources\image\jm
|
||||||
|
rule: Bd_Pname
|
||||||
|
|
@ -31,7 +31,7 @@ os.makedirs(font_path, exist_ok=True)
|
||||||
# 临时数据路径
|
# 临时数据路径
|
||||||
temp_path = path + '/temp/'
|
temp_path = path + '/temp/'
|
||||||
os.makedirs(temp_path, exist_ok=True)
|
os.makedirs(temp_path, exist_ok=True)
|
||||||
# JM发送 图片模板
|
# JM下载位置
|
||||||
jm_path = path + '/image/jm/'
|
jm_path = path + '/image/jm/'
|
||||||
os.makedirs(jm_path, exist_ok=True)
|
os.makedirs(jm_path, exist_ok=True)
|
||||||
# 日志路径
|
# 日志路径
|
||||||
|
|
@ -41,7 +41,8 @@ os.makedirs(log_path, exist_ok=True)
|
||||||
video_path = path+'/video/'
|
video_path = path+'/video/'
|
||||||
os.makedirs(video_path, exist_ok=True)
|
os.makedirs(video_path, exist_ok=True)
|
||||||
|
|
||||||
|
#jm配置文件路径
|
||||||
|
jm_config_path = os.getcwd()+'/src/configs/jm_config.yml'
|
||||||
|
|
||||||
# # 语音路径
|
# # 语音路径
|
||||||
# RECORD_PATH = Path() / "src" / "resources" / "record"
|
# RECORD_PATH = Path() / "src" / "resources" / "record"
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,26 @@
|
||||||
from pathlib import Path
|
import re
|
||||||
from nonebot.rule import to_me
|
from nonebot.rule import to_me
|
||||||
from nonebot.plugin import on_command
|
from nonebot.plugin import on_command
|
||||||
from nonebot.adapters.qq import MessageSegment,MessageEvent
|
from nonebot.adapters.qq import MessageEvent
|
||||||
from src.clover_jm.jm_comic import download_jm
|
from src.clover_jm.jm_comic import download_jm
|
||||||
from src.clover_image.delete_file import delete_file
|
|
||||||
|
|
||||||
jm = on_command("jm", rule=to_me(), priority=10,block=False)
|
jm = on_command("jm", rule=to_me(), priority=10,block=False)
|
||||||
@jm.handle()
|
@jm.handle()
|
||||||
async def handle_function(message: MessageEvent):
|
async def handle_function(message: MessageEvent):
|
||||||
await jm.send("正在下载中,请稍等")
|
|
||||||
key = message.get_plaintext().replace("/jm", "").strip(" ")
|
|
||||||
|
|
||||||
if key == "":
|
values = message.get_plaintext().replace("/jm", "").split(" ")
|
||||||
await jm.finish("请输入jm的id")
|
|
||||||
|
|
||||||
output_file = await download_jm(key)
|
if 3 > len(values) > 4:
|
||||||
await jm.send(MessageSegment.file_image(Path(output_file)))
|
await jm.finish("请输入正确的格式 /jm+id 或 /jm+id+邮箱号")
|
||||||
await delete_file(output_file)
|
else:
|
||||||
|
if not validate_email(values[2]):
|
||||||
|
await jm.finish("邮箱格式不正确!")
|
||||||
|
|
||||||
|
await jm.send("正在发送中,请稍等~")
|
||||||
|
msg = await download_jm(album_id = values[1],receiver_email = values[2])
|
||||||
|
await jm.finish(msg)
|
||||||
|
|
||||||
|
def validate_email(email: str) -> bool:
|
||||||
|
"""验证邮箱格式是否合法"""
|
||||||
|
EMAIL_REGEX = r"^[a-zA-Z0-9._%+-]+@([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}$"
|
||||||
|
return re.fullmatch(EMAIL_REGEX, email) is not None
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.7 KiB |
Loading…
Reference in a new issue