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
@@ -6,70 +6,115 @@ import anyio
6
6
  from telegram import Bot
7
7
  from telegram.error import TelegramError
8
8
 
9
- from .download_base import DownloadBase # type: ignore
10
- from ..utils.metadata_handler import MetadataHandler # type: ignore
9
+ from .download_base import DownloadBase # type: ignore
10
+ from ..utils.files.metadata_handler import MetadataHandler # type: ignore
11
+ from ..job_option import CredOption # type: ignore
12
+
11
13
 
12
14
  class DownloadTelegram(DownloadBase):
13
15
  def __init__(self, *args, **kwargs):
14
16
  super(DownloadTelegram, self).__init__(*args, **kwargs)
15
-
17
+
16
18
  def download_stickers_telegram(self) -> bool:
17
- self.token = self.opt_cred.get('telegram', {}).get('token')
19
+ self.token = self.opt_cred.telegram_token
18
20
  if self.token == None:
19
- self.cb_msg('Download failed: Token required for downloading from telegram')
21
+ self.cb_msg("Download failed: Token required for downloading from telegram")
20
22
  return False
21
-
22
- if not ('telegram.me' in self.url or 't.me' in self.url):
23
- self.cb_msg('Download failed: Unrecognized URL format')
23
+
24
+ if not ("telegram.me" in self.url or "t.me" in self.url):
25
+ self.cb_msg("Download failed: Unrecognized URL format")
24
26
  return False
25
27
 
26
28
  self.title = ""
27
29
  try:
28
- self.title = self.url.split("/addstickers/")[1].split('?')[0]
30
+ self.title = self.url.split("/addstickers/")[1].split("?")[0]
29
31
  except IndexError:
30
- self.title = self.url.split("eu/stickers/")[1].split('?')[0]
31
-
32
+ self.title = self.url.split("eu/stickers/")[1].split("?")[0]
33
+
32
34
  return anyio.run(self.save_stickers)
33
35
 
34
36
  async def save_stickers(self) -> bool:
35
37
  bot = Bot(self.token)
36
38
  async with bot:
37
39
  try:
38
- sticker_set = await bot.get_sticker_set(self.title, read_timeout=30, write_timeout=30, connect_timeout=30, pool_timeout=30)
40
+ sticker_set = await bot.get_sticker_set(
41
+ self.title,
42
+ read_timeout=30,
43
+ write_timeout=30,
44
+ connect_timeout=30,
45
+ pool_timeout=30,
46
+ )
39
47
  except TelegramError as e:
40
- self.cb_msg(f'Failed to download telegram sticker set {self.title} due to: {e}')
48
+ self.cb_msg(
49
+ f"Failed to download telegram sticker set {self.title} due to: {e}"
50
+ )
41
51
  return False
42
52
 
43
53
  if self.cb_bar:
44
- self.cb_bar(set_progress_mode='determinate', steps=len(sticker_set.stickers))
54
+ self.cb_bar(
55
+ set_progress_mode="determinate", steps=len(sticker_set.stickers)
56
+ )
45
57
 
46
58
  emoji_dict = {}
47
59
  num = 0
48
60
  for i in sticker_set.stickers:
49
- sticker = await i.get_file(read_timeout=30, write_timeout=30, connect_timeout=30, pool_timeout=30)
61
+ sticker = await i.get_file(
62
+ read_timeout=30,
63
+ write_timeout=30,
64
+ connect_timeout=30,
65
+ pool_timeout=30,
66
+ )
50
67
  ext = os.path.splitext(sticker.file_path)[-1]
51
68
  f_id = str(num).zfill(3)
52
69
  f_name = f_id + ext
53
70
  f_path = os.path.join(self.out_dir, f_name)
54
- await sticker.download_to_drive(custom_path=f_path, read_timeout=30, write_timeout=30, connect_timeout=30, pool_timeout=30)
71
+ await sticker.download_to_drive(
72
+ custom_path=f_path,
73
+ read_timeout=30,
74
+ write_timeout=30,
75
+ connect_timeout=30,
76
+ pool_timeout=30,
77
+ )
55
78
  emoji_dict[f_id] = i.emoji
