From ec3d93ece891cf68d668c7d8522c7e4c5222eca6 Mon Sep 17 00:00:00 2001 From: laggykiller Date: Tue, 6 Feb 2024 13:58:11 +0800 Subject: [PATCH] - Display warning if not default directory name... and contains files not related to sticker_convert - Only move files that seem to be related to sticker_convert - Code cleanup - Fix typing --- compile.py | 34 +++--- src/sticker_convert/definitions.py | 1 + .../downloaders/download_base.py | 13 ++- .../downloaders/download_kakao.py | 2 +- .../downloaders/download_line.py | 4 +- .../downloaders/download_signal.py | 7 +- .../downloaders/download_telegram.py | 2 +- src/sticker_convert/gui.py | 4 +- src/sticker_convert/job.py | 108 ++++++++++++------ .../uploaders/compress_wastickers.py | 7 +- .../uploaders/xcode_imessage.py | 26 ++--- .../utils/files/cache_store.py | 4 +- .../utils/files/metadata_handler.py | 69 ++++++++--- src/sticker_convert/utils/files/run_bin.py | 1 - tests/test_compression.py | 2 +- tests/test_download.py | 8 +- tests/test_export.py | 2 +- 17 files changed, 182 insertions(+), 112 deletions(-) diff --git a/compile.py b/compile.py index ab155a6..d95b62d 100755 --- a/compile.py +++ b/compile.py @@ -22,12 +22,12 @@ def osx_run_in_venv(cmd, get_stdout=False): else: return subprocess.run(sh_cmd + [venv_cmd + cmd]) -def search_wheel_in_dir(package: str, dir: str): - for i in os.listdir(dir): +def search_wheel_in_dir(package: str, dir: Path): + for i in dir.iterdir(): if i.startswith(package): return i -def copy_if_universal(wheel_name: str, in_dir: str, out_dir: str): +def copy_if_universal(wheel_name: str, in_dir: Path, out_dir: Path): if wheel_name.endswith('universal2.whl') or wheel_name.endswith('any.whl'): src_path = Path(in_dir, wheel_name) dst_path = Path( @@ -42,8 +42,8 @@ def copy_if_universal(wheel_name: str, in_dir: str, out_dir: str): else: return False -def create_universal_wheels(in_dir1, in_dir2, out_dir): - for wheel_name_1 in os.listdir(in_dir1): +def create_universal_wheels(in_dir1: Path, in_dir2: Path, out_dir: Path): + for wheel_name_1 in in_dir1.iterdir(): package = wheel_name_1.split('-')[0] wheel_name_2 = search_wheel_in_dir(package, in_dir2) if copy_if_universal(wheel_name_1, in_dir1, out_dir): @@ -53,16 +53,16 @@ def create_universal_wheels(in_dir1, in_dir2, out_dir): wheel_path_1 = Path(in_dir1, wheel_name_1) wheel_path_2 = Path(in_dir2, wheel_name_2) - subprocess.run(['delocate-fuse', wheel_path_1, wheel_path_2, '-w', out_dir]) + subprocess.run(['delocate-fuse', wheel_path_1, wheel_path_2, '-w', str(out_dir)]) print(f'Created universal wheel {wheel_path_1} {wheel_path_2}') - for wheel_name in os.listdir(out_dir): + for wheel_name in out_dir.iterdir(): wheel_name_new = wheel_name.replace('x86_64', 'universal2').replace('arm64', 'universal2') src_path = Path(out_dir, wheel_name) dst_path = Path(out_dir, wheel_name_new) - os.rename(src_path, dst_path) + src_path.rename(dst_path) print(f'Renamed universal wheel {dst_path}') def osx_install_universal2_dep(): @@ -70,14 +70,14 @@ def osx_install_universal2_dep(): shutil.rmtree('wheel_x64', ignore_errors=True) shutil.rmtree('wheel_universal2', ignore_errors=True) - os.mkdir('wheel_arm') - os.mkdir('wheel_x64') - os.mkdir('wheel_universal2') + Path('wheel_arm').mkdir() + Path('wheel_x64').mkdir() + Path('wheel_universal2').mkdir() osx_run_in_venv('python -m pip download --require-virtualenv -r requirements.txt --platform macosx_11_0_arm64 --only-binary=:all: -d wheel_arm') osx_run_in_venv('python -m pip download --require-virtualenv -r requirements.txt --platform macosx_11_0_x86_64 --only-binary=:all: -d wheel_x64') - create_universal_wheels('./wheel_arm', './wheel_x64', 'wheel_universal2') + create_universal_wheels(Path('./wheel_arm'), Path('./wheel_x64'), Path('wheel_universal2')) osx_run_in_venv('python -m pip install --require-virtualenv ./wheel_universal2/*') def nuitka(python_bin, arch): @@ -115,19 +115,21 @@ def nuitka(python_bin, arch): subprocess.run(cmd_list, shell=True) def win_patch(): - for i in os.listdir('sticker-convert.dist/av.libs'): + for i in Path('sticker-convert.dist/av.libs').iterdir(): file_path = Path('sticker-convert.dist', i) if file_path.is_file(): os.remove(file_path) def osx_patch(): # https://github.com/pyinstaller/pyinstaller/issues/5154#issuecomment-1567603461 - os.rename('sticker-convert.app/Contents/MacOS/sticker-convert', 'sticker-convert.app/Contents/MacOS/sticker-convert-cli') - with open('sticker-convert.app/Contents/MacOS/sticker-convert', 'w+') as f: + sticker_bin = Path('sticker-convert.app/Contents/MacOS/sticker-convert') + sticker_bin_cli = Path('sticker-convert.app/Contents/MacOS/sticker-convert-cli') + sticker_bin.rename(sticker_bin_cli) + with open(sticker_bin, 'w+') as f: f.write('#!/bin/bash\n') f.write('cd "$(dirname "$0")"\n') f.write('open ./sticker-convert-cli') - os.chmod('sticker-convert.app/Contents/MacOS/sticker-convert', 0o744) + os.chmod(sticker_bin, 0o744) osx_run_in_venv('codesign --force --deep -s - sticker-convert.app') diff --git a/src/sticker_convert/definitions.py b/src/sticker_convert/definitions.py index 46bbd0d..d25e874 100644 --- a/src/sticker_convert/definitions.py +++ b/src/sticker_convert/definitions.py @@ -1,3 +1,4 @@ +#!/usr/bin/env python3 import os import platform import sys diff --git a/src/sticker_convert/downloaders/download_base.py b/src/sticker_convert/downloaders/download_base.py index 0d7c99b..df016f3 100755 --- a/src/sticker_convert/downloaders/download_base.py +++ b/src/sticker_convert/downloaders/download_base.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 from __future__ import annotations +from pathlib import Path from multiprocessing.managers import BaseProxy from typing import Optional, Union @@ -13,7 +14,7 @@ class DownloadBase: def __init__( self, url: str, - out_dir: str, + out_dir: Path, opt_cred: Optional[CredOption] = None, cb: Union[BaseProxy, Callback, None] = None, cb_return: Optional[CallbackReturn] = None, @@ -23,11 +24,11 @@ def __init__( cb = Callback(silent=True) cb_return = CallbackReturn() - self.url = url - self.out_dir = out_dir - self.opt_cred = opt_cred - self.cb = cb - self.cb_return = cb_return + self.url: str = url + self.out_dir: Path = out_dir + self.opt_cred: Optional[CredOption] = opt_cred + self.cb: Union[BaseProxy, Callback, None] = cb + self.cb_return: Optional[CallbackReturn] = cb_return def download_multiple_files( self, targets: list[tuple[str, str]], retries: int = 3, **kwargs diff --git a/src/sticker_convert/downloaders/download_kakao.py b/src/sticker_convert/downloaders/download_kakao.py index a9654f2..bc13566 100755 --- a/src/sticker_convert/downloaders/download_kakao.py +++ b/src/sticker_convert/downloaders/download_kakao.py @@ -232,7 +232,7 @@ def download_animated(self, item_code: str) -> bool: @staticmethod def start( url: str, - out_dir: str, + out_dir: Path, opt_cred: Optional[CredOption] = None, cb: Union[BaseProxy, Callback, None] = None, cb_return: Optional[CallbackReturn] = None, diff --git a/src/sticker_convert/downloaders/download_line.py b/src/sticker_convert/downloaders/download_line.py index f142383..e7af8f8 100755 --- a/src/sticker_convert/downloaders/download_line.py +++ b/src/sticker_convert/downloaders/download_line.py @@ -324,7 +324,7 @@ def get_name_text_key(self, sticker_text: str) -> Optional[str]: return name_text_key def combine_custom_text(self): - for i in sorted(os.listdir(self.out_dir)): + for i in sorted(self.out_dir.iterdir()): if i.endswith('-text.png'): base_path = Path(self.out_dir, i.replace('-text.png', '.png')) text_path = Path(self.out_dir, i) @@ -394,7 +394,7 @@ def download_stickers_line(self) -> bool: @staticmethod def start( url: str, - out_dir: str, + out_dir: Path, opt_cred: Optional[CredOption] = None, cb: Union[BaseProxy, Callback, None] = None, cb_return: Optional[CallbackReturn] = None, diff --git a/src/sticker_convert/downloaders/download_signal.py b/src/sticker_convert/downloaders/download_signal.py index 491a347..992e1ec 100755 --- a/src/sticker_convert/downloaders/download_signal.py +++ b/src/sticker_convert/downloaders/download_signal.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -import os from pathlib import Path from typing import Optional, Union from multiprocessing.managers import BaseProxy @@ -47,8 +46,8 @@ def save_stickers(self, pack: StickerPack): msg = f"Warning: Downloaded {f_path} but cannot get file codec" self.cb.put(msg) else: - f_path_new = f"{f_path}.{codec}" - os.rename(f_path, f_path_new) + f_path_new = Path(f"{f_path}.{codec}") + f_path.rename(f_path_new) msg = f"Downloaded {f_id}.{codec}" self.cb.put(msg) @@ -77,7 +76,7 @@ def download_stickers_signal(self) -> bool: @staticmethod def start( url: str, - out_dir: str, + out_dir: Path, opt_cred: Optional[CredOption] = None, cb: Union[BaseProxy, Callback, None] = None, cb_return: Optional[CallbackReturn] = None, diff --git a/src/sticker_convert/downloaders/download_telegram.py b/src/sticker_convert/downloaders/download_telegram.py index 54ae72e..ac67572 100755 --- a/src/sticker_convert/downloaders/download_telegram.py +++ b/src/sticker_convert/downloaders/download_telegram.py @@ -104,7 +104,7 @@ async def save_stickers(self) -> bool: @staticmethod def start( url: str, - out_dir: str, + out_dir: Path, opt_cred: Optional[CredOption] = None, cb: Union[BaseProxy, Callback, None] = None, cb_return: Optional[CallbackReturn] = None, diff --git a/src/sticker_convert/gui.py b/src/sticker_convert/gui.py index bc8327a..c44ef15 100755 --- a/src/sticker_convert/gui.py +++ b/src/sticker_convert/gui.py @@ -575,7 +575,7 @@ def highlight_fields(self) -> bool: self.output_frame.output_setdir_entry.config(bootstyle='default') if (MetadataHandler.check_metadata_required(output_option, 'title') and - not MetadataHandler.check_metadata_provided(self.input_setdir_var.get(), input_option, 'title') and + not MetadataHandler.check_metadata_provided(Path(self.input_setdir_var.get()), input_option, 'title') and not self.title_var.get()): self.output_frame.title_entry.config(bootstyle='warning') @@ -583,7 +583,7 @@ def highlight_fields(self) -> bool: self.output_frame.title_entry.config(bootstyle='default') if (MetadataHandler.check_metadata_required(output_option, 'author') and - not MetadataHandler.check_metadata_provided(self.input_setdir_var.get(), input_option, 'author') and + not MetadataHandler.check_metadata_provided(Path(self.input_setdir_var.get()), input_option, 'author') and not self.author_var.get()): self.output_frame.author_entry.config(bootstyle='warning') diff --git a/src/sticker_convert/job.py b/src/sticker_convert/job.py index 70f3b22..4123487 100755 --- a/src/sticker_convert/job.py +++ b/src/sticker_convert/job.py @@ -8,6 +8,7 @@ from multiprocessing import Process, Value from multiprocessing.managers import BaseProxy, SyncManager from pathlib import Path +import platform from threading import Thread from typing import Optional, Callable, Union from urllib.parse import urlparse @@ -24,7 +25,7 @@ from sticker_convert.uploaders.upload_base import UploadBase from sticker_convert.uploaders.upload_signal import UploadSignal # type: ignore from sticker_convert.uploaders.upload_telegram import UploadTelegram # type: ignore -from sticker_convert.uploaders.xcode_imessage import XcodeImessage # type: ignore +from sticker_convert.uploaders.xcode_imessage import XcodeImessage, XcodeImessageIconset # type: ignore from sticker_convert.utils.callback import CallbackReturn # type: ignore from sticker_convert.utils.files.json_manager import JsonManager # type: ignore from sticker_convert.utils.files.metadata_handler import MetadataHandler # type: ignore @@ -67,6 +68,8 @@ def __init__(self, self.is_cancel_job = Value('i', 0) + Thread(target=self.cb_thread, args=(self.cb_queue, self.cb_return,)).start() + def cb_thread( self, cb_queue: work_queue_type, @@ -128,8 +131,6 @@ def start_workers(self, processes: int = 1): while not self.work_queue.empty(): self.work_queue.get() - Thread(target=self.cb_thread, args=(self.cb_queue, self.cb_return,)).start() - for _ in range(processes): process = Process( target=Executor.worker, @@ -161,7 +162,10 @@ def kill_workers(self, *args, **kwargs): self.work_queue.get() for process in self.processes: - process.close() + if platform.system() == "Windows": + process.terminate() + else: + process.close() process.join() self.cleanup() @@ -187,20 +191,20 @@ def __init__(self, cb_ask_bool: Callable, cb_ask_str: Callable): - self.opt_input = opt_input - self.opt_comp = opt_comp - self.opt_output = opt_output - self.opt_cred = opt_cred - self.cb_msg = cb_msg - self.cb_msg_block = cb_msg_block - self.cb_bar = cb_bar - self.cb_ask_bool = cb_ask_bool - self.cb_ask_str = cb_ask_str + self.opt_input: InputOption = opt_input + self.opt_comp: CompOption = opt_comp + self.opt_output: OutputOption = opt_output + self.opt_cred: CredOption = opt_cred + self.cb_msg: Callable = cb_msg + self.cb_msg_block: Callable = cb_msg_block + self.cb_bar: Callable = cb_bar + self.cb_ask_bool: Callable = cb_ask_bool + self.cb_ask_str: Callable = cb_ask_str self.compress_fails: list[str] = [] self.out_urls: list[str] = [] - self.executor = Executor( + self.executor: Executor = Executor( self.cb_msg, self.cb_msg_block, self.cb_bar, @@ -339,7 +343,8 @@ def verify_input(self) -> bool: msg += 'You may continue, but the files will need to be compressed again before export\n' msg += 'You are recommended to choose the matching option for compression and output. Continue?' - response = self.executor.cb("ask_bool", (msg,)) + self.executor.cb("ask_bool", (msg,)) + response = self.executor.cb_return.get_response() if response == False: return False @@ -376,16 +381,53 @@ def verify_input(self) -> bool: msg += 'You are adviced to read documentations.\n' msg += 'If you continue, you will only download static stickers. Continue?' - response = self.executor.cb("ask_bool", (msg,)) + self.executor.cb("ask_bool", (msg,)) + response = self.executor.cb_return.get_response() if response == False: return False + + # Warn about in/output directories that might contain other files + # Directory is safe if the name is stickers_input/stickers_output, or + # all contents are related to sticker-convert + for path_type, path, default_name in ( + ("Input", self.opt_input.dir, "stickers_input"), + ("Output", self.opt_output.dir, "stickers_output") + ): - response = self.executor.cb("ask_bool", (msg,)) + if (path_type == "Input" and + (path.name == "stickers_input" or + self.opt_input.option == "local" or + not any(path.iterdir()))): + + continue + elif (path_type == "Output" and + (path.name == "stickers_output" or + self.opt_comp.no_compress or + not any(path.iterdir()))): + + continue + + related_files = MetadataHandler.get_files_related_to_sticker_convert(path) + if any([ + i for i in path.iterdir() + if i not in related_files]): + + msg = 'WARNING: {} directory is set to {}.\n' + msg += 'It does not have default name of "{}",\n' + msg += 'and It seems like it contains PERSONAL DATA.\n' + msg += 'During execution, contents of this directory\n' + msg += 'maybe MOVED to "archive_*".\n' + msg += 'THIS MAY CAUSE DAMAGE TO YOUR DATA. Continue?' + + self.executor.cb("ask_bool", (msg.format(path_type, path, default_name),)) + response = self.executor.cb_return.get_response() + + if response == False: + return False + + break - if response == False: - return False - return True def cleanup(self) -> bool: @@ -396,8 +438,8 @@ def cleanup(self) -> bool: timestamp = datetime.now().strftime('%Y-%d-%m_%H-%M-%S') dir_name = 'archive_' + timestamp - in_dir_files = [i for i in os.listdir(self.opt_input.dir) if not i.startswith('archive_')] - out_dir_files = [i for i in os.listdir(self.opt_output.dir) if not i.startswith('archive_')] + in_dir_files = MetadataHandler.get_files_related_to_sticker_convert(self.opt_input.dir, include_archive=False) + out_dir_files = MetadataHandler.get_files_related_to_sticker_convert(self.opt_output.dir, include_archive=False) if self.opt_input.option == 'local': self.executor.cb('Skip moving old files in input directory as input source is local') @@ -406,11 +448,10 @@ def cleanup(self) -> bool: else: archive_dir = Path(self.opt_input.dir, dir_name) self.executor.cb(f"Moving old files in input directory to {archive_dir} as input source is not local") - os.makedirs(archive_dir) - for i in in_dir_files: - old_path = Path(self.opt_input.dir, i) - new_path = archive_dir / i - shutil.move(old_path, new_path) + archive_dir.mkdir(exist_ok=True) + for old_path in in_dir_files: + new_path = Path(archive_dir, old_path.name) + old_path.rename(new_path) if self.opt_comp.no_compress: self.executor.cb('Skip moving old files in output directory as no_compress is True') @@ -420,10 +461,9 @@ def cleanup(self) -> bool: archive_dir = Path(self.opt_output.dir, dir_name) self.executor.cb(f"Moving old files in output directory to {archive_dir}") os.makedirs(archive_dir) - for i in out_dir_files: - old_path = Path(self.opt_output.dir, i) - new_path = archive_dir / i - shutil.move(old_path, new_path) + for old_path in out_dir_files: + new_path = Path(archive_dir, old_path.name) + old_path.rename(new_path) return True @@ -474,8 +514,8 @@ def download(self) -> bool: def compress(self) -> bool: if self.opt_comp.no_compress == True: self.executor.cb('no_compress is set to True, skip compression') - in_dir_files = [i for i in sorted(os.listdir(self.opt_input.dir)) if Path(self.opt_input.dir, i).is_file()] - out_dir_files = [i for i in sorted(os.listdir(self.opt_output.dir)) if Path(self.opt_output.dir, i).is_file()] + in_dir_files = [i for i in sorted(self.opt_input.dir.iterdir()) if Path(self.opt_input.dir, i).is_file()] + out_dir_files = [i for i in sorted(self.opt_output.dir.iterdir()) if Path(self.opt_output.dir, i).is_file()] if len(in_dir_files) == 0: self.executor.cb('Input directory is empty, nothing to copy to output directory') elif len(out_dir_files) != 0: @@ -496,7 +536,7 @@ def compress(self) -> bool: # .txt: emoji.txt, title.txt # .m4a: line sticker sound effects - for i in sorted(os.listdir(input_dir)): + for i in sorted(input_dir.iterdir()): in_f = input_dir / i if not in_f.is_file(): diff --git a/src/sticker_convert/uploaders/compress_wastickers.py b/src/sticker_convert/uploaders/compress_wastickers.py index 1bed525..074e038 100755 --- a/src/sticker_convert/uploaders/compress_wastickers.py +++ b/src/sticker_convert/uploaders/compress_wastickers.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 import copy -import os import shutil import zipfile from multiprocessing.managers import BaseProxy @@ -88,7 +87,7 @@ def compress_wastickers(self) -> list[str]: self.add_metadata(tempdir, pack_title, author) with zipfile.ZipFile(out_f, "w", zipfile.ZIP_DEFLATED) as zipf: - for file in os.listdir(tempdir): + for file in tempdir.iterdir(): file_path = Path(tempdir, file) zipf.write(file_path, arcname=file_path.stem) @@ -97,7 +96,7 @@ def compress_wastickers(self) -> list[str]: return urls - def add_metadata(self, pack_dir: str, title: str, author: str): + def add_metadata(self, pack_dir: Path, title: str, author: str): opt_comp_merged = copy.deepcopy(self.opt_comp) opt_comp_merged.merge(self.spec_cover) @@ -114,7 +113,7 @@ def add_metadata(self, pack_dir: str, title: str, author: str): # First image in the directory, extracting first frame first_image = [ i - for i in sorted(os.listdir(self.opt_output.dir)) + for i in sorted(self.opt_output.dir.iterdir()) if Path(self.opt_output.dir, i).is_file() and not i.endswith((".txt", ".m4a", ".wastickers")) ][0] diff --git a/src/sticker_convert/uploaders/xcode_imessage.py b/src/sticker_convert/uploaders/xcode_imessage.py index 6456445..c861878 100755 --- a/src/sticker_convert/uploaders/xcode_imessage.py +++ b/src/sticker_convert/uploaders/xcode_imessage.py @@ -22,7 +22,7 @@ class XcodeImessageIconset: - iconset = {} + iconset: dict[str, tuple[int, int]] = {} def __init__(self): if self.iconset != {}: @@ -145,7 +145,7 @@ def add_metadata(self, author: str, title: str): first_image_path = Path(self.opt_output.dir, [ i - for i in sorted(os.listdir(self.opt_output.dir)) + for i in sorted(self.opt_output.dir.iterdir()) if (self.opt_output.dir / i).is_file() and i.endswith(".png") ][0] ) @@ -165,7 +165,7 @@ def add_metadata(self, author: str, title: str): }) icon_path = self.opt_output.dir / icon - if icon in os.listdir(self.opt_output.dir) and not FormatVerify.check_file( + if icon in self.opt_output.dir.iterdir() and not FormatVerify.check_file( icon_path, spec=spec_cover ): StickerConvert.convert(icon_path, icon_path, spec_cover, self.cb, self.cb_return) @@ -237,12 +237,12 @@ def create_xcode_proj(self, author: str, title: str): # packname StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack stickers_path = pack_path / "stickers StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack" - for i in os.listdir(stickers_path): + for i in stickers_path.iterdir(): if i.endswith(".sticker"): shutil.rmtree(stickers_path / i) stickers_lst = [] - for i in sorted(os.listdir(self.opt_output.dir)): + for i in sorted(self.opt_output.dir.iterdir()): if ( CodecInfo.get_file_ext(i) == ".png" and Path(i).stem != "cover" @@ -282,7 +282,7 @@ def create_xcode_proj(self, author: str, title: str): # packname StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset iconset_path = pack_path / "stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset" - for i in os.listdir(iconset_path): + for i in iconset_path.iterdir(): if Path(i).suffix == ".png": os.remove(iconset_path / i) @@ -300,17 +300,9 @@ def create_xcode_proj(self, author: str, title: str): with open(plist_path, "wb+") as f: plistlib.dump(plist_dict, f) - os.rename( - pack_path / "stickers", pack_path / title - ) - os.rename( - pack_path / "stickers StickerPackExtension", - pack_path / f"{title} StickerPackExtension", - ) - os.rename( - pack_path / "stickers.xcodeproj", - pack_path / f"{title}.xcodeproj", - ) + Path(pack_path, "stickers").rename(Path(pack_path, title)) + Path(pack_path, "stickers StickerPackExtension").rename(Path(pack_path, f"{title} StickerPackExtension")) + Path(pack_path, "stickers.xcodeproj").rename(Path(pack_path, f"{title}.xcodeproj")) @staticmethod def start( diff --git a/src/sticker_convert/utils/files/cache_store.py b/src/sticker_convert/utils/files/cache_store.py index 033706f..7b02f87 100755 --- a/src/sticker_convert/utils/files/cache_store.py +++ b/src/sticker_convert/utils/files/cache_store.py @@ -27,8 +27,8 @@ def debug_cache_dir(path: str): class CacheStore: @staticmethod - def get_cache_store(path: Optional[str] = None): + def get_cache_store(path: Optional[str] = None) -> Path: if path: return debug_cache_dir(path) else: - return tempfile.TemporaryDirectory() + return Path(tempfile.TemporaryDirectory()) diff --git a/src/sticker_convert/utils/files/metadata_handler.py b/src/sticker_convert/utils/files/metadata_handler.py index 7f3cdad..936f9ff 100755 --- a/src/sticker_convert/utils/files/metadata_handler.py +++ b/src/sticker_convert/utils/files/metadata_handler.py @@ -2,7 +2,6 @@ from __future__ import annotations import json -import os from pathlib import Path from typing import Optional @@ -11,10 +10,48 @@ from sticker_convert.utils.media.codec_info import CodecInfo # type: ignore +def check_if_xcodeproj(path: Path) -> bool: + if not path.is_dir(): + return False + for i in path.iterdir(): + if i.suffix == ".xcodeproj": + return True + return False + + class MetadataHandler: @staticmethod - def get_stickers_present(dir: str) -> list[str]: - from sticker_convert.uploaders.xcode_imessage import XcodeImessageIconset # type: ignore + def get_files_related_to_sticker_convert(dir: Path, include_archive: bool = True) -> list[Path]: + from sticker_convert.uploaders.xcode_imessage import XcodeImessageIconset # type: ignore + + xcode_iconset = XcodeImessageIconset().iconset + related_extensions = ( + ".png", ".apng", ".jpg", ".jpeg", ".gif", + ".tgs", ".lottie", ".json", + ".mp4", ".mkv", ".mov", ".webm", ".webp", ".avi", + ".m4a", ".wastickers" + ) + related_name = ( + "title.txt", "author.txt", "emoji.txt", + 'export-result.txt', ".DS_Store", "._.DS_Store" + ) + + files = [ + i + for i in sorted(dir.iterdir()) + if i.stem in related_name or + i.name in xcode_iconset or + i.suffix in related_extensions or + (include_archive and i.name.startswith('archive_')) or + check_if_xcodeproj(i) + ] + + return files + + + @staticmethod + def get_stickers_present(dir: Path) -> list[Path]: + from sticker_convert.uploaders.xcode_imessage import XcodeImessageIconset # type: ignore blacklist_prefix = ('cover',) blacklist_suffix = (".txt", ".m4a", ".wastickers", ".DS_Store", "._.DS_Store") @@ -22,18 +59,18 @@ def get_stickers_present(dir: str) -> list[str]: stickers_present = [ i - for i in sorted(os.listdir(dir)) + for i in sorted(dir.iterdir()) if Path(dir, i).is_file() and - not i.startswith(blacklist_prefix) and - not i.endswith(blacklist_suffix) and - not i in xcode_iconset + not i.name.startswith(blacklist_prefix) and + not i.suffix in blacklist_suffix and + not i.name in xcode_iconset ] return stickers_present @staticmethod - def get_cover(dir: str) -> Optional[Path]: - stickers_present = sorted(os.listdir(dir)) + def get_cover(dir: Path) -> Optional[Path]: + stickers_present = sorted(dir.iterdir()) for i in stickers_present: if Path(i).stem == "cover": return Path(dir, i) @@ -42,7 +79,7 @@ def get_cover(dir: str) -> Optional[Path]: @staticmethod def get_metadata( - dir: str, + dir: Path, title: Optional[str] = None, author: Optional[str] = None, emoji_dict: Optional[dict[str, str]] = None, @@ -66,7 +103,7 @@ def get_metadata( @staticmethod def set_metadata( - dir: str, + dir: Path, title: Optional[str] = None, author: Optional[str] = None, emoji_dict: Optional[dict[str, str]] = None, @@ -88,7 +125,7 @@ def set_metadata( @staticmethod def check_metadata_provided( - input_dir: str, input_option: str, metadata: str + input_dir: Path, input_option: str, metadata: str ) -> bool: """ Check if metadata provided via .txt file (if from local) @@ -118,7 +155,7 @@ def check_metadata_required(output_option: str, metadata: str) -> bool: return output_presets[output_option]["metadata_requirements"][metadata] @staticmethod - def generate_emoji_file(dir: str, default_emoji: str = ""): + def generate_emoji_file(dir: Path, default_emoji: str = ""): emoji_path = Path(dir, "emoji.txt") emoji_dict = None if emoji_path.is_file(): @@ -126,7 +163,7 @@ def generate_emoji_file(dir: str, default_emoji: str = ""): emoji_dict = json.load(f) emoji_dict_new = {} - for file in sorted(os.listdir(dir)): + for file in sorted(dir.iterdir()): if not Path(dir, file).is_file() and CodecInfo.get_file_ext( file ) in (".txt", ".m4a"): @@ -142,7 +179,7 @@ def generate_emoji_file(dir: str, default_emoji: str = ""): @staticmethod def split_sticker_packs( - dir: str, + dir: Path, title: str, file_per_pack: Optional[int] = None, file_per_anim_pack: Optional[int] = None, @@ -177,7 +214,7 @@ def split_sticker_packs( image_present = False for processed, file in enumerate(stickers_present): - file_path = Path(dir, file) + file_path = dir / file if CodecInfo.is_anim(file_path): anim_stickers.append(file_path) diff --git a/src/sticker_convert/utils/files/run_bin.py b/src/sticker_convert/utils/files/run_bin.py index 56abfec..7612be4 100755 --- a/src/sticker_convert/utils/files/run_bin.py +++ b/src/sticker_convert/utils/files/run_bin.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -import os import platform import shutil import subprocess diff --git a/tests/test_compression.py b/tests/test_compression.py index 917b9a6..f91da3d 100644 --- a/tests/test_compression.py +++ b/tests/test_compression.py @@ -28,7 +28,7 @@ def _run_sticker_convert(fmt: str, tmp_path: Path): '--vid-format', fmt ], cwd=SRC_DIR) - for i in os.listdir(SAMPLE_DIR): + for i in SAMPLE_DIR.iterdir(): preset_dict = COMPRESSION_DICT.get("custom") if i.startswith("static_") and preset_dict.get("fake_vid") == False: size_max = preset_dict.get("size_max").get("img") diff --git a/tests/test_download.py b/tests/test_download.py index b5fb738..3d977cc 100644 --- a/tests/test_download.py +++ b/tests/test_download.py @@ -36,14 +36,14 @@ def _run_sticker_convert( for i in range(expected_file_count): for fmt in expected_file_formats: fname = str(i).zfill(3) + fmt - assert fname in os.listdir(input_dir) + assert fname in input_dir.iterdir() if with_title: - assert "title.txt" in os.listdir(input_dir) + assert "title.txt" in input_dir.iterdir() if with_author: - assert "author.txt" in os.listdir(input_dir) + assert "author.txt" in input_dir.iterdir() if with_emoji: - assert "emoji.txt" in os.listdir(input_dir) + assert "emoji.txt" in input_dir.iterdir() @pytest.mark.skipif(not TEST_DOWNLOAD, reason="TEST_DOWNLOAD not set") def test_download_signal_static_png(tmp_path): diff --git a/tests/test_export.py b/tests/test_export.py index b10aaae..cb93d1c 100644 --- a/tests/test_export.py +++ b/tests/test_export.py @@ -34,7 +34,7 @@ def _run_sticker_convert(tmp_path: Path, preset: str, export: str): run_cmd(cmd, cwd=SRC_DIR) - for i in os.listdir(SAMPLE_DIR): + for i in SAMPLE_DIR.iterdir(): preset_dict.get("size_max").get("img") if i.startswith("static_") and preset_dict.get("fake_vid") == False: