sticker-convert 2.1.6__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.
Files changed (57) hide show
  1. sticker_convert/__init__.py +1 -1
  2. sticker_convert/__main__.py +7 -4
  3. sticker_convert/cli.py +39 -31
  4. sticker_convert/converter.py +432 -0
  5. sticker_convert/downloaders/download_base.py +40 -16
  6. sticker_convert/downloaders/download_kakao.py +103 -136
  7. sticker_convert/downloaders/download_line.py +16 -6
  8. sticker_convert/downloaders/download_signal.py +48 -32
  9. sticker_convert/downloaders/download_telegram.py +71 -26
  10. sticker_convert/gui.py +78 -129
  11. sticker_convert/{gui_frames → gui_components/frames}/comp_frame.py +2 -3
  12. sticker_convert/{gui_frames → gui_components/frames}/config_frame.py +3 -4
  13. sticker_convert/{gui_frames → gui_components/frames}/control_frame.py +2 -2
  14. sticker_convert/{gui_frames → gui_components/frames}/cred_frame.py +4 -4
  15. sticker_convert/{gui_frames → gui_components/frames}/input_frame.py +4 -4
  16. sticker_convert/{gui_frames → gui_components/frames}/output_frame.py +3 -3
  17. sticker_convert/{gui_frames → gui_components/frames}/progress_frame.py +1 -1
  18. sticker_convert/{utils → gui_components}/gui_utils.py +38 -21
  19. sticker_convert/{gui_windows → gui_components/windows}/advanced_compression_window.py +3 -2
  20. sticker_convert/{gui_windows → gui_components/windows}/base_window.py +3 -2
  21. sticker_convert/{gui_windows → gui_components/windows}/kakao_get_auth_window.py +3 -3
  22. sticker_convert/{gui_windows → gui_components/windows}/line_get_auth_window.py +2 -2
  23. sticker_convert/{gui_windows → gui_components/windows}/signal_get_auth_window.py +2 -2
  24. sticker_convert/{flow.py → job.py} +91 -102
  25. sticker_convert/job_option.py +301 -0
  26. sticker_convert/resources/compression.json +1 -1
  27. sticker_convert/uploaders/compress_wastickers.py +95 -74
  28. sticker_convert/uploaders/upload_base.py +16 -4
  29. sticker_convert/uploaders/upload_signal.py +100 -62
  30. sticker_convert/uploaders/upload_telegram.py +168 -128
  31. sticker_convert/uploaders/xcode_imessage.py +202 -132
  32. sticker_convert/{auth → utils/auth}/get_kakao_auth.py +7 -5
  33. sticker_convert/{auth → utils/auth}/get_line_auth.py +3 -3
  34. sticker_convert/{auth → utils/auth}/get_signal_auth.py +1 -1
  35. sticker_convert/utils/fake_cb_msg.py +5 -2
  36. sticker_convert/utils/{cache_store.py → files/cache_store.py} +7 -3
  37. sticker_convert/utils/files/dir_utils.py +64 -0
  38. sticker_convert/utils/{json_manager.py → files/json_manager.py} +5 -4
  39. sticker_convert/utils/files/metadata_handler.py +226 -0
  40. sticker_convert/utils/files/run_bin.py +58 -0
  41. sticker_convert/utils/{apple_png_normalize.py → media/apple_png_normalize.py} +23 -20
  42. sticker_convert/utils/{codec_info.py → media/codec_info.py} +41 -35
  43. sticker_convert/utils/media/decrypt_kakao.py +68 -0
  44. sticker_convert/utils/media/format_verify.py +184 -0
  45. sticker_convert/utils/url_detect.py +16 -14
  46. {sticker_convert-2.1.6.dist-info → sticker_convert-2.1.7.dist-info}/METADATA +8 -9
  47. {sticker_convert-2.1.6.dist-info → sticker_convert-2.1.7.dist-info}/RECORD +52 -50
  48. {sticker_convert-2.1.6.dist-info → sticker_convert-2.1.7.dist-info}/WHEEL +1 -1
  49. sticker_convert/utils/converter.py +0 -407
  50. sticker_convert/utils/curr_dir.py +0 -70
  51. sticker_convert/utils/format_verify.py +0 -188
  52. sticker_convert/utils/metadata_handler.py +0 -190
  53. sticker_convert/utils/run_bin.py +0 -46
  54. /sticker_convert/{gui_frames → gui_components/frames}/right_clicker.py +0 -0
  55. {sticker_convert-2.1.6.dist-info → sticker_convert-2.1.7.dist-info}/LICENSE +0 -0
  56. {sticker_convert-2.1.6.dist-info → sticker_convert-2.1.7.dist-info}/entry_points.txt +0 -0
  57. {sticker_convert-2.1.6.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
+ }
@@ -44,7 +44,7 @@
44
44
  "vid": 300000