56
- self.cb_msg(f'Downloaded {f_name}')
79
+ self.cb_msg(f"Downloaded {f_name}")
57
80
  if self.cb_bar:
58
81
  self.cb_bar(update_bar=True)
59
82
  num += 1
60
-
83
+
61
84
  if sticker_set.thumbnail:
62
- cover = await sticker_set.thumbnail.get_file(read_timeout=30, write_timeout=30, connect_timeout=30, pool_timeout=30)
85
+ cover = await sticker_set.thumbnail.get_file(
86
+ read_timeout=30,
87
+ write_timeout=30,
88
+ connect_timeout=30,
89
+ pool_timeout=30,
90
+ )
63
91
  cover_ext = os.path.splitext(cover.file_path)[-1]
64
- cover_name = 'cover' + cover_ext
92
+ cover_name = "cover" + cover_ext
65
93
  cover_path = os.path.join(self.out_dir, cover_name)
66
- await cover.download_to_drive(custom_path=cover_path, read_timeout=30, write_timeout=30, connect_timeout=30, pool_timeout=30)
67
- self.cb_msg(f'Downloaded {cover_name}')
94
+ await cover.download_to_drive(
95
+ custom_path=cover_path,
96
+ read_timeout=30,
97
+ write_timeout=30,
98
+ connect_timeout=30,
99
+ pool_timeout=30,
100
+ )
101
+ self.cb_msg(f"Downloaded {cover_name}")
68
102
 
69
- MetadataHandler.set_metadata(self.out_dir, title=self.title, emoji_dict=emoji_dict)
103
+ MetadataHandler.set_metadata(
104
+ self.out_dir, title=self.title, emoji_dict=emoji_dict
105
+ )
70
106
  return True
71
107
 
72
108
  @staticmethod
73
- def start(url: str, out_dir: str, opt_cred: Optional[dict] = None, cb_msg=print, cb_msg_block=input, cb_bar=None) -> bool:
74
- downloader = DownloadTelegram(url, out_dir, opt_cred, cb_msg, cb_msg_block, cb_bar)
75
- return downloader.download_stickers_telegram()
109
+ def start(
110
+ url: str,
111
+ out_dir: str,
112
+ opt_cred: Optional[CredOption] = None,
113
+ cb_msg=print,
114
+ cb_msg_block=input,
115
+ cb_bar=None,
116
+ ) -> bool:
117
+ downloader = DownloadTelegram(
118
+ url, out_dir, opt_cred, cb_msg, cb_msg_block, cb_bar
119
+ )
120
+ return downloader.download_stickers_telegram()
sticker_convert/gui.py CHANGED
@@ -16,21 +16,22 @@ from PIL import ImageFont
16
16
  from ttkbootstrap import Window, StringVar, BooleanVar, IntVar # type: ignore
17
17
  from ttkbootstrap.dialogs import Messagebox, Querybox # type: ignore
18
18
 
19
- from .flow import Flow # type: ignore
20
- from .utils.json_manager import JsonManager # type: ignore
21
- from .utils.curr_dir import CurrDir # type: ignore
22
- from .utils.metadata_handler import MetadataHandler # type: ignore
19
+ from .job import Job # type: ignore
20
+ from .job_option import InputOption, CompOption, OutputOption, CredOption # type: ignore
21
+ from .utils.files.json_manager import JsonManager # type: ignore
22
+ from .utils.files.dir_utils import DirUtils # type: ignore
23
+ from .utils.files.metadata_handler import MetadataHandler # type: ignore
23
24
  from .utils.url_detect import UrlDetect # type: ignore
24
- from .utils.gui_utils import GUIUtils # type: ignore
25
+ from .gui_components.gui_utils import GUIUtils # type: ignore
25
26
  from .__init__ import __version__ # type: ignore
26
27
 
