From 7a58497e5f8c2ee6b5abc5683353b1a576c77463 Mon Sep 17 00:00:00 2001 From: SlyAimer <2289782085@qq.com> Date: Mon, 31 Mar 2025 17:59:30 +0800 Subject: [PATCH] =?UTF-8?q?feat(jm):=20=E6=B7=BB=E5=8A=A0JM=E6=BC=AB?= =?UTF-8?q?=E7=94=BB=E4=B8=8B=E8=BD=BD=E5=8A=9F=E8=83=BD=E5=8F=8A=E7=9B=B8?= =?UTF-8?q?=E5=85=B3=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增jm_download插件、jm_comic核心下载逻辑、disguise_pdf文件处理工具 扩展delete_file功能,添加批量删除和文件夹删除方法 更新路径配置和菜单选项 --- requirements.txt | 3 ++ src/clover_image/delete_file.py | 26 ++++++++++++- src/clover_jm/disguise_pdf.py | 65 ++++++++++++++++++++++++++++++++ src/clover_jm/jm_comic.py | 28 ++++++++++++++ src/configs/path_config.py | 3 ++ src/plugins/check.py | 4 +- src/plugins/jm_download.py | 15 ++++++++ src/resources/image/jm/temp.jpg | Bin 0 -> 2790 bytes 8 files changed, 141 insertions(+), 3 deletions(-) create mode 100644 src/clover_jm/disguise_pdf.py create mode 100644 src/clover_jm/jm_comic.py create mode 100644 src/plugins/jm_download.py create mode 100644 src/resources/image/jm/temp.jpg diff --git a/requirements.txt b/requirements.txt index b358581..ba0c4ee 100644 --- a/requirements.txt +++ b/requirements.txt @@ -26,6 +26,9 @@ nonebot-plugin-htmlrender tenacity paramiko +commonX +jmcomic +natsort requests pillow diff --git a/src/clover_image/delete_file.py b/src/clover_image/delete_file.py index 9260815..b39e5cd 100644 --- a/src/clover_image/delete_file.py +++ b/src/clover_image/delete_file.py @@ -1,4 +1,6 @@ import os +import asyncio +import shutil async def delete_file(file_path): @@ -7,4 +9,26 @@ async def delete_file(file_path): except FileNotFoundError: print(f"文件 {file_path} 不存在。") except Exception as e: - print(f"删除文件时发生错误: {e}") \ No newline at end of file + print(f"删除文件时发生错误: {e}") + + +async def delete_file_batch(file_paths): + """ + 批量删除文件的异步函数(并行版本) + + :param file_paths: 需要删除的文件路径列表 + """ + tasks = [delete_file(path) for path in file_paths] + results = await asyncio.gather(*tasks, return_exceptions=True) + + for path, result in zip(file_paths, results): + if isinstance(result, Exception): + print(f"删除 {path} 失败: {result}") + +async def delete_folder(folder_path): + try: + shutil.rmtree(folder_path) + except FileNotFoundError: + print(f"文件夹 {folder_path} 不存在。") + except Exception as e: + print(f"删除文件夹时发生错误: {e}") \ No newline at end of file diff --git a/src/clover_jm/disguise_pdf.py b/src/clover_jm/disguise_pdf.py new file mode 100644 index 0000000..20d9de6 --- /dev/null +++ b/src/clover_jm/disguise_pdf.py @@ -0,0 +1,65 @@ +import os +import zipfile +from PIL import Image +from natsort import natsorted + + +async def webp_to_pdf(input_folder, output_pdf): + """ + WebP转PDF + """ + webp_files = natsorted( + [os.path.join(input_folder, f) for f in os.listdir(input_folder) + if f.lower().endswith('.webp')], + key=lambda x: os.path.basename(x) + ) + + if not webp_files: + print("未找到WebP图片") + # raise ValueError("未找到WebP图片") + + images = [] + for webp_file in webp_files: + try: + img = Image.open(webp_file) + # 处理透明背景 + if img.mode in ('RGBA', 'LA'): + white_bg = Image.new('RGB', img.size, (255, 255, 255)) + white_bg.paste(img, mask=img.split()[-1]) + images.append(white_bg) + else: + images.append(img.convert('RGB')) + except Exception as e: + print(f"处理失败 {webp_file}: {e}") + + if not images: + print("无有效图片") + # raise ValueError("无有效图片") + + images[0].save( + output_pdf, + save_all=True, + append_images=images[1:], + optimize=True, + quality=85 + ) + return output_pdf + + + +async def zip_pdf(pdf_path, zip_path): + try: + with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf: + arcname = os.path.basename(pdf_path) + zipf.write(pdf_path, arcname=arcname) + except Exception as e: + print(f"压缩PDF时出错: {e}") + + +async def merge_files(jpg_path, zip_path, output_path): + try: + 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(zip_file.read()) + except Exception as e: + print(f"合并文件时出错: {e}") diff --git a/src/clover_jm/jm_comic.py b/src/clover_jm/jm_comic.py new file mode 100644 index 0000000..3859ce7 --- /dev/null +++ b/src/clover_jm/jm_comic.py @@ -0,0 +1,28 @@ +import jmcomic +from src.clover_jm.disguise_pdf import * +from src.configs.path_config import jm_path +from src.clover_image.delete_file import delete_file_batch,delete_folder + +async def download_jm(album_id: str| None): + + album_detail,downloader = jmcomic.download_album(album_id) + + original_path = os.getcwd()+f"/{album_detail.title}" + # 将图片转换为PDF + await webp_to_pdf(original_path,jm_path +f"{album_id}.pdf") + pdf_file = jm_path + f"{album_id}.pdf" + jpg_file = jm_path + 'temp.jpg' + zip_file = jm_path + "resume.zip" + output_file = jm_path +"merged.jpg" + + if os.path.exists(pdf_file) and os.path.exists(jpg_file): + await zip_pdf(pdf_file, zip_file) + await merge_files(jpg_file, zip_file, output_file) + + await delete_file_batch([zip_file, pdf_file]) + await delete_folder(original_path) + else: + print("PDF文件或JPG文件不存在,请检查文件路径。") + + return output_file + diff --git a/src/configs/path_config.py b/src/configs/path_config.py index 99f0865..4cd5648 100644 --- a/src/configs/path_config.py +++ b/src/configs/path_config.py @@ -31,6 +31,9 @@ os.makedirs(font_path, exist_ok=True) # 临时数据路径 temp_path = path + '/temp/' os.makedirs(temp_path, exist_ok=True) +# JM发送 图片模板 +jm_path = path + '/image/jm/' +os.makedirs(jm_path, exist_ok=True) # 日志路径 log_path = path+'/log/' os.makedirs(log_path, exist_ok=True) diff --git a/src/plugins/check.py b/src/plugins/check.py index 179ef33..27e54b1 100644 --- a/src/plugins/check.py +++ b/src/plugins/check.py @@ -10,11 +10,11 @@ from src.clover_sqlite.models.user import UserList menu = ["/重启","/今日运势","/今日塔罗","/图","/随机图","/搜番","/日报","/点歌","/摸摸头","/群老婆","/今日老婆", "/开启ai","/关闭ai","/角色列表","/添加人设", "/更新人设", "/删除人设", "/切换人设", "/管理员注册", "/待办", "/test","/天气","我喜欢你", "❤", "/待办查询", "/新建待办", "/删除待办" ,"/cf","/B站搜索", "/BV搜索", "/喜报", "/悲报", "/luxun","/鲁迅说", - "/奶龙", "/repo", "/info", "/menu", "/轻小说","/本季新番","/下季新番","/新番观察","/绝对色感"] + "/奶龙", "/repo", "/info", "/menu", "/轻小说","/本季新番","/下季新番","/新番观察","/绝对色感" ,"/jm"] send_menu = ["/menu","/今日运势","/今日塔罗","/图","/随机图","搜番","/日报","/点歌","/摸摸头","/群老婆","/待办","/天气", "/待办查询", "/新建待办", "/删除待办" ,"/cf","/B站搜索", "/BV搜索", "/喜报", "/悲报","/鲁迅说", - "/轻小说","/本季新番","/新番观察","/下季新番","/绝对色感"] + "/轻小说","/本季新番","/新番观察","/下季新番","/绝对色感","/jm"] async def check_value_in_menu(message: MessageEvent) -> bool: value = message.get_plaintext().strip().split(" ") diff --git a/src/plugins/jm_download.py b/src/plugins/jm_download.py new file mode 100644 index 0000000..2ffa860 --- /dev/null +++ b/src/plugins/jm_download.py @@ -0,0 +1,15 @@ +from pathlib import Path +from nonebot.rule import to_me +from nonebot.plugin import on_command +from nonebot.adapters.qq import MessageSegment,MessageEvent +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.handle() +async def handle_function(message: MessageEvent): + key = message.get_plaintext().replace("/jm", "").strip(" ") + + output_file = await download_jm(key) + await jm.send(MessageSegment.file_image(Path(output_file))) + await delete_file(output_file) diff --git a/src/resources/image/jm/temp.jpg b/src/resources/image/jm/temp.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6c2cd9bc68599f1c23cabe0933a5021b1a89ebf4 GIT binary patch literal 2790 zcmbW1e>~Is9>>44&Ddy-kR>9&ij~5sgV)QPCk zPuu!2?PQ{(IL*&&2W_s@BHIXe zt?C`HI>;~34}d@*zyY-ZDluT;n@v6n03jj3W&i-R)HOW-s?H#4`$H-b-~(ttAS?c- zpm6AlG+{6(9HEIotb~>}N?S_{sf9owb&*Jvj#>!qRcKwERV(?*AuHo6Q)<`ILTIgY z{BKhI0${WN6QBeNu>dqM5GV$sY6r~JyTa8(D^Pz5q5*}$HPtI2QR)WPYW4b1sD^r3 zI1HxlKBKM!FbrJJe4Cf1e%L{T#ql-U&z4`;+UR}%xxrq6%+m2tTCO(I&}gkO*2>z( zcGG4jXS|E+j-5VxeEs|b0)vR*5s{>*ebI*#jvP%)A}6P3WS+>%K6xrH|NDZ%b4A4! zl@~5nUHb8->Ys1a)!%GrymkA*!xk2s^XT!DHh%kyj?S0AcJ=o44-5{y9Ttiu7X*O*3+pek|KP%?xir*o07I;BK{T?|0mZ=J=G!#&yuuI% zkLz1(KdZIIyZrk7=h_<`_sR?or3sLRmQG?T`3l+}Wd9vl?*B#h7udhKgn$kdqJBIm z2Jirum;TXt>ze=hoGU|o57|DCQsLIN6rx!8$<$p|Sdj6_l@&{h=w(qEOJ#gxmX;nI z6KGN$RT;`X@~!wlfi~3ffS8>p_CWBG39CT6Q1Eh7v?8<5=?o%379@qcuT=_&iep1@ z(%pXWu$04hMM36O@%UW__6`WTyYeil_ue3+?_Zm?9GkprdJ!x?sRH0|kRkInLz0cm z*eu(M4;b-}jB=C)x>Fw{+{ynS>*ttovc zy{8uIw!Vp6RfCixa_3U$%KZD1<^G>As9UJCN54U@|5ohq8>`T6yDNzCquAaT&rAd$F$M&c4>a` z;>8Hq zI#Jd#n(LX40o|E~TK1C%I&7iyM=O)=cFmkM-NFS$Vlz~fPop9jym*~|C;N${&ku~3 zk3|ev4;hreQPu%UX%HvNVuNJ%p~zDOJqjd&X0c={ArF2tPeTNJdA-jAKuHsNC~egK5yQko-7p9@e|Cm}H9Gg(G)C_2D0?_B;^qa*(vl~d zp1IcNJB)>--$GCOayasE2Y!kzXBSRfWB}7)QuM?D2&wyB)>DFZ8#EjI9n6 z&*Rasy(~FC5zlDG3&V-lVe1KVbG3S`7rf#LdDD}J-Kh%; z)mJWU-~W@PwV7=rS>v|-!ARF}PmM-{PZvTF-EmkIkek|&@4Txy{Tr}bo{C-{Ti>4| z=_us)O1CwSv=c`+doP7O@cK68SY!yBKXH#EVsSev*FCS51(u;dX3hU9;T4hx5D@MgPYUxi+pO?Z z-@Z#>1?DvsMtCqJ10n*&N1B# z^*8l=3ti7gUPhG1UA$qY6O~fxXQCnphlxg-e>6-V3OKR)2Rn-KC8#= zafv(V8!e>VN@$_9zI<7@dcQa0UTP#PuR)9+&heAAHk6r8lH}IBCWSwl6gB9)tFB^p zY9b*3w;`Nio;xbsvF}i+YyXj&K(}A(tM~2RTnxOFndLRpO+bBL+46{z+CgV~PvAb%@jK1*Uz$(ZUPG&f{|Rxo1bqMi literal 0 HcmV?d00001