45
45
  },
46
46
  "format": {
47
- "img": ".webp",
47
+ "img": ".png",
48
48
  "vid": ".apng"
49
49
  },
50
50
  "fps": {
@@ -5,98 +5,87 @@ import copy
5
5
  import zipfile
6
6
  from typing import Optional
7
7
 
8
- from mergedeep import merge # type: ignore
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
- 'size_max': {
22
- "img": 100000,
23
- "vid": 500000
24
- },
25
- 'res': {
26
- 'w': {
27
- 'min': 512,
28
- 'max': 512
29
- },
30
- 'h': {
31
- 'min': 512,
32
- 'max': 512
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['format'] = '.webp'
64
- self.webp_spec['animated'] = None if self.fake_vid else True
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['format'] = '.png'
68
- self.png_spec['animated'] = False
40
+ self.png_spec.format = ".png"
41
+ self.png_spec.animated = False
69
42
 
70
- self.opt_comp_merged = merge({}, self.opt_comp, base_spec)
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(self.in_dir, title=self.opt_output.get('title'), author=self.opt_output.get('author'))
75
- packs = MetadataHandler.split_sticker_packs(self.in_dir, title=title, file_per_pack=30, separate_image_anim=not self.fake_vid)
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 # Originally the Sticker Maker application name the files with int(time.time())
79
- with CacheStore.get_cache_store(path=self.opt_comp.get('cache_dir')) as tempdir:
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'Verifying {src} for compressing into .wastickers')
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 = '.webp'
69
+ ext = ".webp"
85
70
  else:
86
- ext = '.png'
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 FormatVerify.check_file(src, spec=self.png_spec):
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(self.out_dir, FormatVerify.sanitize_filename(pack_title + '.wastickers'))
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, 'w', zipfile.ZIP_DEFLATED) as zipf:
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 = merge({}, self.opt_comp, self.spec_cover)
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, '100.png')
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(cover_path_old, cover_path_new, opt_comp_merged, self.cb_msg).convert()
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 = [i for i in sorted(os.listdir(self.in_dir)) if os.path.isfile(os.path.join(self.in_dir, i)) and not i.endswith(('.txt', '.m4a', '.wastickers'))][0]
123
- StickerConvert(os.path.join(self.in_dir, f'{first_image}'), cover_path_new, opt_comp_merged, self.cb_msg).convert()
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(opt_output: dict, opt_comp: dict, opt_cred: dict, cb_msg=print, cb_msg_block=input, cb_ask_bool=input, cb_bar=None, out_dir: Optional[str] = None, **kwargs) -> list[str]:
129
- exporter = CompressWastickers(opt_output, opt_comp, opt_cred, cb_msg, cb_msg_block, cb_ask_bool, cb_bar, out_dir)
130
- return exporter.compress_wastickers()
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__(self, opt_output: dict, opt_comp: dict, opt_cred: dict, cb_msg=print, cb_msg_block=input, cb_ask_bool=input, cb_bar=None, out_dir: Optional[str] = None):
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.get('fake_vid', False)
15
- self.in_dir = self.opt_output['dir']
16
- self.out_dir = out_dir if out_dir else self.opt_output['dir']
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