sticker-convert 2.1.5__py3-none-any.whl → 2.1.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sticker_convert/__init__.py +1 -1
- sticker_convert/__main__.py +7 -4
- sticker_convert/cli.py +42 -32
- sticker_convert/converter.py +432 -0
- sticker_convert/downloaders/download_base.py +40 -16
- sticker_convert/downloaders/download_kakao.py +103 -136
- sticker_convert/downloaders/download_line.py +30 -12
- sticker_convert/downloaders/download_signal.py +48 -32
- sticker_convert/downloaders/download_telegram.py +71 -26
- sticker_convert/gui.py +79 -130
- sticker_convert/{gui_frames → gui_components/frames}/comp_frame.py +2 -3
- sticker_convert/{gui_frames → gui_components/frames}/config_frame.py +3 -4
- sticker_convert/{gui_frames → gui_components/frames}/control_frame.py +2 -2
- sticker_convert/{gui_frames → gui_components/frames}/cred_frame.py +4 -4
- sticker_convert/{gui_frames → gui_components/frames}/input_frame.py +4 -4
- sticker_convert/{gui_frames → gui_components/frames}/output_frame.py +3 -3
- sticker_convert/{gui_frames → gui_components/frames}/progress_frame.py +1 -1
- sticker_convert/{utils → gui_components}/gui_utils.py +38 -21
- sticker_convert/{gui_windows → gui_components/windows}/advanced_compression_window.py +3 -2
- sticker_convert/{gui_windows → gui_components/windows}/base_window.py +3 -2
- sticker_convert/{gui_windows → gui_components/windows}/kakao_get_auth_window.py +3 -3
- sticker_convert/{gui_windows → gui_components/windows}/line_get_auth_window.py +2 -2
- sticker_convert/{gui_windows → gui_components/windows}/signal_get_auth_window.py +2 -2
- sticker_convert/{flow.py → job.py} +91 -102
- sticker_convert/job_option.py +301 -0
- sticker_convert/resources/compression.json +1 -1
- sticker_convert/uploaders/compress_wastickers.py +95 -74
- sticker_convert/uploaders/upload_base.py +16 -4
- sticker_convert/uploaders/upload_signal.py +100 -62
- sticker_convert/uploaders/upload_telegram.py +168 -128
- sticker_convert/uploaders/xcode_imessage.py +202 -132
- sticker_convert/{auth → utils/auth}/get_kakao_auth.py +7 -5
- sticker_convert/{auth → utils/auth}/get_line_auth.py +6 -5
- sticker_convert/{auth → utils/auth}/get_signal_auth.py +1 -1
- sticker_convert/utils/fake_cb_msg.py +5 -2
- sticker_convert/utils/{cache_store.py → files/cache_store.py} +7 -3
- sticker_convert/utils/files/dir_utils.py +64 -0
- sticker_convert/utils/{json_manager.py → files/json_manager.py} +5 -4
- sticker_convert/utils/files/metadata_handler.py +226 -0
- sticker_convert/utils/files/run_bin.py +58 -0
- sticker_convert/utils/{apple_png_normalize.py → media/apple_png_normalize.py} +23 -20
- sticker_convert/utils/{codec_info.py → media/codec_info.py} +41 -35
- sticker_convert/utils/media/decrypt_kakao.py +68 -0
- sticker_convert/utils/media/format_verify.py +184 -0
- sticker_convert/utils/url_detect.py +16 -14
- {sticker_convert-2.1.5.dist-info → sticker_convert-2.1.7.dist-info}/METADATA +11 -11
- {sticker_convert-2.1.5.dist-info → sticker_convert-2.1.7.dist-info}/RECORD +52 -50
- {sticker_convert-2.1.5.dist-info → sticker_convert-2.1.7.dist-info}/WHEEL +1 -1
- sticker_convert/utils/converter.py +0 -399
- sticker_convert/utils/curr_dir.py +0 -70
- sticker_convert/utils/format_verify.py +0 -188
- sticker_convert/utils/metadata_handler.py +0 -190
- sticker_convert/utils/run_bin.py +0 -46
- /sticker_convert/{gui_frames → gui_components/frames}/right_clicker.py +0 -0
- {sticker_convert-2.1.5.dist-info → sticker_convert-2.1.7.dist-info}/LICENSE +0 -0
- {sticker_convert-2.1.5.dist-info → sticker_convert-2.1.7.dist-info}/entry_points.txt +0 -0
- {sticker_convert-2.1.5.dist-info → sticker_convert-2.1.7.dist-info}/top_level.txt +0 -0
@@ -1,190 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
import os
|
3
|
-
import json
|
4
|
-
from typing import Optional
|
5
|
-
|
6
|
-
from .codec_info import CodecInfo # type: ignore
|
7
|
-
from .json_manager import JsonManager # type: ignore
|
8
|
-
|
9
|
-
class MetadataHandler:
|
10
|
-
@staticmethod
|
11
|
-
def get_stickers_present(dir: str) -> list[str]:
|
12
|
-
from ..uploaders.xcode_imessage import XcodeImessageIconset # type: ignore
|
13
|
-
|
14
|
-
stickers_present = sorted(os.listdir(dir))
|
15
|
-
for i in stickers_present:
|
16
|
-
if os.path.splitext(i)[0] == 'cover':
|
17
|
-
stickers_present.remove(os.path.split(i)[1])
|
18
|
-
for icon in XcodeImessageIconset().iconset:
|
19
|
-
if icon in stickers_present:
|
20
|
-
stickers_present.remove(icon)
|
21
|
-
if '.DS_Store' in stickers_present:
|
22
|
-
stickers_present.remove('.DS_Store')
|
23
|
-
if '._.DS_Store' in stickers_present:
|
24
|
-
stickers_present.remove('._.DS_Store')
|
25
|
-
stickers_present = [i for i in stickers_present if os.path.isfile(os.path.join(dir, i)) and not i.endswith(('.txt', '.m4a'))]
|
26
|
-
|
27
|
-
return stickers_present
|
28
|
-
|
29
|
-
@staticmethod
|
30
|
-
def get_cover(dir: str) -> Optional[str]:
|
31
|
-
stickers_present = sorted(os.listdir(dir))
|
32
|
-
for i in stickers_present:
|
33
|
-
if os.path.splitext(i)[0] == 'cover':
|
34
|
-
return os.path.join(dir, i)
|
35
|
-
|
36
|
-
return None
|
37
|
-
|
38
|
-
@staticmethod
|
39
|
-
def get_metadata(dir: str, title: Optional[str] = None, author: Optional[str] = None, emoji_dict: Optional[dict[str, str]] = None) -> tuple[Optional[str], Optional[str], Optional[dict[str, str]]]:
|
40
|
-
title_path = os.path.join(dir, 'title.txt')
|
41
|
-
if not title and os.path.isfile(title_path):
|
42
|
-
with open(title_path, encoding='utf-8') as f:
|
43
|
-
title = f.read().strip()
|
44
|
-
|
45
|
-
author_path = os.path.join(dir, 'author.txt')
|
46
|
-
if not author and os.path.isfile(author_path):
|
47
|
-
with open(author_path, encoding='utf-8') as f:
|
48
|
-
author = f.read().strip()
|
49
|
-
|
50
|
-
emoji_path = os.path.join(dir, 'emoji.txt')
|
51
|
-
if not emoji_dict and os.path.isfile(emoji_path):
|
52
|
-
with open(emoji_path , "r", encoding='utf-8') as f:
|
53
|
-
emoji_dict = json.load(f)
|
54
|
-
|
55
|
-
return title, author, emoji_dict
|
56
|
-
|
57
|
-
@staticmethod
|
58
|
-
def set_metadata(dir: str, title: Optional[str] = None, author: Optional[str] = None, emoji_dict: Optional[dict[str, str]] = None):
|
59
|
-
title_path = os.path.join(dir, 'title.txt')
|
60
|
-
if title != None:
|
61
|
-
with open(title_path, 'w+', encoding='utf-8') as f:
|
62
|
-
f.write(title) # type: ignore[arg-type]
|
63
|
-
|
64
|
-
author_path = os.path.join(dir, 'author.txt')
|
65
|
-
if author != None:
|
66
|
-
with open(author_path, 'w+', encoding='utf-8') as f:
|
67
|
-
f.write(author) # type: ignore[arg-type]
|
68
|
-
|
69
|
-
emoji_path = os.path.join(dir, 'emoji.txt')
|
70
|
-
if emoji_dict != None:
|
71
|
-
with open(emoji_path, 'w+', encoding='utf-8') as f:
|
72
|
-
json.dump(emoji_dict, f, indent=4, ensure_ascii=False)
|
73
|
-
|
74
|
-
@staticmethod
|
75
|
-
def check_metadata_provided(input_dir: str, input_option: str, metadata: str) -> bool:
|
76
|
-
# Check if metadata provided via .txt file (if from local) or will be provided by input source (if not from local)
|
77
|
-
# Does not check if metadata provided via user input in GUI or flag options
|
78
|
-
# metadata = 'title' or 'author'
|
79
|
-
input_presets = JsonManager.load_json('resources/input.json')
|
80
|
-
|
81
|
-
if input_option == 'local':
|
82
|
-
metadata_file_path = os.path.join(input_dir, f'{metadata}.txt')
|
83
|
-
metadata_provided = os.path.isfile(metadata_file_path)
|
84
|
-
if metadata_provided:
|
85
|
-
with open(metadata_file_path, encoding='utf-8') as f:
|
86
|
-
metadata_provided = True if f.read() else False
|
87
|
-
else:
|
88
|
-
metadata_provided = input_presets[input_option]['metadata_provides'][metadata]
|
89
|
-
|
90
|
-
return metadata_provided
|
91
|
-
|
92
|
-
@staticmethod
|
93
|
-
def check_metadata_required(output_option: str, metadata: str) -> bool:
|
94
|
-
# metadata = 'title' or 'author'
|
95
|
-
output_presets = JsonManager.load_json('resources/output.json')
|
96
|
-
return output_presets[output_option]['metadata_requirements'][metadata]
|
97
|
-
|
98
|
-
@staticmethod
|
99
|
-
def generate_emoji_file(dir: str, default_emoji: str = ''):
|
100
|
-
emoji_path = os.path.join(dir, 'emoji.txt')
|
101
|
-
emoji_dict = None
|
102
|
-
if os.path.isfile(emoji_path):
|
103
|
-
with open(emoji_path , "r", encoding='utf-8') as f:
|
104
|
-
emoji_dict = json.load(f)
|
105
|
-
|
106
|
-
emoji_dict_new = {}
|
107
|
-
for file in sorted(os.listdir(dir)):
|
108
|
-
if not os.path.isfile(os.path.join(dir, file)) and CodecInfo.get_file_ext(file) in ('.txt', '.m4a'):
|
109
|
-
continue
|
110
|
-
file_name = os.path.splitext(file)[0]
|
111
|
-
if emoji_dict and file_name in emoji_dict:
|
112
|
-
emoji_dict_new[file_name] = emoji_dict[file_name]
|
113
|
-
else:
|
114
|
-
emoji_dict_new[file_name] = default_emoji
|
115
|
-
|
116
|
-
with open(emoji_path, 'w+', encoding='utf-8') as f:
|
117
|
-
json.dump(emoji_dict_new, f, indent=4, ensure_ascii=False)
|
118
|
-
|
119
|
-
@staticmethod
|
120
|
-
def split_sticker_packs(dir: str, title: str, file_per_pack: Optional[int] = None, file_per_anim_pack: Optional[int] = None, file_per_image_pack: Optional[int] = None, separate_image_anim: bool = True) -> dict:
|
121
|
-
# {pack_1: [sticker1_path, sticker2_path]}
|
122
|
-
packs = {}
|
123
|
-
|
124
|
-
if file_per_pack == None:
|
125
|
-
file_per_pack = file_per_anim_pack if file_per_anim_pack != None else file_per_image_pack
|
126
|
-
else:
|
127
|
-
file_per_anim_pack = file_per_pack
|
128
|
-
file_per_image_pack = file_per_pack
|
129
|
-
|
130
|
-
stickers_present = MetadataHandler.get_stickers_present(dir)
|
131
|
-
|
132
|
-
processed = 0
|
133
|
-
|
134
|
-
if separate_image_anim == True:
|
135
|
-
image_stickers = []
|
136
|
-
anim_stickers = []
|
137
|
-
|
138
|
-
image_pack_count = 0
|
139
|
-
anim_pack_count = 0
|
140
|
-
|
141
|
-
anim_present = False
|
142
|
-
image_present = False
|
143
|
-
|
144
|
-
for file in stickers_present:
|
145
|
-
file_path = os.path.join(dir, file)
|
146
|
-
|
147
|
-
if CodecInfo.is_anim(file_path):
|
148
|
-
anim_stickers.append(file_path)
|
149
|
-
else:
|
150
|
-
image_stickers.append(file_path)
|
151
|
-
|
152
|
-
anim_present = anim_present or len(anim_stickers) > 0
|
153
|
-
image_present = image_present or len(image_stickers) > 0
|
154
|
-
|
155
|
-
processed += 1
|
156
|
-
finished_all = True if processed == len(stickers_present) else False
|
157
|
-
|
158
|
-
if len(anim_stickers) == file_per_anim_pack or (finished_all and len(anim_stickers) > 0):
|
159
|
-
suffix = f'{"-anim" if image_present else ""}{"-" + str(anim_pack_count) if anim_pack_count > 0 else ""}'
|
160
|
-
title_current = str(title) + suffix
|
161
|
-
packs[title_current] = anim_stickers.copy()
|
162
|
-
anim_stickers = []
|
163
|
-
anim_pack_count += 1
|
164
|
-
if len(image_stickers) == file_per_image_pack or (finished_all and len(image_stickers) > 0):
|
165
|
-
suffix = f'{"-image" if anim_present else ""}{"-" + str(image_pack_count) if image_pack_count > 0 else ""}'
|
166
|
-
title_current = str(title) + suffix
|
167
|
-
packs[title_current] = image_stickers.copy()
|
168
|
-
image_stickers = []
|
169
|
-
image_pack_count += 1
|
170
|
-
|
171
|
-
else:
|
172
|
-
stickers = []
|
173
|
-
pack_count = 0
|
174
|
-
|
175
|
-
for file in stickers_present:
|
176
|
-
file_path = os.path.join(dir, file)
|
177
|
-
|
178
|
-
stickers.append(file_path)
|
179
|
-
|
180
|
-
processed += 1
|
181
|
-
finished_all = True if processed == len(stickers_present) else False
|
182
|
-
|
183
|
-
if len(stickers) == file_per_pack or (finished_all and len(stickers) > 0):
|
184
|
-
suffix = f'{"-" + str(pack_count) if pack_count > 0 else ""}'
|
185
|
-
title = str(title) + suffix
|
186
|
-
packs[title] = stickers.copy()
|
187
|
-
stickers = []
|
188
|
-
pack_count += 1
|
189
|
-
|
190
|
-
return packs
|
sticker_convert/utils/run_bin.py
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
import subprocess
|
3
|
-
import os
|
4
|
-
import shutil
|
5
|
-
import platform
|
6
|
-
from typing import Union, AnyStr
|
7
|
-
|
8
|
-
class RunBin:
|
9
|
-
@staticmethod
|
10
|
-
def get_bin(bin: str, silent: bool = False, cb_msg=print) -> Union[str, AnyStr, None]:
|
11
|
-
if os.path.isfile(bin):
|
12
|
-
return bin
|
13
|
-
|
14
|
-
if platform.system() == 'Windows':
|
15
|
-
bin = bin + '.exe'
|
16
|
-
|
17
|
-
which_result = shutil.which(bin)
|
18
|
-
if which_result != None:
|
19
|
-
return os.path.abspath(which_result) # type: ignore[type-var]
|
20
|
-
elif silent == False:
|
21
|
-
cb_msg(f'Warning: Cannot find binary file {bin}')
|
22
|
-
|
23
|
-
return None
|
24
|
-
|
25
|
-
@staticmethod
|
26
|
-
def run_cmd(cmd_list: list[str], silence: bool = False, cb_msg=print) -> Union[bool, str]:
|
27
|
-
bin_path = RunBin.get_bin(cmd_list[0]) # type: ignore[assignment]
|
28
|
-
|
29
|
-
if bin_path:
|
30
|
-
cmd_list[0] = bin_path
|
31
|
-
else:
|
32
|
-
if silence == False:
|
33
|
-
cb_msg(f"Error while executing {' '.join(cmd_list)} : Command not found")
|
34
|
-
return False
|
35
|
-
|
36
|
-
# sp = subprocess.Popen(cmd_list, stdout=subprocess.DEVNULL, stderr=subprocess.STDOUT)
|
37
|
-
sp = subprocess.run(cmd_list, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
38
|
-
|
39
|
-
output_str = sp.stdout.decode()
|
40
|
-
error_str = sp.stderr.decode()
|
41
|
-
|
42
|
-
if silence == False and error_str != '':
|
43
|
-
cb_msg(f"Error while executing {' '.join(cmd_list)} : {error_str}")
|
44
|
-
return False
|
45
|
-
|
46
|
-
return output_str
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|