sticker-convert 2.13.3.0__py3-none-any.whl → 2.15.0.0__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 (41) hide show
  1. sticker_convert/auth/__init__.py +0 -0
  2. sticker_convert/auth/auth_base.py +19 -0
  3. sticker_convert/{utils/auth/get_discord_auth.py → auth/auth_discord.py} +40 -13
  4. sticker_convert/{utils/auth/get_kakao_auth.py → auth/auth_kakao_android_login.py} +80 -84
  5. sticker_convert/auth/auth_kakao_desktop_login.py +323 -0
  6. sticker_convert/{utils/auth/get_kakao_desktop_auth.py → auth/auth_kakao_desktop_memdump.py} +21 -12
  7. sticker_convert/{utils/auth/get_line_auth.py → auth/auth_line.py} +21 -6
  8. sticker_convert/{utils/auth/get_signal_auth.py → auth/auth_signal.py} +18 -20
  9. sticker_convert/auth/auth_telethon.py +151 -0
  10. sticker_convert/{utils/auth/get_viber_auth.py → auth/auth_viber.py} +19 -11
  11. sticker_convert/{utils/auth → auth}/telegram_api.py +10 -18
  12. sticker_convert/cli.py +57 -67
  13. sticker_convert/converter.py +4 -4
  14. sticker_convert/downloaders/download_line.py +2 -2
  15. sticker_convert/downloaders/download_telegram.py +1 -1
  16. sticker_convert/gui.py +20 -100
  17. sticker_convert/gui_components/frames/comp_frame.py +12 -4
  18. sticker_convert/gui_components/frames/config_frame.py +14 -6
  19. sticker_convert/gui_components/frames/control_frame.py +1 -1
  20. sticker_convert/gui_components/frames/cred_frame.py +6 -8
  21. sticker_convert/gui_components/windows/advanced_compression_window.py +3 -4
  22. sticker_convert/gui_components/windows/base_window.py +7 -2
  23. sticker_convert/gui_components/windows/discord_get_auth_window.py +3 -7
  24. sticker_convert/gui_components/windows/kakao_get_auth_window.py +272 -97
  25. sticker_convert/gui_components/windows/line_get_auth_window.py +5 -14
  26. sticker_convert/gui_components/windows/signal_get_auth_window.py +4 -12
  27. sticker_convert/gui_components/windows/viber_get_auth_window.py +8 -11
  28. sticker_convert/job.py +16 -32
  29. sticker_convert/job_option.py +1 -0
  30. sticker_convert/resources/NotoColorEmoji.ttf +0 -0
  31. sticker_convert/resources/help.json +8 -6
  32. sticker_convert/uploaders/upload_telegram.py +1 -1
  33. sticker_convert/utils/callback.py +238 -6
  34. sticker_convert/version.py +1 -1
  35. {sticker_convert-2.13.3.0.dist-info → sticker_convert-2.15.0.0.dist-info}/METADATA +41 -42
  36. {sticker_convert-2.13.3.0.dist-info → sticker_convert-2.15.0.0.dist-info}/RECORD +40 -37
  37. sticker_convert/utils/auth/telethon_setup.py +0 -97
  38. {sticker_convert-2.13.3.0.dist-info → sticker_convert-2.15.0.0.dist-info}/WHEEL +0 -0
  39. {sticker_convert-2.13.3.0.dist-info → sticker_convert-2.15.0.0.dist-info}/entry_points.txt +0 -0
  40. {sticker_convert-2.13.3.0.dist-info → sticker_convert-2.15.0.0.dist-info}/licenses/LICENSE +0 -0
  41. {sticker_convert-2.13.3.0.dist-info → sticker_convert-2.15.0.0.dist-info}/top_level.txt +0 -0
@@ -5,11 +5,10 @@ import platform
5
5
  import shutil
6
6
  import subprocess
7
7
  import time
8
- from functools import partial
9
- from getpass import getpass
10
8
  from pathlib import Path
11
- from typing import Callable, List, Optional, Tuple, cast
9
+ from typing import Any, Callable, List, Optional, Tuple, cast
12
10
 
11
+ from sticker_convert.auth.auth_base import AuthBase
13
12
  from sticker_convert.utils.process import check_admin, find_pid_by_name, get_mem, killall
14
13
 