27
- from .gui_frames.input_frame import InputFrame # type: ignore
28
- from .gui_frames.comp_frame import CompFrame # type: ignore
29
- from .gui_frames.cred_frame import CredFrame # type: ignore
30
- from .gui_frames.output_frame import OutputFrame # type: ignore
31
- from .gui_frames.config_frame import ConfigFrame # type: ignore
32
- from .gui_frames.progress_frame import ProgressFrame # type: ignore
33
- from .gui_frames.control_frame import ControlFrame # type: ignore
28
+ from .gui_components.frames.input_frame import InputFrame # type: ignore
29
+ from .gui_components.frames.comp_frame import CompFrame # type: ignore
30
+ from .gui_components.frames.cred_frame import CredFrame # type: ignore
31
+ from .gui_components.frames.output_frame import OutputFrame # type: ignore
32
+ from .gui_components.frames.config_frame import ConfigFrame # type: ignore
33
+ from .gui_components.frames.progress_frame import ProgressFrame # type: ignore
34
+ from .gui_components.frames.control_frame import ControlFrame # type: ignore
34
35
 
35
36
  class GUI(Window):
36
37
  def __init__(self):
@@ -73,7 +74,7 @@ class GUI(Window):
73
74
  self.mainloop()
74
75
 
75
76
  def quit(self):
76
- if self.flow:
77
+ if self.job:
77
78
  response = self.cb_ask_bool('Job is running, really quit?')
78
79
  if response == False:
79
80
  return
@@ -86,7 +87,7 @@ class GUI(Window):
86
87
  else:
87
88
  self.delete_creds()
88
89
 
89
- if self.flow:
90
+ if self.job:
90
91
  self.cancel_job()
91
92
  self.destroy()
92
93
 
@@ -157,7 +158,7 @@ class GUI(Window):
157
158
  self.response_dict_lock = Lock()
158
159
  self.response_dict = {}
159
160
  self.action_queue = Queue()
160
- self.flow = None
161
+ self.job = None
161
162
 
162
163
  def init_frames(self):
163
164
  self.input_frame = InputFrame(self, self.scrollable_frame, borderwidth=1, text='Input')
@@ -181,11 +182,12 @@ class GUI(Window):
181
182
  if (platform.system() == 'Darwin' and
182
183
  platform.mac_ver()[0].split('.')[0] == '14' and
183
184
  sys.version_info[0] == 3 and
184
- sys.version_info[1] == 11):
185
+ sys.version_info[1] == 11 and
186
+ sys.version_info[2] <= 6):
185
187
  msg = 'NOTICE: If buttons are not responsive, try to press '
186
188
  msg += 'on title bar or move mouse cursor away from window for a while.'
187
189
  self.cb_msg(msg)
188
- msg = '(This is due to a bug in tkinter specific to macOS 14 python3.11)'
190
+ msg = '(This is due to a bug in tkinter specific to macOS 14 python <=3.11.6)'
189
191
  self.cb_msg(msg)
190
192
  msg = '(https://github.com/python/cpython/issues/110218)'
191
193
  self.cb_msg(msg)
@@ -201,13 +203,13 @@ class GUI(Window):
201
203
  Messagebox.show_error(message='Warning: json(s) under "resources" directory cannot be found', title='sticker-convert')
202
204
  sys.exit()
203
205
 
204
- self.settings_path = os.path.join(CurrDir.get_config_dir(), 'config.json')
206
+ self.settings_path = os.path.join(DirUtils.get_config_dir(), 'config.json')
205
207
  if os.path.isfile(self.settings_path):
206
208
  self.settings = JsonManager.load_json(self.settings_path)
207
209
  else:
208
210
  self.settings = {}
209
211
 
210
- self.creds_path = os.path.join(CurrDir.get_config_dir(), 'creds.json')
212
+ self.creds_path = os.path.join(DirUtils.get_config_dir(), 'creds.json')
211
213
  if os.path.isfile(self.creds_path):
212
214
  self.creds = JsonManager.load_json(self.creds_path)
