|
| 1 | +from .config import os,json,USERSET,LOCALDATE,THISPATH,log,Optional,Union,Tuple,repath,init_path |
| 2 | +init_path() |
| 3 | + |
| 4 | +import zipfile |
| 5 | +import xml.etree.ElementTree as ET |
| 6 | +import shutil |
| 7 | + |
| 8 | +from cairosvg import svg2png |
| 9 | +from PIL import Image |
| 10 | + |
| 11 | +class PathTool: |
| 12 | + def __init__(self,fp:Optional[str|tuple[str, str]]=None,mode='p'): |
| 13 | + '''mode = 'p': fp是一个文件路径; |
| 14 | + mode = 'n': fp是一个文件名; |
| 15 | + mode = 'd': fp是一个目录路径; |
| 16 | + mode = 'j': 只合并路径,fp的类型为tuple[str,str]。''' |
| 17 | + if fp: |
| 18 | + if isinstance(fp,str): |
| 19 | + fp=os.path.normpath(fp) |
| 20 | + self.NAME:str |
| 21 | + match mode: |
| 22 | + case 'p': |
| 23 | + self.DIR=os.path.dirname(fp) |
| 24 | + self.FILE=os.path.basename(fp) |
| 25 | + self.NAME,self.SUFFIX=os.path.splitext(self.FILE) |
| 26 | + case 'n': |
| 27 | + self.FILE=fp |
| 28 | + self.NAME,self.SUFFIX=os.path.splitext(fp) |
| 29 | + case 'd': |
| 30 | + self.DIR=fp |
| 31 | + self.NAME=os.path.basename(fp) |
| 32 | + elif mode=='j': |
| 33 | + self.j=os.path.join(*(os.path.normpath(p) for p in fp)) |
| 34 | + def rmlog(self,dirpath:str,count:int=0): |
| 35 | + # 获取目录中的所有文件 |
| 36 | + files = os.listdir(dirpath) |
| 37 | + if len(files) >= count: |
| 38 | + # 过滤出文件,而不是目录 |
| 39 | + files = [f for f in files if os.path.isfile(os.path.join(dirpath, f))] |
| 40 | + if count: |
| 41 | + # 获取每个文件的修改时间,并按照修改时间排序 |
| 42 | + files.sort(key=lambda f: os.path.getmtime(os.path.join(dirpath, f))) |
| 43 | + for i in range(count): |
| 44 | + os.remove(os.path.join(dirpath,files[i])) |
| 45 | + else: |
| 46 | + for f in files: |
| 47 | + os.remove(os.path.join(dirpath,f)) |
| 48 | + def join(self,args:Union[str,Tuple[str,...]]=("",)): |
| 49 | + if hasattr(PathTool,'j'): |
| 50 | + return self.j |
| 51 | + elif args and len(args)!= 0: |
| 52 | + return os.path.join(*(os.path.normpath(p) for p in args)) |
| 53 | + |
| 54 | +LOGPATH=PathTool().join((USERSET['log']['outdir'] if USERSET['log']['outdir'] != "default" else "./../../log",LOCALDATE+".log")) #type: ignore |
| 55 | +LOGDIR=os.path.dirname(LOGPATH) |
| 56 | + |
| 57 | +class UnPackingScratch3File: |
| 58 | + def __init__(self,fp:str): |
| 59 | + """ |
| 60 | + 解包.sb3文件。 |
| 61 | + |
| 62 | + :param fp: .sb3文件位置 |
| 63 | + """ |
| 64 | + log.debug(f"Unpacking {repath(fp)}...") |
| 65 | + with zipfile.ZipFile(fp,'r') as self.f: #解压.sb3文件 |
| 66 | + if os.path.basename(fp)!=fp: #如果是一段路径 |
| 67 | + self.p=PathTool(fp) |
| 68 | + self.cdir=self.p.join((self.p.DIR,self.p.NAME)) |
| 69 | + else: #如果是一段文件名 |
| 70 | + self.p=PathTool(fp,mode='n') |
| 71 | + self.cdir=self.p.join((THISPATH,self.p.NAME)) |
| 72 | + self.f.extractall(self.cdir) |
| 73 | + |
| 74 | + #格式化.json文档 |
| 75 | + self.prj_path=self.p.join((self.cdir,'project.json')) |
| 76 | + with open(self.prj_path,'r',encoding='utf-8') as f: |
| 77 | + c=json.load(f) |
| 78 | + with open(self.prj_path,'w',encoding='utf-8') as f: |
| 79 | + json.dump(c,f,ensure_ascii=False,indent=4) |
| 80 | + log.success(f"Completed unpacking {repath(fp)} -> {repath(self.cdir)}.") |
| 81 | + |
| 82 | + def convert(self): |
| 83 | + self.outdir=self.p.join((self.cdir,'output')) |
| 84 | + os.makedirs(self.outdir,exist_ok=True) |
| 85 | + for fn in os.listdir(self.cdir): #批量转换 |
| 86 | + p=PathTool(fn,'n') |
| 87 | + if p.SUFFIX=='.svg': |
| 88 | + fp=p.join((self.cdir,p.FILE)) |
| 89 | + #with open(p.join((self.cdir,p.FILE)), 'r',encoding='utf-8') as f: |
| 90 | + # svg_size = surface.SVGSurface(f.read(),).width, surface.SVGSurface(p.join((self.cdir,p.FILE))).height |
| 91 | + tree = ET.parse(fp) |
| 92 | + root = tree.getroot() |
| 93 | + svg_size = float(root.attrib['width']), float(root.attrib['height']) |
| 94 | + png_path = p.join((self.cdir,"output",p.NAME+".png")) |
| 95 | + if svg_size != (0,0): |
| 96 | + log.debug(f"The size of {repath(fp)} is {svg_size}.") |
| 97 | + svg2png(url=fp, |
| 98 | + write_to=png_path, |
| 99 | + unsafe=True, |
| 100 | + parent_width=svg_size[0], |
| 101 | + parent_height=svg_size[1]) |
| 102 | + else: |
| 103 | + log.warning(f"{fn} has no size!") |
| 104 | + image = Image.new("RGB",(1, 1),(0,0,0)) |
| 105 | + image.save(png_path) |
| 106 | + #os.remove(p.join((self.cdir,p.FILE))) |
| 107 | + #log.success(f"Removed {p.join((self.cdir,p.FILE))}.") |
| 108 | + log.success(f"Converted {repath(fp)} -> {repath(png_path)}.") |
| 109 | + |
| 110 | + |
| 111 | +class PackingScratch3File: |
| 112 | + def __init__(self,dp:str): |
| 113 | + """ |
| 114 | + 打包.sb3文件。 |
| 115 | + |
| 116 | + :param dp: .sb3文件解包后文件夹位置 |
| 117 | + """ |
| 118 | + log.debug(f"Packing {dp}...") |
| 119 | + self.p=PathTool(dp,'d') |
| 120 | + fp=['project.json'] |
| 121 | + with open(self.p.join((self.p.DIR,'project.json')),'r',encoding='utf-8') as f: |
| 122 | + c=json.load(f) |
| 123 | + for t in c['targets']: |
| 124 | + for i in t['costumes']: |
| 125 | + if i['md5ext'] in os.listdir(self.p.DIR): |
| 126 | + fp.append(i['md5ext']) |
| 127 | + for s in t['sounds']: |
| 128 | + if s['md5ext'] in os.listdir(self.p.DIR): |
| 129 | + fp.append(s['md5ext']) |
| 130 | + self.outdir=self.p.join((self.p.DIR,'output')) |
| 131 | + os.makedirs(self.outdir,exist_ok=True) |
| 132 | + self.outfile=self.p.join((self.outdir,self.p.NAME+'.sb3')) |
| 133 | + with zipfile.ZipFile(self.outfile,'w') as f: |
| 134 | + for i in fp: |
| 135 | + f.write(self.p.join((self.p.DIR,i)),i) |
| 136 | + log.success(f"Completed packing {repath(dp)} -> {repath(self.outfile)}.") |
0 commit comments