15
14
  MSG_NO_BIN = """Viber Desktop not detected.
@@ -27,9 +26,9 @@ MSG_LAUNCH_FAIL = "Failed to launch Viber"
27
26
  MSG_PERMISSION_ERROR = "Failed to read Viber process memory"
28
27
 
29
28
 
30
- class GetViberAuth:
31
- def __init__(self, cb_ask_str: Callable[..., str] = input) -> None:
32
- self.cb_ask_str = cb_ask_str
29
+ class AuthViber(AuthBase):
30
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
31
+ super().__init__(*args, **kwargs)
33
32
 
34
33
  def relaunch_viber(self, viber_bin_path: str) -> Optional[int]:
35
34
  killed = killall("viber")
@@ -124,12 +123,18 @@ class GetViberAuth:
124
123
  if viber_pid is None:
125
124
  return None, MSG_LAUNCH_FAIL
126
125
 
127
- if self.cb_ask_str == input:
128
- pw_func = getpass
129
- else:
130
- pw_func = partial(
131
- self.cb_ask_str, initialvalue="", cli_show_initialvalue=False
126
+ def pw_func(msg: str) -> str:
127
+ return self.cb.put(
128
+ (
129
+ "ask_str",
130
+ None,
131
+ {
132
+ "message": msg,
133
+ "password": True,
134
+ },
135
+ )
132
136
  )
137
+
133
138
  s = get_mem(viber_pid, pw_func)
134
139
 
135
140
  if s is None:
@@ -189,6 +194,8 @@ class GetViberAuth:
189
194
  self,
190
195
  viber_bin_path: Optional[str] = None,
191
196
  ) -> Tuple[Optional[str], str]:
197
+ msg = "Getting Viber credentials...\n(This may take a minute)"
198
+ self.cb.put(("msg_dynamic", (msg,), None))
192
199
  if not viber_bin_path:
193
200
  viber_bin_path = self.get_viber_desktop()
194
201
 
@@ -232,4 +239,5 @@ class GetViberAuth:
232
239
  break
233
240
 
234
241
  killall("viber")
242
+ self.cb.put(("msg_dynamic", (None,), None))
235
243
  return viber_auth, msg
@@ -3,7 +3,7 @@ import re
3
3
  import time
4
4
  from collections import defaultdict
5
5
  from pathlib import Path
6
- from typing import Any, Dict, List, Optional, Protocol, Tuple, Union, cast
6
+ from typing import Any, Dict, List, Protocol, Tuple, Union, cast
7
7
 
8
8
  import anyio
9
9
  from telegram import InputSticker, PhotoSize, Sticker
@@ -15,8 +15,8 @@ from telethon.functions import messages # type: ignore
15
15
  from telethon.tl.types.messages import StickerSet as TLStickerSet # type: ignore
16
16
  from telethon.types import DocumentAttributeFilename, InputStickerSetShortName, InputStickerSetThumb, Message, TypeDocument # type: ignore
17
17
 
18
+ from sticker_convert.auth.auth_telethon import AuthTelethon
18
19
  from sticker_convert.job_option import CredOption
19
- from sticker_convert.utils.auth.telethon_setup import TelethonSetup
20
20
  from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
21
21
 
22
22
  # sticker_path: Path, sticker_bytes: bytes, emoji_list: List[str], sticker_format: str
@@ -67,11 +67,12 @@ class BotAPI(TelegramAPI):
67
67
  self.cb.put("Token required for downloading from telegram")
68
68
  return False
69
69
 
70
- if opt_cred.telegram_userid.isnumeric():
71
- self.telegram_userid = int(opt_cred.telegram_userid)
72
- else:
73
- self.cb.put("Invalid userid, should contain numbers only")
74
- return False
70
+ if opt_cred.telegram_userid:
71
+ if opt_cred.telegram_userid.isnumeric():
72
+ self.telegram_userid = int(opt_cred.telegram_userid)
73
+ else:
74
+ self.cb.put("Invalid userid, should contain numbers only")
75
+ return False
75
76
 
76
77
  self.application = ( # type: ignore
77
78
  ApplicationBuilder()
@@ -342,8 +343,8 @@ class TelethonAPI(TelegramAPI):
342
343
  self.cb = cb
343
344
  self.cb_return = cb_return
344
345
 
345
- success, client, _, _ = await TelethonSetup(
346
- self.opt_cred, self.cb_ask_str
346
+ success, client, _, _, _ = await AuthTelethon(
347
+ self.opt_cred, self.cb
347
348
  ).start_async()
348
349
 
349
350
  if success is True and client is not None:
@@ -353,15 +354,6 @@ class TelethonAPI(TelegramAPI):
353
354
  async def exit(self) -> None:
354
355
  self.client.disconnect()
355
356
 
356
- def cb_ask_str(
357
- self, msg: Optional[str] = None, initialvalue: Optional[str] = None
358
- ) -> str:
359
- self.cb.put(("ask_str", (msg,), None))
360
- response = self.cb_return.get_response()
361
-
362
- assert isinstance(response, str)
363
- return response
364
-
365
357
  async def set_upload_pack_short_name(self, pack_title: str) -> str:
366
358
  self.pack_title = pack_title
367
359
  self.pack_short_name = re.sub(
sticker_convert/cli.py CHANGED
@@ -11,17 +11,18 @@ from typing import Any, Dict
11
11
 
12
12
  from mergedeep import merge # type: ignore
13
13
 
14
+ from sticker_convert.auth.auth_discord import AuthDiscord
15
+ from sticker_convert.auth.auth_kakao_android_login import AuthKakaoAndroidLogin
16
+ from sticker_convert.auth.auth_kakao_desktop_login import AuthKakaoDesktopLogin
17
+ from sticker_convert.auth.auth_kakao_desktop_memdump import AuthKakaoDesktopMemdump
18
+ from sticker_convert.auth.auth_line import AuthLine
19
+ from sticker_convert.auth.auth_signal import AuthSignal
20
+ from sticker_convert.auth.auth_telethon import AuthTelethon
21
+ from sticker_convert.auth.auth_viber import AuthViber
14
22
  from sticker_convert.definitions import CONFIG_DIR, DEFAULT_DIR
15
23
  from sticker_convert.job import Job
16
24
  from sticker_convert.job_option import CompOption, CredOption, InputOption, OutputOption
17
- from sticker_convert.utils.auth.get_discord_auth import GetDiscordAuth
18
- from sticker_convert.utils.auth.get_kakao_auth import GetKakaoAuth
19
- from sticker_convert.utils.auth.get_kakao_desktop_auth import GetKakaoDesktopAuth
20
- from sticker_convert.utils.auth.get_line_auth import GetLineAuth
21
- from sticker_convert.utils.auth.get_signal_auth import GetSignalAuth
22
- from sticker_convert.utils.auth.get_viber_auth import GetViberAuth
23
- from sticker_convert.utils.auth.telethon_setup import TelethonSetup
24
- from sticker_convert.utils.callback import Callback
25
+ from sticker_convert.utils.callback import CallbackCli
25
26
  from sticker_convert.utils.files.json_manager import JsonManager
26
27
  from sticker_convert.utils.url_detect import UrlDetect
27
28
  from sticker_convert.version import __version__
@@ -29,13 +30,13 @@ from sticker_convert.version import __version__
29
30
 
30
31
  class CLI:
31
32
  def __init__(self) -> None:
32
- self.cb = Callback()
33
+ self.cb = CallbackCli()
33
34
 
34
35
  def cli(self) -> None:
35
36
  try:
36
37
  from sticker_convert.utils.files.json_resources_loader import COMPRESSION_JSON, EMOJI_JSON, HELP_JSON, INPUT_JSON, OUTPUT_JSON
37
38
  except RuntimeError as e:
38
- self.cb.msg(str(e))
39
+ self.cb.put(str(e))
39
40
  return
40
41
 
41
42
  self.help = HELP_JSON
@@ -176,8 +177,9 @@ class CLI:
176
177
  flags_cred_bool = (
177
178
  "signal_get_auth",
178
179
  "telethon_setup",
179
- "kakao_get_auth",
180
- "kakao_get_auth_desktop",
180
+ "kakao_get_auth_desktop_memdump",
181
+ "kakao_get_auth_desktop_login",
182
+ "kakao_get_auth_android_login",
181
183
  "line_get_auth",
182
184
  "discord_get_auth",
183
185
  "save_cred",
@@ -214,15 +216,7 @@ class CLI:
214
216
  self.opt_cred = self.get_opt_cred(args)
215
217
 
216
218
  job = Job(
217
- self.opt_input,
218
- self.opt_comp,
219
- self.opt_output,
220
- self.opt_cred,
221
- self.cb.msg,
222
- self.cb.msg_block,
223
- self.cb.bar,
224
- self.cb.ask_bool,
225
- self.cb.ask_str,
219
+ self.opt_input, self.opt_comp, self.opt_output, self.opt_cred, self.cb
226
220
  )
227
221
 
228
222
  signal.signal(signal.SIGINT, job.cancel)
@@ -256,9 +250,9 @@ class CLI:
256
250
  detected_download_option = UrlDetect.detect(url)
257
251
  if detected_download_option:
258
252
  download_option = detected_download_option
259
- self.cb.msg(f"Detected URL input source: {download_option}")
253
+ self.cb.put(f"Detected URL input source: {download_option}")
260
254
  else:
261
- self.cb.msg(f"Error: Unrecognied URL input source for url: {url}")
255
+ self.cb.put(f"Error: Unrecognied URL input source for url: {url}")
262
256
  sys.exit()
263
257
 
264
258
  opt_input = InputOption(
@@ -341,21 +335,21 @@ class CLI:
341
335
  if output_option == "local":
342
336
  preset = "custom"
343
337
  args.no_compress = True
344
- self.cb.msg(
338
+ self.cb.put(
345
339
  "Auto compression option set to no_compress (Reason: Export to local directory only)"
346
340
  )
347
341
  elif "telegram_emoji" in output_option:
348
342
  preset = "telegram_emoji"
349
- self.cb.msg(f"Auto compression option set to {preset}")
343
+ self.cb.put(f"Auto compression option set to {preset}")
350
344
  elif "telegram" in output_option:
351
345
  preset = "telegram"
352
- self.cb.msg(f"Auto compression option set to {preset}")
346
+ self.cb.put(f"Auto compression option set to {preset}")
353
347
  elif output_option == "imessage":
354
348
  preset = "imessage_small"
355
- self.cb.msg(f"Auto compression option set to {preset}")
349
+ self.cb.put(f"Auto compression option set to {preset}")
356
350
  else:
357
351
  preset = output_option
358
- self.cb.msg(f"Auto compression option set to {preset}")
352
+ self.cb.put(f"Auto compression option set to {preset}")
359
353
 
360
354
  opt_comp = CompOption(
361
355
  preset=preset,
@@ -462,13 +456,13 @@ class CLI:
462
456
  try:
463
457
  creds = JsonManager.load_json(creds_path)
464
458
  except JSONDecodeError:
465
- self.cb.msg("Warning: creds.json content is corrupted")
459
+ self.cb.put("Warning: creds.json content is corrupted")
466
460
  creds = {}
467
461
  else:
468
462
  creds = {}
469
463
 
470
464
  if creds:
471
- self.cb.msg("Loaded credentials from creds.json")
465
+ self.cb.put("Loaded credentials from creds.json")
472
466
 
473
467
  opt_cred = CredOption(
474
468
  signal_uuid=args.signal_uuid
@@ -511,74 +505,70 @@ class CLI:
511
505
  else creds.get("discord", {}).get("token"),
512
506
  )
513
507
 
514
- if args.kakao_get_auth:
515
- get_kakao_auth = GetKakaoAuth(
516
- opt_cred=opt_cred,
517
- cb_msg=self.cb.msg,
518
- cb_msg_block=self.cb.msg_block,
519
- cb_ask_str=self.cb.ask_str,
520
- )
521
- auth_token = get_kakao_auth.get_cred()
508
+ if args.kakao_get_auth_android_login:
509
+ get_kakao_auth_android_login = AuthKakaoAndroidLogin(opt_cred, self.cb)
510
+ auth_token, msg = get_kakao_auth_android_login.get_cred()
522
511
 
523
512
  if auth_token:
524
513
  opt_cred.kakao_auth_token = auth_token
525
514
 
526
- self.cb.msg(f"Got auth_token successfully: {auth_token}")
515
+ self.cb.put(msg)
527
516
 
528
- if args.kakao_get_auth_desktop:
529
- get_kakao_desktop_auth = GetKakaoDesktopAuth(
530
- cb_ask_str=self.cb.ask_str,
531
- )
517
+ if args.kakao_get_auth_desktop_memdump:
518
+ get_kakao_auth_desktop_memdump = AuthKakaoDesktopMemdump(opt_cred, self.cb)
532
519
  kakao_bin_path = None
533
520
  if args.kakao_bin_path:
534
521
  kakao_bin_path = args.kakao_bin_path
535
- auth_token, msg = get_kakao_desktop_auth.get_cred(kakao_bin_path)
522
+ auth_token, msg = get_kakao_auth_desktop_memdump.get_cred(kakao_bin_path)
523
+
524
+ if auth_token:
525
+ opt_cred.kakao_auth_token = auth_token
526
+
527
+ self.cb.put(msg)
528
+
529
+ if args.kakao_get_auth_desktop_login:
530
+ get_kakao_auth_desktop_login = AuthKakaoDesktopLogin(opt_cred, self.cb)
531
+ auth_token, msg = get_kakao_auth_desktop_login.get_cred()
536
532
 
537
533
  if auth_token:
538
534
  opt_cred.kakao_auth_token = auth_token
539
535
 
540
- self.cb.msg(msg)
536
+ self.cb.put(msg)
541
537
 
542
538
  if args.signal_get_auth:
543
- m = GetSignalAuth(cb_msg=self.cb.msg, cb_ask_str=self.cb.ask_str)
539
+ m = AuthSignal(opt_cred, self.cb)
544
540
 
545
- uuid, password = m.get_cred()
541
+ uuid, password, msg = m.get_cred()
546
542
  if uuid and password:
547
543
  opt_cred.signal_uuid = uuid
548
544
  opt_cred.signal_password = password
549
545
 
550
- self.cb.msg(f"Got uuid and password successfully: {uuid}, {password}")
551
-
552
- self.cb.msg("Failed to get uuid and password")
546
+ self.cb.put(msg)
553
547
 
554
548
  if args.telethon_setup:
555
- telethon_setup = TelethonSetup(opt_cred, self.cb.ask_str)
556
- success, _, telethon_api_id, telethon_api_hash = telethon_setup.start()
549
+ telethon_setup = AuthTelethon(opt_cred, self.cb)
550
+ success, _, telethon_api_id, telethon_api_hash, msg = telethon_setup.start(
551
+ check_auth_only=True
552
+ )
557
553
 
558
554
  if success:
559
555
  opt_cred.telethon_api_id = telethon_api_id
560
556
  opt_cred.telethon_api_hash = telethon_api_hash
561
557
 
562
- self.cb.msg("Telethon setup successful")
563
- else:
564
- self.cb.msg("Telethon setup failed")
558
+ self.cb.put(msg)
565
559
 
566
560
  if args.line_get_auth:
567
- get_line_auth = GetLineAuth()
561
+ get_line_auth = AuthLine(opt_cred, self.cb)
568
562
 
569
- line_cookies = get_line_auth.get_cred()
563
+ line_cookies, msg = get_line_auth.get_cred()
570
564
 
571
565
  if line_cookies:
572
566
  opt_cred.line_cookies = line_cookies
573
567
 
574
- self.cb.msg("Got Line cookies successfully")
575
- else:
576
- self.cb.msg(
577
- "Failed to get Line cookies. Have you logged in the web browser?"
578
- )
568
+ self.cb.put(msg)
579
569
 
580
570
  if args.viber_get_auth:
581
- get_viber_auth = GetViberAuth(self.cb.ask_str)
571
+ get_viber_auth = AuthViber(opt_cred, self.cb)
582
572
 
583
573
  viber_bin_path = None
584
574
  if args.viber_bin_path:
@@ -589,20 +579,20 @@ class CLI:
589
579
  if viber_auth:
590
580
  opt_cred.viber_auth = viber_auth
591
581
 
592
- self.cb.msg(msg)
582
+ self.cb.put(msg)
593
583
 
594
584
  if args.discord_get_auth:
595
- get_discord_auth = GetDiscordAuth(self.cb.msg)
585
+ get_discord_auth = AuthDiscord(opt_cred, self.cb)
596
586
  discord_token, msg = get_discord_auth.get_cred()
597
587
 
598
588
  if discord_token:
599
589
  opt_cred.discord_token = discord_token
600
590
 
601
- self.cb.msg(msg)
591
+ self.cb.put(msg)
602
592
 
603
593
  if args.save_cred:
604
594
  creds_path = CONFIG_DIR / "creds.json"
605
595
  JsonManager.save_json(creds_path, opt_cred.to_dict())
606
- self.cb.msg("Saved credentials to creds.json")
596
+ self.cb.put("Saved credentials to creds.json")
607
597
 
608
598
  return opt_cred
@@ -111,10 +111,10 @@ def yuva_to_rgba(frame: "VideoFrame") -> "np.ndarray[Any, Any]":
111
111
  u = u.repeat(2, axis=0).repeat(2, axis=1)
112
112
  v = v.repeat(2, axis=0).repeat(2, axis=1)
113
113
 
114
- y = y.reshape((y.shape[0], y.shape[1], 1))
115
- u = u.reshape((u.shape[0], u.shape[1], 1))
116
- v = v.reshape((v.shape[0], v.shape[1], 1))
117
- a = a.reshape((a.shape[0], a.shape[1], 1))
114
+ y = y.reshape((y.shape[0], y.shape[1], 1)) # type: ignore
115
+ u = u.reshape((u.shape[0], u.shape[1], 1)) # type: ignore
116
+ v = v.reshape((v.shape[0], v.shape[1], 1)) # type: ignore
117
+ a = a.reshape((a.shape[0], a.shape[1], 1)) # type: ignore
118
118
 
119
119
  yuv_array = np.concatenate((y, u, v), axis=2)
120
120
 
@@ -14,9 +14,9 @@ import requests
14
14
  from bs4 import BeautifulSoup
15
15
  from PIL import Image
16
16
 
17
+ from sticker_convert.auth.auth_line import AuthLine
17
18
  from sticker_convert.downloaders.download_base import DownloadBase
18
19
  from sticker_convert.job_option import CredOption, InputOption
19
- from sticker_convert.utils.auth.get_line_auth import GetLineAuth
20
20
  from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
21
21
  from sticker_convert.utils.files.metadata_handler import MetadataHandler
22
22
  from sticker_convert.utils.media.apple_png_normalize import ApplePngNormalize
@@ -190,7 +190,7 @@ class DownloadLine(DownloadBase):
190
190
  'Warning: Line cookies invalid, you will not be able to add text to "Custom stickers"'
191
191
  )
192
192
 
193
- if not GetLineAuth.validate_cookies(cookies):
193
+ if not AuthLine.validate_cookies(cookies):
194
194
  self.cb.put(
195
195
  'Warning: Line cookies invalid, you will not be able to add text to "Custom stickers"'
196
196
  )
@@ -5,9 +5,9 @@ from urllib.parse import urlparse
5
5
 
6
6
  import anyio
7
7
 
8
+ from sticker_convert.auth.telegram_api import BotAPI, TelegramAPI, TelethonAPI
8
9
  from sticker_convert.downloaders.download_base import DownloadBase
9
10
  from sticker_convert.job_option import CredOption, InputOption
10
- from sticker_convert.utils.auth.telegram_api import BotAPI, TelegramAPI, TelethonAPI
11
11
  from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
12
12
  from sticker_convert.utils.files.metadata_handler import MetadataHandler
13
13
 
sticker_convert/gui.py CHANGED
@@ -4,19 +4,18 @@ import os
4
4
  import platform
5
5
  import signal
6
6
  import sys
7
- from functools import partial
8
7
  from json.decoder import JSONDecodeError
9
8
  from math import ceil
10
9
  from multiprocessing import Event, cpu_count
11
10
  from pathlib import Path
12
11
  from threading import Thread
13
- from typing import Any, Callable, Dict, Optional, Union, cast
12
+ from typing import Any, Callable, Dict, Optional, cast
14
13
  from urllib.parse import urlparse
15
14
 
16
15
  from mergedeep import merge # type: ignore
17
16
  from PIL import ImageFont
18
- from ttkbootstrap import BooleanVar, DoubleVar, IntVar, StringVar, Toplevel, Window # type: ignore
19
- from ttkbootstrap.dialogs import Messagebox, Querybox # type: ignore
17
+ from ttkbootstrap import BooleanVar, DoubleVar, IntVar, StringVar, Window # type: ignore
18
+ from ttkbootstrap.dialogs import Messagebox # type: ignore
20
19
 
21
20
  from sticker_convert.definitions import CONFIG_DIR, DEFAULT_DIR, ROOT_DIR
22
21
  from sticker_convert.gui_components.frames.comp_frame import CompFrame
@@ -29,6 +28,7 @@ from sticker_convert.gui_components.frames.progress_frame import ProgressFrame
29
28
  from sticker_convert.gui_components.gui_utils import GUIUtils
30
29
  from sticker_convert.job import Job
31
30
  from sticker_convert.job_option import CompOption, CredOption, InputOption, OutputOption
31
+ from sticker_convert.utils.callback import CallbackGui
32
32
  from sticker_convert.utils.files.json_manager import JsonManager
33
33
  from sticker_convert.utils.files.metadata_handler import MetadataHandler
34
34
  from sticker_convert.utils.url_detect import UrlDetect
@@ -38,6 +38,7 @@ from sticker_convert.version import __version__
38
38
  class GUI(Window):
39
39
  def __init__(self) -> None:
40
40
  super().__init__(themename="darkly", alpha=0) # type: ignore
41
+ self.cb = CallbackGui(self)
41
42
  self.init_done = False
42
43
  self.load_jsons()
43
44
 
@@ -79,11 +80,13 @@ class GUI(Window):
79
80
 
80
81
  def quit(self) -> None:
81
82
  if self.job:
82
- response = self.cb_ask_bool("Job is running, really quit?")
83
+ response = self.cb.put(
84
+ ("ask_bool", ("Job is running, really quit?",), None)
85
+ )
83
86
  if response is False:
84
87
  return
85
88
 
86
- self.cb_msg(msg="Quitting, please wait...")
89
+ self.cb.put("Quitting, please wait...")
87
90
 
88
91
  self.save_config()
89
92
  if self.settings_save_cred_var.get() is True:
@@ -163,6 +166,7 @@ class GUI(Window):
163
166
  self.kakao_password_var = StringVar(self)
164
167
  self.kakao_country_code_var = StringVar(self)
165
168
  self.kakao_phone_number_var = StringVar(self)
169
+ self.kakao_device_uuid_var = StringVar(self)
166
170
  self.kakao_bin_path_var = StringVar(self)
167
171
  self.line_cookies_var = StringVar(self)
168
172
  self.viber_auth_var = StringVar(self)
@@ -240,7 +244,7 @@ class GUI(Window):
240
244
  msg += "Please use the stickers with your friends only.\n"
241
245
  msg += "It is illegal and immoral to sell stickers downloaded from this program.\n"
242
246
 
243
- self.cb_msg(msg)
247
+ self.cb.put(msg)
244
248
 
245
249
  def warn_tkinter_bug(self) -> None:
246
250
  if (
@@ -254,13 +258,13 @@ class GUI(Window):
254
258
  msg += "on title bar or move mouse cursor away from window for a while.\n"
255
259
  msg += "(This is a bug in tkinter specific to macOS 14 python <=3.11.6)\n"
256
260
  msg += "(https://github.com/python/cpython/issues/110218)\n"
257
- self.cb_msg(msg)
261
+ self.cb.put(msg)
258
262
 
259
263
  def load_jsons(self) -> None:
260
264
  try:
261
265
  from sticker_convert.utils.files.json_resources_loader import COMPRESSION_JSON, EMOJI_JSON, HELP_JSON, INPUT_JSON, OUTPUT_JSON
262
266
  except RuntimeError as e:
263
- self.cb_msg(str(e))
267
+ self.cb.put(str(e))
264
268
  return
265
269
 
266
270
  self.help = HELP_JSON
@@ -285,7 +289,7 @@ class GUI(Window):
285
289
  self.settings_path
286
290
  )
287
291
  except JSONDecodeError:
288
- self.cb_msg("Warning: config.json content is corrupted")
292
+ self.cb.put("Warning: config.json content is corrupted")
289
293
  self.settings = {}
290
294
  else:
291
295
  self.settings = {}
@@ -295,7 +299,7 @@ class GUI(Window):
295
299
  try:
296
300
  self.creds = JsonManager.load_json(self.creds_path)
297
301
  except JSONDecodeError:
298
- self.cb_msg("Warning: creds.json content is corrupted")
302
+ self.cb.put("Warning: creds.json content is corrupted")
299
303
  self.creds = {}
300
304
  else:
301
305
  self.creds = {}
@@ -427,6 +431,9 @@ class GUI(Window):
427
431
  self.kakao_phone_number_var.set(
428
432
  self.creds.get("kakao", {}).get("phone_number", "")
429
433
  )
434
+ self.kakao_device_uuid_var.set(
435
+ self.creds.get("kakao", {}).get("device_uuid", "")
436
+ )
430
437
  self.line_cookies_var.set(self.creds.get("line", {}).get("cookies", ""))
431
438
  self.viber_auth_var.set(self.creds.get("viber", {}).get("auth", ""))
432
439
  self.discord_token_var.set(self.creds.get("discord", {}).get("token", ""))
@@ -490,17 +497,7 @@ class GUI(Window):
490
497
  opt_comp = self.get_opt_comp()
491
498
  opt_cred = self.get_opt_cred()
492
499
 
493
- self.job = Job(
494
- opt_input,
495
- opt_comp,
496
- opt_output,
497
- opt_cred,
498
- self.cb_msg,
499
- self.cb_msg_block,
500
- self.cb_bar,
501
- self.cb_ask_bool,
502
- self.cb_ask_str,
503
- )
500
+ self.job = Job(opt_input, opt_comp, opt_output, opt_cred, self.cb)
504
501
 
505
502
  signal.signal(signal.SIGINT, self.job.cancel)
506
503
 
@@ -599,6 +596,7 @@ class GUI(Window):
599
596
  kakao_password=self.kakao_password_var.get(),
600
597
  kakao_country_code=self.kakao_country_code_var.get(),
601
598
  kakao_phone_number=self.kakao_phone_number_var.get(),
599
+ kakao_device_uuid=self.kakao_device_uuid_var.get(),
602
600
  line_cookies=self.line_cookies_var.get(),
603
601
  viber_auth=self.viber_auth_var.get(),
604
602
  discord_token=self.discord_token_var.get(),
@@ -638,84 +636,6 @@ class GUI(Window):
638
636
  self.response = self.action()
639
637
  self.response_event.set()
640
638
 
641
- def cb_ask_str(
642
- self,
643
- question: str,
644
- initialvalue: Optional[str] = None,
645
- cli_show_initialvalue: bool = True,
646
- parent: Optional[object] = None,
647
- ) -> str:
648
- self.action = partial(
649
- Querybox.get_string, # type: ignore
650
- question,
651
- title="sticker-convert",
652
- initialvalue=initialvalue,
653
- parent=parent,
654
- )
655
- self.event_generate("<<exec_in_main>>")
656
- self.response_event.wait()
657
- self.response_event.clear()
658
-
659
- if self.response is None:
660
- return ""
661
- elif isinstance(self.response, str):
662
- return self.response
663
- else:
664
- raise RuntimeError(f"Invalid response in cb_ask_str: {self.response}")
665
-
666
- def cb_ask_bool(
667
- self, question: str, parent: Union[Window, Toplevel, None] = None
668
- ) -> bool:
669
- self.action = partial(
670
- Messagebox.yesno, # type: ignore
671
- question,
672
- title="sticker-convert",
673
- parent=parent,
674
- )
675
- self.event_generate("<<exec_in_main>>")
676
- self.response_event.wait()
677
- self.response_event.clear()
678
-
679
- if self.response == "Yes":
680
- return True
681
- return False
682
-
683
- def cb_msg(self, *args: Any, **kwargs: Any) -> None:
684
- self.progress_frame.update_message_box(*args, **kwargs)
685
-
686
- def cb_msg_block(
687
- self,
688
- *args: Any,
689
- message: Optional[str] = None,
690
- parent: Optional[object] = None,
691
- **_kwargs: Any,
692
- ) -> Any:
693
- if message is None and len(args) > 0:
694
- message = " ".join(str(i) for i in args)
695
- self.action = partial(
696
- Messagebox.show_info, # type: ignore
697
- message,
698
- title="sticker-convert",
699
- parent=parent,
700
- )
701
- self.event_generate("<<exec_in_main>>")
702
- self.response_event.wait()
703
- self.response_event.clear()
704
-
705
- return self.response
706
-
707
- def cb_bar(
708
- self,
709
- set_progress_mode: Optional[str] = None,
710
- steps: int = 0,
711
- update_bar: int = 0,
712
- *args: Any,
713
- **kwargs: Any,
714
- ) -> None:
715
- self.progress_frame.update_progress_bar(
716
- set_progress_mode, steps, update_bar, *args, **kwargs
717
- )
718
-
719
639
  def highlight_fields(self) -> bool:
720
640
  if not self.init_done:
721
641
  return True