213
215
  else:
@@ -216,54 +218,14 @@ class GUI(Window):
216
218
  def save_config(self):
217
219
  # Only update comp_custom if custom preset is selected
218
220
  if self.comp_preset_var.get() == 'custom':
219
- comp_custom = {
220
- 'size_max': {
221
- 'img': self.img_size_max_var.get() if not self.size_disable_var.get() else None,
222
- 'vid': self.vid_size_max_var.get() if not self.size_disable_var.get() else None
223
- },
224
- 'format': {
225
- 'img': self.img_format_var.get(),
226
- 'vid': self.vid_format_var.get()
227
- },
228
- 'fps': {
229
- 'min': self.fps_min_var.get() if not self.fps_disable_var.get() else None,
230
- 'max': self.fps_max_var.get() if not self.fps_disable_var.get() else None
231
- },
232
- 'res': {
233
- 'w': {
234
- 'min': self.res_w_min_var.get() if not self.res_w_disable_var.get() else None,
235
- 'max': self.res_w_max_var.get() if not self.res_w_disable_var.get() else None
236
- },
237
- 'h': {
238
- 'min': self.res_h_min_var.get() if not self.res_h_disable_var.get() else None,
239
- 'max': self.res_h_max_var.get() if not self.res_h_disable_var.get() else None
240
- }
241
- },
242
- 'quality': {
243
- 'min': self.quality_min_var.get() if not self.quality_disable_var.get() else None,
244
- 'max': self.quality_max_var.get() if not self.quality_disable_var.get() else None
245
- },
246
- 'color': {
247
- 'min': self.color_min_var.get() if not self.color_disable_var.get() else None,
248
- 'max': self.color_max_var.get() if not self.color_disable_var.get() else None
249
- },
250
- 'duration': {
251
- 'min': self.duration_min_var.get() if not self.duration_disable_var.get() else None,
252
- 'max': self.duration_max_var.get() if not self.duration_disable_var.get() else None
253
- },
254
- 'steps': self.steps_var.get(),
255
- 'fake_vid': self.fake_vid_var.get(),
256
- 'default_emoji': self.default_emoji_var.get(),
257
- }
221
+ comp_custom = self.get_opt_comp()
222
+ del comp_custom['preset']
223
+ del comp_custom['no_compress']
258
224
  else:
259
225
  comp_custom = self.compression_presets.get('custom')
260
226
 
