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
@@ -0,0 +1,301 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
from __future__ import annotations
|
3
|
+
from typing import Optional, Union
|
4
|
+
|
5
|
+
|
6
|
+
def to_int(i) -> Optional[int]:
|
7
|
+
return int(i) if i != None else None
|
8
|
+
|
9
|
+
class BaseOption:
|
10
|
+
def merge(self, config: "BaseOption"):
|
11
|
+
for k, v in vars(config).items():
|
12
|
+
if v != None:
|
13
|
+
setattr(self, k, v)
|
14
|
+
|
15
|
+
class InputOption(BaseOption):
|
16
|
+
def __init__(self, input_config_dict: dict):
|
17
|
+
self.option = input_config_dict.get('option')
|
18
|
+
self.url = input_config_dict.get('url')
|
19
|
+
self.dir = input_config_dict.get('dir')
|
20
|
+
|
21
|
+
def to_dict(self) -> dict:
|
22
|
+
return {
|
23
|
+
'option': self.option,
|
24
|
+
'url': self.url,
|
25
|
+
'dir': self.dir
|
26
|
+
}
|
27
|
+
|
28
|
+
class CompOption(BaseOption):
|
29
|
+
def __init__(self, comp_config_dict: dict):
|
30
|
+
self.preset = comp_config_dict.get('preset')
|
31
|
+
|
32
|
+
size_max = comp_config_dict.get('size_max')
|
33
|
+
if isinstance(size_max, dict):
|
34
|
+
self.size_max_img = to_int(size_max.get('img'))
|
35
|
+
self.size_max_vid = to_int(size_max.get('vid'))
|
36
|
+
else:
|
37
|
+
self.size_max_img = to_int(size_max)
|
38
|
+
self.size_max_vid = to_int(size_max)
|
39
|
+
|
40
|
+
fmt = comp_config_dict.get('format')
|
41
|
+
if isinstance(fmt, dict):
|
42
|
+
self.format_img = fmt.get('img')
|
43
|
+
self.format_vid = fmt.get('vid')
|
44
|
+
else:
|
45
|
+
self.format_img = fmt
|
46
|
+
self.format_vid = fmt
|
47
|
+
|
48
|
+
fps = comp_config_dict.get('fps')
|
49
|
+
if isinstance(fps, dict):
|
50
|
+
self.fps_min = to_int(fps.get('min'))
|
51
|
+
self.fps_max = to_int(fps.get('max'))
|
52
|
+
else:
|
53
|
+
self.fps_min = to_int(fps)
|
54
|
+
self.fps_max = to_int(fps)
|
55
|
+
|
56
|
+
self.res_w_min = None
|
57
|
+
self.res_w_max = None
|
58
|
+
self.res_h_min = None
|
59
|
+
self.res_h_max = None
|
60
|
+
if isinstance(res := comp_config_dict.get('res'), dict):
|
61
|
+
if res_w := res.get('w'):
|
62
|
+
if isinstance(res_w, dict):
|
63
|
+
self.res_w_min = to_int(res_w.get('min'))
|
64
|
+
self.res_w_max = to_int(res_w.get('max'))
|
65
|
+
else:
|
66
|
+
self.res_w_min = res_w
|
67
|
+
self.res_w_max = res_w
|
68
|
+
if res_h := res.get('h'):
|
69
|
+
if isinstance(res_h, dict):
|
70
|
+
self.res_h_min = to_int(res_h.get('min', res_h))
|
71
|
+
self.res_h_max = to_int(res_h.get('max', res_h))
|
72
|
+
else:
|
73
|
+
self.res_h_min = res_h
|
74
|
+
self.res_h_max = res_h
|
75
|
+
if res_min := res.get('min'):
|
76
|
+
if isinstance(res_min, dict):
|
77
|
+
self.res_w_min = to_int(res_min.get('w', res_min))
|
78
|
+
self.res_h_min = to_int(res_min.get('h', res_min))
|
79
|
+
else:
|
80
|
+
self.res_w_min = res_min
|
81
|
+
self.res_h_min = res_min
|
82
|
+
if res_max := res.get('max'):
|
83
|
+
if isinstance(res_max, dict):
|
84
|
+
self.res_w_max = to_int(res_max.get('w', res_max))
|
85
|
+
self.res_h_max = to_int(res_max.get('h', res_max))
|
86
|
+
else:
|
87
|
+
self.res_w_max = res_max
|
88
|
+
self.res_h_max = res_max
|
89
|
+
else:
|
90
|
+
self.res_w_min = to_int(res)
|
91
|
+
self.res_w_max = to_int(res)
|
92
|
+
self.res_h_min = to_int(res)
|
93
|
+
self.res_h_max = to_int(res)
|
94
|
+
|
95
|
+
quality = comp_config_dict.get('quality')
|
96
|
+
if isinstance(quality, dict):
|
97
|
+
self.quality_min = to_int(quality.get('min'))
|
98
|
+
self.quality_max = to_int(quality.get('max'))
|
99
|
+
else:
|
100
|
+
self.quality_min = to_int(quality)
|
101
|
+
self.quality_max = to_int(quality)
|
102
|
+
|
103
|
+
color = comp_config_dict.get('color')
|
104
|
+
if isinstance(color, dict):
|
105
|
+
self.color_min = to_int(color.get('min'))
|
106
|
+
self.color_max = to_int(color.get('max'))
|
107
|
+
else:
|
108
|
+
self.color_min = to_int(color)
|
109
|
+
self.color_max = to_int(color)
|
110
|
+
|
111
|
+
duration = comp_config_dict.get('duration')
|
112
|
+
if isinstance(duration, dict):
|
113
|
+
self.duration_min = to_int(duration.get('min'))
|
114
|
+
self.duration_max = to_int(duration.get('max'))
|
115
|
+
else:
|
116
|
+
self.duration_min = to_int(duration)
|
117
|
+
self.duration_max = to_int(duration)
|
118
|
+
|
119
|
+
self.steps = to_int(comp_config_dict.get('steps'))
|
120
|
+
self.fake_vid = comp_config_dict.get('fake_vid')
|
121
|
+
self.cache_dir = comp_config_dict.get('cache_dir')
|
122
|
+
self.default_emoji = comp_config_dict.get('default_emoji')
|
123
|
+
self.no_compress = comp_config_dict.get('no_compress')
|
124
|
+
self.processes = to_int(comp_config_dict.get('processes'))
|
125
|
+
|
126
|
+
# Only used for format verification
|
127
|
+
self.animated = comp_config_dict.get('animated')
|
128
|
+
self.square = comp_config_dict.get('square')
|
129
|
+
|
130
|
+
def to_dict(self) -> dict:
|
131
|
+
return {
|
132
|
+
'preset': self.preset,
|
133
|
+
'size_max': {
|
134
|
+
'img': self.size_max_img,
|
135
|
+
'vid': self.size_max_vid
|
136
|
+
},
|
137
|
+
'format': {
|
138
|
+
'img': self.format_img,
|
139
|
+
'vid': self.format_vid
|
140
|
+
},
|
141
|
+
'fps': {
|
142
|
+
'min': self.fps_min,
|
143
|
+
'max': self.fps_max
|
144
|
+
},
|
145
|
+
'res': {
|
146
|
+
'w': {
|
147
|
+
'min': self.res_w_min,
|
148
|
+
'max': self.res_w_max
|
149
|
+
},
|
150
|
+
'h': {
|
151
|
+
'min': self.res_h_min,
|
152
|
+
'max': self.res_h_max
|
153
|
+
}
|
154
|
+
},
|
155
|
+
'quality': {
|
156
|
+
'min': self.quality_min,
|
157
|
+
'max': self.quality_max
|
158
|
+
},
|
159
|
+
'color': {
|
160
|
+
'min': self.color_min,
|
161
|
+
'max': self.color_max
|
162
|
+
},
|
163
|
+
'duration': {
|
164
|
+
'min': self.duration_min,
|
165
|
+
'max': self.duration_max
|
166
|
+
},
|
167
|
+
'steps': self.steps,
|
168
|
+
'fake_vid': self.fake_vid,
|
169
|
+
'cache_dir': self.cache_dir,
|
170
|
+
'default_emoji': self.default_emoji,
|
171
|
+
'no_compress': self.no_compress,
|
172
|
+
'processes': self.processes,
|
173
|
+
'animated': self.animated,
|
174
|
+
'square': self.square
|
175
|
+
}
|
176
|
+
|
177
|
+
@property
|
178
|
+
def size_max(self) -> list[Optional[int]]:
|
179
|
+
return [self.size_max_img, self.size_max_vid]
|
180
|
+
|
181
|
+
@size_max.setter
|
182
|
+
def size_max(self, value: Optional[int]):
|
183
|
+
self.size_max_img, self.size_max_vid = to_int(value), to_int(value)
|
184
|
+
|
185
|
+
@property
|
186
|
+
def format(self) -> list[Union[list[str], str, None]]:
|
187
|
+
return [self.format_img, self.format_vid]
|
188
|
+
|
189
|
+
@format.setter
|
190
|
+
def format(self, value: Union[list[str], str, None]):
|
191
|
+
self.format_img, self.format_vid = value, value
|
192
|
+
|
193
|
+
@property
|
194
|
+
def fps(self) -> list[Optional[int]]:
|
195
|
+
return [self.fps_min, self.fps_max]
|
196
|
+
|
197
|
+
@fps.setter
|
198
|
+
def fps(self, value: Optional[int]):
|
199
|
+
self.fps_min, self.fps_max = to_int(value), to_int(value)
|
200
|
+
|
201
|
+
@property
|
202
|
+
def res(self) -> list[Optional[list[Optional[int]]]]:
|
203
|
+
return [self.res_w, self.res_h]
|
204
|
+
|
205
|
+
@res.setter
|
206
|
+
def res(self, value: Optional[int]):
|
207
|
+
self.res_w_min = to_int(value)
|
208
|
+
self.res_w_max = to_int(value)
|
209
|
+
self.res_h_min = to_int(value)
|
210
|
+
self.res_h_max = to_int(value)
|
211
|
+
|
212
|
+
@property
|
213
|
+
def res_w(self) -> list[Optional[int]]:
|
214
|
+
return [self.res_w_min, self.res_w_max]
|
215
|
+
|
216
|
+
@res_w.setter
|
217
|
+
def res_w(self, value: Optional[int]):
|
218
|
+
self.res_w_min, self.res_w_max = to_int(value), to_int(value)
|
219
|
+
|
220
|
+
@property
|
221
|
+
def res_h(self) -> list[Optional[int]]:
|
222
|
+
return [self.res_h_min, self.res_h_max]
|
223
|
+
|
224
|
+
@res_h.setter
|
225
|
+
def res_h(self, value: Optional[int]):
|
226
|
+
self.res_h_min, self.res_h_max = to_int(value), to_int(value)
|
227
|
+
|
228
|
+
@property
|
229
|
+
def quality(self) -> list[Optional[int]]:
|
230
|
+
return [self.quality_min, self.quality_max]
|
231
|
+
|
232
|
+
@quality.setter
|
233
|
+
def quality(self, value: Optional[int]):
|
234
|
+
self.quality_min, self.quality_max = to_int(value), to_int(value)
|
235
|
+
|
236
|
+
@property
|
237
|
+
def color(self) -> list[Optional[int]]:
|
238
|
+
return [self.color_min, self.color_max]
|
239
|
+
|
240
|
+
@color.setter
|
241
|
+
def color(self, value: Optional[int]):
|
242
|
+
self.color_min, self.color_max = to_int(value), to_int(value)
|
243
|
+
|
244
|
+
@property
|
245
|
+
def duration(self) -> list[Optional[int]]:
|
246
|
+
return [self.duration_min, self.duration_max]
|
247
|
+
|
248
|
+
@duration.setter
|
249
|
+
def duration(self, value: Optional[int]):
|
250
|
+
self.duration_min, self.duration_max = to_int(value), to_int(value)
|
251
|
+
|
252
|
+
|
253
|
+
class OutputOption(BaseOption):
|
254
|
+
def __init__(self, output_config_dict: dict):
|
255
|
+
self.option = output_config_dict.get('option')
|
256
|
+
self.dir = output_config_dict.get('dir')
|
257
|
+
self.title = output_config_dict.get('title')
|
258
|
+
self.author = output_config_dict.get('author')
|
259
|
+
|
260
|
+
def to_dict(self) -> dict:
|
261
|
+
return {
|
262
|
+
'option': self.option,
|
263
|
+
'dir': self.dir,
|
264
|
+
'title': self.title,
|
265
|
+
'author': self.author
|
266
|
+
}
|
267
|
+
|
268
|
+
class CredOption(BaseOption):
|
269
|
+
def __init__(self, cred_config_dict: dict):
|
270
|
+
self.signal_uuid = cred_config_dict.get('signal', {}).get('uuid')
|
271
|
+
self.signal_password = cred_config_dict.get('signal', {}).get('password')
|
272
|
+
self.telegram_token = cred_config_dict.get('telegram', {}).get('token')
|
273
|
+
self.telegram_userid = cred_config_dict.get('telegram', {}).get('userid')
|
274
|
+
self.kakao_auth_token = cred_config_dict.get('kakao', {}).get('auth_token')
|
275
|
+
self.kakao_username = cred_config_dict.get('kakao', {}).get('username')
|
276
|
+
self.kakao_password = cred_config_dict.get('kakao', {}).get('password')
|
277
|
+
self.kakao_country_code = cred_config_dict.get('kakao', {}).get('country_code')
|
278
|
+
self.kakao_phone_number = cred_config_dict.get('kakao', {}).get('phone_number')
|
279
|
+
self.line_cookies = cred_config_dict.get('line', {}).get('cookies')
|
280
|
+
|
281
|
+
def to_dict(self) -> dict:
|
282
|
+
return {
|
283
|
+
'signal': {
|
284
|
+
'uuid': self.signal_uuid,
|
285
|
+
'password': self.signal_password
|
286
|
+
},
|
287
|
+
'telegram': {
|
288
|
+
'token': self.telegram_token,
|
289
|
+
'userid': self.telegram_userid
|
290
|
+
},
|
291
|
+
'kakao': {
|
292
|
+
'auth_token': self.kakao_auth_token,
|
293
|
+
'username': self.kakao_username,
|
294
|
+
'password': self.kakao_password,
|
295
|
+
'country_code': self.kakao_country_code,
|
296
|
+
'phone_number': self.kakao_phone_number
|
297
|
+
},
|
298
|
+
'line': {
|
299
|
+
'cookies': self.line_cookies
|
300
|
+
}
|
301
|
+
}
|
@@ -5,98 +5,87 @@ import copy
|
|
5
5
|
import zipfile
|
6
6
|
from typing import Optional
|
7
7
|
|
8
|
-
from
|
8
|
+
from .upload_base import UploadBase # type: ignore
|
9
|
+
from ..converter import StickerConvert # type: ignore
|
10
|
+
from ..utils.media.format_verify import FormatVerify # type: ignore
|
11
|
+
from ..utils.files.metadata_handler import MetadataHandler # type: ignore
|
12
|
+
from ..utils.media.codec_info import CodecInfo # type: ignore
|
13
|
+
from ..utils.files.cache_store import CacheStore # type: ignore
|
14
|
+
from ..job_option import CompOption, OutputOption, CredOption # type: ignore
|
9
15
|
|
10
|
-
from .upload_base import UploadBase # type: ignore
|
11
|
-
from ..utils.converter import StickerConvert # type: ignore
|
12
|
-
from ..utils.format_verify import FormatVerify # type: ignore
|
13
|
-
from ..utils.metadata_handler import MetadataHandler # type: ignore
|
14
|
-
from ..utils.codec_info import CodecInfo # type: ignore
|
15
|
-
from ..utils.cache_store import CacheStore # type: ignore
|
16
16
|
|
17
17
|
class CompressWastickers(UploadBase):
|
18
18
|
def __init__(self, *args, **kwargs):
|
19
19
|
super(CompressWastickers, self).__init__(*args, **kwargs)
|
20
|
-
base_spec = {
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
},
|
35
|
-
'duration': {
|
36
|
-
'min': 8,
|
37
|
-
'max': 10000
|
38
|
-
},
|
39
|
-
'format': '.webp',
|
40
|
-
'square': True
|
41
|
-
}
|
42
|
-
|
43
|
-
self.spec_cover = {
|
44
|
-
"size_max": {
|
45
|
-
"img": 50000,
|
46
|
-
"vid": 50000
|
47
|
-
},
|
48
|
-
"res": {
|
49
|
-
"w": {
|
50
|
-
"min": 96,
|
51
|
-
"max": 96
|
52
|
-
},
|
53
|
-
"h": {
|
54
|
-
"min": 96,
|
55
|
-
"max": 96
|
56
|
-
}
|
57
|
-
},
|
58
|
-
'format': '.png',
|
59
|
-
'animated': False
|
60
|
-
}
|
20
|
+
base_spec = CompOption({
|
21
|
+
"size_max": {"img": 100000, "vid": 500000},
|
22
|
+
"res": 512,
|
23
|
+
"duration": {"min": 8, "max": 10000},
|
24
|
+
"format": ".webp",
|
25
|
+
"square": True,
|
26
|
+
})
|
27
|
+
|
28
|
+
self.spec_cover = CompOption({
|
29
|
+
"size_max": {"img": 50000, "vid": 50000},
|
30
|
+
"res": 96,
|
31
|
+
"format": ".png",
|
32
|
+
"animated": False,
|
33
|
+
})
|
61
34
|
|
62
35
|
self.webp_spec = copy.deepcopy(base_spec)
|
63
|
-
self.webp_spec
|
64
|
-
self.webp_spec
|
36
|
+
self.webp_spec.format = ".webp"
|
37
|
+
self.webp_spec.animated = None if self.fake_vid else True
|
65
38
|
|
66
39
|
self.png_spec = copy.deepcopy(base_spec)
|
67
|
-
self.png_spec
|
68
|
-
self.png_spec
|
40
|
+
self.png_spec.format = ".png"
|
41
|
+
self.png_spec.animated = False
|
69
42
|
|
70
|
-
self.opt_comp_merged =
|
43
|
+
self.opt_comp_merged = copy.deepcopy(self.opt_comp)
|
44
|
+
self.opt_comp_merged.merge(base_spec)
|
71
45
|
|
72
46
|
def compress_wastickers(self) -> list[str]:
|
73
47
|
urls = []
|
74
|
-
title, author, emoji_dict = MetadataHandler.get_metadata(
|
75
|
-
|
48
|
+
title, author, emoji_dict = MetadataHandler.get_metadata(
|
49
|
+
self.in_dir,
|
50
|
+
title=self.opt_output.title,
|
51
|
+
author=self.opt_output.author,
|
52
|
+
)
|
53
|
+
packs = MetadataHandler.split_sticker_packs(
|
54
|
+
self.in_dir,
|
55
|
+
title=title,
|
56
|
+
file_per_pack=30,
|
57
|
+
separate_image_anim=not self.fake_vid,
|
58
|
+
)
|
76
59
|
|
77
60
|
for pack_title, stickers in packs.items():
|
78
|
-
num = 0
|
79
|
-
with CacheStore.get_cache_store(
|
61
|
+
num = 0 # Originally the Sticker Maker application name the files with int(time.time())
|
62
|
+
with CacheStore.get_cache_store(
|
63
|
+
path=self.opt_comp.cache_dir
|
64
|
+
) as tempdir:
|
80
65
|
for src in stickers:
|
81
|
-
self.cb_msg(f
|
66
|
+
self.cb_msg(f"Verifying {src} for compressing into .wastickers")
|
82
67
|
|
83
68
|
if self.fake_vid or CodecInfo.is_anim(src):
|
84
|
-
ext =
|
69
|
+
ext = ".webp"
|
85
70
|
else:
|
86
|
-
ext =
|
71
|
+
ext = ".png"
|
87
72
|
|
88
73
|
dst = os.path.join(tempdir, str(num) + ext)
|
89
74
|
num += 1
|
90
75
|
|
91
|
-
if FormatVerify.check_file(src, spec=self.webp_spec) or
|
76
|
+
if (FormatVerify.check_file(src, spec=self.webp_spec) or
|
77
|
+
FormatVerify.check_file(src, spec=self.png_spec)):
|
92
78
|
shutil.copy(src, dst)
|
93
79
|
else:
|
94
80
|
StickerConvert(src, dst, self.opt_comp_merged, self.cb_msg).convert()
|
95
81
|
|
96
|
-
out_f = os.path.join(
|
82
|
+
out_f = os.path.join(
|
83
|
+
self.out_dir,
|
84
|
+
FormatVerify.sanitize_filename(pack_title + ".wastickers"),
|
85
|
+
)
|
97
86
|
|
98
87
|
self.add_metadata(tempdir, pack_title, author)
|
99
|
-
with zipfile.ZipFile(out_f,
|
88
|
+
with zipfile.ZipFile(out_f, "w", zipfile.ZIP_DEFLATED) as zipf:
|
100
89
|
for file in os.listdir(tempdir):
|
101
90
|
file_path = os.path.join(tempdir, file)
|
102
91
|
file_name = os.path.basename(file_path)
|
@@ -104,27 +93,59 @@ class CompressWastickers(UploadBase):
|
|
104
93
|
|
105
94
|
self.cb_msg(out_f)
|
106
95
|
urls.append(out_f)
|
107
|
-
|
96
|
+
|
108
97
|
return urls
|
109
98
|
|
110
99
|
def add_metadata(self, pack_dir: str, title: str, author: str):
|
111
|
-
opt_comp_merged =
|
100
|
+
opt_comp_merged = copy.deepcopy(self.opt_comp)
|
101
|
+
opt_comp_merged.merge(self.spec_cover)
|
112
102
|
|
113
103
|
cover_path_old = MetadataHandler.get_cover(self.in_dir)
|
114
|
-
cover_path_new = os.path.join(pack_dir,
|
104
|
+
cover_path_new = os.path.join(pack_dir, "100.png")
|
115
105
|
if cover_path_old:
|
116
106
|
if FormatVerify.check_file(cover_path_old, spec=self.spec_cover):
|
117
107
|
shutil.copy(cover_path_old, cover_path_new)
|
118
108
|
else:
|
119
|
-
StickerConvert(
|
109
|
+
StickerConvert(
|
110
|
+
cover_path_old, cover_path_new, opt_comp_merged, self.cb_msg
|
111
|
+
).convert()
|
120
112
|
else:
|
121
113
|
# First image in the directory, extracting first frame
|
122
|
-
first_image = [
|
123
|
-
|
124
|
-
|
114
|
+
first_image = [
|
115
|
+
i
|
116
|
+
for i in sorted(os.listdir(self.in_dir))
|
117
|
+
if os.path.isfile(os.path.join(self.in_dir, i))
|
118
|
+
and not i.endswith((".txt", ".m4a", ".wastickers"))
|
119
|
+
][0]
|
120
|
+
StickerConvert(
|
121
|
+
os.path.join(self.in_dir, f"{first_image}"),
|
122
|
+
cover_path_new,
|
123
|
+
opt_comp_merged,
|
124
|
+
self.cb_msg,
|
125
|
+
).convert()
|
126
|
+
|
125
127
|
MetadataHandler.set_metadata(pack_dir, author=author, title=title)
|
126
|
-
|
128
|
+
|
127
129
|
@staticmethod
|
128
|
-
def start(
|
129
|
-
|
130
|
-
|
130
|
+
def start(
|
131
|
+
opt_output: OutputOption,
|
132
|
+
opt_comp: CompOption,
|
133
|
+
opt_cred: CredOption,
|
134
|
+
cb_msg=print,
|
135
|
+
cb_msg_block=input,
|
136
|
+
cb_ask_bool=input,
|
137
|
+
cb_bar=None,
|
138
|
+
out_dir: Optional[str] = None,
|
139
|
+
**kwargs,
|
140
|
+
) -> list[str]:
|
141
|
+
exporter = CompressWastickers(
|
142
|
+
opt_output,
|
143
|
+
opt_comp,
|
144
|
+
opt_cred,
|
145
|
+
cb_msg,
|
146
|
+
cb_msg_block,
|
147
|
+
cb_ask_bool,
|
148
|
+
cb_bar,
|
149
|
+
out_dir,
|
150
|
+
)
|
151
|
+
return exporter.compress_wastickers()
|
@@ -1,8 +1,20 @@
|
|
1
1
|
#!/usr/bin/env python3
|
2
2
|
from typing import Optional
|
3
|
+
from ..job_option import CompOption, OutputOption, CredOption # type: ignore
|
4
|
+
|
3
5
|
|
4
6
|
class UploadBase:
|
5
|
-
def __init__(
|
7
|
+
def __init__(
|
8
|
+
self,
|
9
|
+
opt_output: OutputOption,
|
10
|
+
opt_comp: CompOption,
|
11
|
+
opt_cred: CredOption,
|
12
|
+
cb_msg=print,
|
13
|
+
cb_msg_block=input,
|
14
|
+
cb_ask_bool=input,
|
15
|
+
cb_bar=None,
|
16
|
+
out_dir: Optional[str] = None,
|
17
|
+
):
|
6
18
|
self.opt_output = opt_output
|
7
19
|
self.opt_comp = opt_comp
|
8
20
|
self.opt_cred = opt_cred
|
@@ -11,6 +23,6 @@ class UploadBase:
|
|
11
23
|
self.cb_ask_bool = cb_ask_bool
|
12
24
|
self.cb_bar = cb_bar
|
13
25
|
|
14
|
-
self.fake_vid = self.opt_comp.
|
15
|
-
self.in_dir = self.opt_output
|
16
|
-
self.out_dir = out_dir if out_dir else self.opt_output
|
26
|
+
self.fake_vid = self.opt_comp.fake_vid
|
27
|
+
self.in_dir = self.opt_output.dir
|
28
|
+
self.out_dir = out_dir if out_dir else self.opt_output.dir
|