261
227
  self.settings = {
262
- 'input': {
263
- 'option': self.get_input_name(),
264
- 'url': self.input_address_var.get(),
265
- 'dir': self.input_setdir_var.get()
266
- },
228
+ 'input': self.get_opt_input(),
267
229
  'comp': {
268
230
  'no_compress': self.no_compress_var.get(),
269
231
  'preset': self.comp_preset_var.get(),
@@ -271,12 +233,7 @@ class GUI(Window):
271
233
  'processes': self.processes_var.get()
272
234
  },
273
235
  'comp_custom': comp_custom,
274
- 'output': {
275
- 'option': self.get_output_name(),
276
- 'dir': self.output_setdir_var.get(),
277
- 'title': self.title_var.get(),
278
- 'author': self.author_var.get()
279
- },
236
+ 'output': self.get_opt_output(),
280
237
  'creds': {
281
238
  'save_cred': self.settings_save_cred_var.get()
282
239
  }
@@ -285,26 +242,7 @@ class GUI(Window):
285
242
  JsonManager.save_json(self.settings_path, self.settings)
286
243
 
287
244
  def save_creds(self):
288
- self.creds = {
289
- 'signal': {
290
- 'uuid': self.signal_uuid_var.get(),
291
- 'password': self.signal_password_var.get()
292
- },
293
- 'telegram': {
294
- 'token': self.telegram_token_var.get(),
295
- 'userid': self.telegram_userid_var.get()
296
- },
297
- 'kakao': {
298
- 'auth_token': self.kakao_auth_token_var.get(),
299
- 'username': self.kakao_username_var.get(),
300
- 'password': self.kakao_password_var.get(),
301
- 'country_code': self.kakao_country_code_var.get(),
302
- 'phone_number': self.kakao_phone_number_var.get()
303
- },
304
- 'line': {
305
- 'cookies': self.line_cookies_var.get()
306
- }
307
- }
245
+ self.creds = self.get_opt_cred()
308
246
 
309
247
  JsonManager.save_json(self.creds_path, self.creds)
310
248
 
@@ -317,38 +255,34 @@ class GUI(Window):
317
255
  os.remove(self.settings_path)
318
256
 
319
257
  def apply_config(self):
258
+ # Input
320
259
  self.default_input_mode = self.settings.get('input', {}).get('option', 'auto')
321
260
  self.input_address_var.set(self.settings.get('input', {}).get('url', ''))
322
-
323
- default_stickers_input_dir = os.path.join(CurrDir.get_curr_dir(), 'stickers_input')
261
+ default_stickers_input_dir = os.path.join(DirUtils.get_curr_dir(), 'stickers_input')
324
262
  self.input_setdir_var.set(self.settings.get('input', {}).get('dir', default_stickers_input_dir))
325
263
  if not os.path.isdir(self.input_setdir_var.get()):
326
264
  self.input_setdir_var.set(default_stickers_input_dir)
265
+ self.input_option_display_var.set(self.input_presets[self.default_input_mode]['full_name'])
266
+ self.input_option_true_var.set(self.input_presets[self.default_input_mode]['full_name'])
327
267
 
268
+ # Compression
328
269
  self.no_compress_var.set(self.settings.get('comp', {}).get('no_compress', False))
329
-
330
270
  default_comp_preset = list(self.compression_presets.keys())[0]
331
271
  self.comp_preset_var.set(self.settings.get('comp', {}).get('preset', default_comp_preset))
332
-
272
+ if self.settings.get('comp_custom'):
273
+ self.compression_presets['custom'] = self.settings.get('comp_custom')
333
274
  self.cache_dir_var.set(self.settings.get('comp', {}).get('cache_dir', ''))
334
275
  self.processes_var.set(self.settings.get('comp', {}).get('processes', math.ceil(cpu_count() / 2)))
335
276
  self.default_output_mode = self.settings.get('output', {}).get('option', 'signal')
336
277
 
337
- default_stickers_output_dir = os.path.join(CurrDir.get_curr_dir(), 'stickers_output')
278
+ # Output
279
+ default_stickers_output_dir = os.path.join(DirUtils.get_curr_dir(), 'stickers_output')
338
280
  self.output_setdir_var.set(self.settings.get('output', {}).get('dir', default_stickers_output_dir))
339
281
  if not os.path.isdir(self.output_setdir_var.get()):
340
282
  self.output_setdir_var.set(default_stickers_output_dir)
341
-
342
283
  self.title_var.set(self.settings.get('output', {}).get('title', ''))
343
284
  self.author_var.set(self.settings.get('output', {}).get('author', ''))
344
285
  self.settings_save_cred_var.set(self.settings.get('creds', {}).get('save_cred', True))
345
-
346
- if self.settings.get('comp_custom'):
347
- self.compression_presets['custom'] = self.settings.get('comp_custom')
348
-
349
- self.input_option_display_var.set(self.input_presets[self.default_input_mode]['full_name'])
350
- self.input_option_true_var.set(self.input_presets[self.default_input_mode]['full_name'])
351
-
352
286
  self.output_option_display_var.set(self.output_presets[self.default_output_mode]['full_name'])
353
287
  self.output_option_true_var.set(self.output_presets[self.default_output_mode]['full_name'])
354
288
 
@@ -392,31 +326,24 @@ class GUI(Window):
392
326
 
393
327
  def start_job(self):
394
328
  Thread(target=self.start_process, daemon=True).start()
395
-
396
- def start_process(self):
397
- self.save_config()
398
- if self.settings_save_cred_var.get() == True:
399
- self.save_creds()
400
- else:
401
- self.delete_creds()
402
-
403
- self.control_frame.start_btn.config(text='Cancel', bootstyle='danger')
404
- self.set_inputs('disabled')
405
329
 
406
- opt_input = {
330
+ def get_opt_input(self) -> dict:
331
+ return {
407
332
  'option': self.get_input_name(),
408
333
  'url': self.input_address_var.get(),
409
334
  'dir': self.input_setdir_var.get()
410
335
  }
411
-
412
- opt_output = {
336
+
337
+ def get_opt_output(self) -> dict:
338
+ return {
413
339
  'option': self.get_output_name(),
414
340
  'dir': self.output_setdir_var.get(),
415
341
  'title': self.title_var.get(),
416
342
  'author': self.author_var.get()
417
343
  }
418
-
419
- opt_comp = {
344
+
345
+ def get_opt_comp(self) -> dict:
346
+ return {
420
347
  'preset': self.get_preset(),
421
348
  'size_max': {
422
349
  'img': self.img_size_max_var.get() if not self.size_disable_var.get() else None,
@@ -459,8 +386,9 @@ class GUI(Window):
459
386
  'no_compress': self.no_compress_var.get(),
460
387
  'processes': self.processes_var.get()
461
388
  }
462
-
463
- opt_cred = {
389
+
390
+ def get_opt_cred(self) -> dict:
391
+ return {
464
392
  'signal': {
465
393
  'uuid': self.signal_uuid_var.get(),
466
394
  'password': self.signal_password_var.get()
@@ -480,16 +408,30 @@ class GUI(Window):
480
408
  'cookies': self.line_cookies_var.get()
481
409
  }
482
410
  }
411
+
412
+ def start_process(self):
413
+ self.save_config()
414
+ if self.settings_save_cred_var.get() == True:
415
+ self.save_creds()
416
+ else:
417
+ self.delete_creds()
418
+
419
+ self.control_frame.start_btn.config(text='Cancel', bootstyle='danger')
420
+ self.set_inputs('disabled')
421
+
422
+ opt_input = InputOption(self.get_opt_input())
423
+ opt_output = OutputOption(self.get_opt_output())
424
+ opt_comp = CompOption(self.get_opt_comp())
425
+ opt_cred = CredOption(self.get_opt_cred())
483
426
 
484
- self.flow = Flow(
427
+ self.job = Job(
485
428
  opt_input, opt_comp, opt_output, opt_cred,
486
- self.input_presets, self.output_presets,
487
429
  self.cb_msg, self.cb_msg_block, self.cb_bar, self.cb_ask_bool
488
430
  )
489
431
 
490
- status = self.flow.start()
432
+ status = self.job.start()
491
433
 
492
- self.flow = None
434
+ self.job = None
493
435
 
494
436
  if status == 1:
495
437
  self.cb_msg(msg='An error occured during this run.')
@@ -505,10 +447,10 @@ class GUI(Window):
505
447
 
506
448
  def cancel_job(self):
507
449
  self.cb_msg(msg='Cancelling job...')
508
- self.flow.is_cancel_job.value = 1
509
- while not self.flow.jobs_queue.empty():
510
- self.flow.jobs_queue.get()
511
- for process in self.flow.processes:
450
+ self.job.is_cancel_job.value = 1
451
+ while not self.job.jobs_queue.empty():
452
+ self.job.jobs_queue.get()
453
+ for process in self.job.processes:
512
454
  process.terminate()
513
455
  process.join()
514
456
 
@@ -559,7 +501,11 @@ class GUI(Window):
559
501
  response = self.get_response_from_id(response_id)
560
502
  return response
561
503
 
562
- def cb_ask_str(self, question: str, initialvalue: Optional[str] = None, cli_show_initialvalue: bool = True, parent: Optional[object] = None) -> str:
504
+ def cb_ask_str(self,
505
+ question: str,
506
+ initialvalue: Optional[str] = None,
507
+ cli_show_initialvalue: bool = True,
508
+ parent: Optional[object] = None) -> str:
563
509
  return self.exec_in_main(partial(Querybox.get_string, question, title='sticker-convert', initialvalue=initialvalue, parent=parent))
564
510
 
565
511
  def cb_ask_bool(self, question, parent=None) -> bool:
@@ -573,7 +519,10 @@ class GUI(Window):
573
519
  with self.msg_lock:
574
520
  self.progress_frame.update_message_box(*args, **kwargs)
575
521
 
576
- def cb_msg_block(self, message: Optional[str] = None, parent: Optional[object] = None, *args, **kwargs):
522
+ def cb_msg_block(self,
523
+ message: Optional[str] = None,
524
+ parent: Optional[object] = None,
525
+ *args, **kwargs):
577
526
  if message == None and len(args) > 0:
578
527
  message = ' '.join(str(i) for i in args)
579
528
  self.exec_in_main(partial(Messagebox.show_info, message, title='sticker-convert', parent=parent))
@@ -3,10 +3,9 @@ from ttkbootstrap import LabelFrame, OptionMenu, Button, Entry, Label, Checkbutt
3
3
  from typing import TYPE_CHECKING
4
4
 
5
5
  if TYPE_CHECKING:
6
- from ..gui import GUI # type: ignore
7
- from ..gui_windows.advanced_compression_window import AdvancedCompressionWindow # type: ignore
6
+ from ...gui import GUI # type: ignore
7
+ from ..windows.advanced_compression_window import AdvancedCompressionWindow # type: ignore
8
8
  from .right_clicker import RightClicker # type: ignore
9
- from ..__init__ import __version__ # type: ignore
10
9
 
11
10
  class CompFrame(LabelFrame):
12
11
  def __init__(self, gui: "GUI", *args, **kwargs):
@@ -7,9 +7,8 @@ from ttkbootstrap import LabelFrame, Button, Label, Checkbutton # type: ignore
7
7
 
8
8
  if TYPE_CHECKING:
9
9
  from ..gui import GUI # type: ignore
10
- from ..utils.curr_dir import CurrDir # type: ignore
11
- from ..utils.run_bin import RunBin # type: ignore
12
- from ..__init__ import __version__ # type: ignore
10
+ from ...utils.files.dir_utils import DirUtils # type: ignore
11
+ from ...utils.files.run_bin import RunBin # type: ignore
13
12
 
14
13
  class ConfigFrame(LabelFrame):
15
14
  def __init__(self, gui: "GUI", *args, **kwargs):
@@ -62,7 +61,7 @@ class ConfigFrame(LabelFrame):
62
61
  self.gui.cb_msg_block('Restored to default config.')
63
62
 
64
63
  def cb_open_config_directory(self, *args, **kwargs):
65
- config_dir = CurrDir.get_config_dir()
64
+ config_dir = DirUtils.get_config_dir()
66
65
  self.gui.cb_msg(msg=f'Config is located at {config_dir}')
67
66
  if platform.system() == 'Windows':
68
67
  os.startfile(config_dir)
@@ -4,7 +4,7 @@ from typing import TYPE_CHECKING
4
4
  from ttkbootstrap import Frame, Button # type: ignore
5
5
 
6
6
  if TYPE_CHECKING:
7
- from ..gui import GUI # type: ignore
7
+ from ...gui import GUI # type: ignore
8
8
 
9
9
  class ControlFrame(Frame):
10
10
  def __init__(self, gui: "GUI", *args, **kwargs):
@@ -16,7 +16,7 @@ class ControlFrame(Frame):
16
16
  self.start_btn.pack(expand=True, fill='x')
17
17
 
18
18
  def cb_start_btn(self, *args, **kwargs):
19
- if self.gui.flow:
19
+ if self.gui.job:
20
20
  response = self.gui.cb_ask_bool('Cancel job?')
21
21
  if response == True:
22
22
  self.gui.cancel_job()
@@ -5,10 +5,10 @@ from typing import TYPE_CHECKING
5
5
  from ttkbootstrap import LabelFrame, Button, Entry, Label # type: ignore
6
6
 
7
7
  if TYPE_CHECKING:
8
- from ..gui import GUI # type: ignore
9
- from ..gui_windows.signal_get_auth_window import SignalGetAuthWindow # type: ignore
10
- from ..gui_windows.line_get_auth_window import LineGetAuthWindow # type: ignore
11
- from ..gui_windows.kakao_get_auth_window import KakaoGetAuthWindow # type: ignore
8
+ from ...gui import GUI # type: ignore
9
+ from ..windows.signal_get_auth_window import SignalGetAuthWindow # type: ignore
10
+ from ..windows.line_get_auth_window import LineGetAuthWindow # type: ignore
11
+ from ..windows.kakao_get_auth_window import KakaoGetAuthWindow # type: ignore
12
12
  from .right_clicker import RightClicker # type: ignore
13
13
 
14
14
  class CredFrame(LabelFrame):
@@ -6,9 +6,9 @@ from tkinter import filedialog
6
6
  from ttkbootstrap import LabelFrame, OptionMenu, Button, Entry, Label # type: ignore
7
7
 
8
8
  if TYPE_CHECKING:
9
- from ..gui import GUI # type: ignore
10
- from ..utils.url_detect import UrlDetect # type: ignore
11
- from ..utils.curr_dir import CurrDir # type: ignore
9
+ from ...gui import GUI # type: ignore
10
+ from ...utils.url_detect import UrlDetect # type: ignore
11
+ from ...utils.files.dir_utils import DirUtils # type: ignore
12
12
  from .right_clicker import RightClicker # type: ignore
13
13
 
14
14
  class InputFrame(LabelFrame):
@@ -50,7 +50,7 @@ class InputFrame(LabelFrame):
50
50
  def cb_set_indir(self, *args):
51
51
  orig_input_dir = self.gui.input_setdir_var.get()
52
52
  if not os.path.isdir(orig_input_dir):
53
- orig_input_dir = CurrDir.get_curr_dir()
53
+ orig_input_dir = DirUtils.get_curr_dir()
54
54
  input_dir = filedialog.askdirectory(initialdir=orig_input_dir)
55
55
  if input_dir:
56
56
  self.gui.input_setdir_var.set(input_dir)
@@ -6,8 +6,8 @@ from tkinter import filedialog
6
6
  from ttkbootstrap import LabelFrame, OptionMenu, Button, Entry, Label # type: ignore
7
7
 
8
8
  if TYPE_CHECKING:
9
- from ..gui import GUI # type: ignore
10
- from ..utils.curr_dir import CurrDir # type: ignore
9
+ from ...gui import GUI # type: ignore
10
+ from ...utils.files.dir_utils import DirUtils # type: ignore
11
11
  from .right_clicker import RightClicker # type: ignore
12
12
 
13
13
  class OutputFrame(LabelFrame):
@@ -48,7 +48,7 @@ class OutputFrame(LabelFrame):
48
48
  def cb_set_outdir(self, *args):
49
49
  orig_output_dir = self.gui.output_setdir_var.get()
50
50
  if not os.path.isdir(orig_output_dir):
51
- orig_output_dir = CurrDir.get_curr_dir()
51
+ orig_output_dir = DirUtils.get_curr_dir()
52
52
  output_dir = filedialog.askdirectory(initialdir=orig_output_dir)
53
53
  if output_dir:
54
54
  self.gui.output_setdir_var.set(output_dir)
@@ -6,7 +6,7 @@ from ttkbootstrap.scrolled import ScrolledText # type: ignore
6
6
  from tqdm import tqdm
7
7
 
8
8
  if TYPE_CHECKING:
9
- from ..gui import GUI # type: ignore
9
+ from ...gui import GUI # type: ignore
10
10
  from .right_clicker import RightClicker # type: ignore
11
11
 
12
12
  class ProgressFrame(LabelFrame):