sticker-convert 2.9.3__py3-none-any.whl → 2.10.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. sticker_convert/cli.py +26 -13
  2. sticker_convert/downloaders/download_base.py +20 -23
  3. sticker_convert/downloaders/download_discord.py +91 -0
  4. sticker_convert/downloaders/download_kakao.py +3 -4
  5. sticker_convert/downloaders/download_line.py +3 -4
  6. sticker_convert/downloaders/download_signal.py +3 -4
  7. sticker_convert/downloaders/download_telegram.py +3 -4
  8. sticker_convert/downloaders/download_viber.py +3 -4
  9. sticker_convert/gui.py +15 -3
  10. sticker_convert/gui_components/frames/cred_frame.py +22 -1
  11. sticker_convert/gui_components/windows/discord_get_auth_window.py +82 -0
  12. sticker_convert/gui_components/windows/signal_get_auth_window.py +39 -85
  13. sticker_convert/job.py +11 -1
  14. sticker_convert/job_option.py +2 -0
  15. sticker_convert/resources/compression.json +94 -0
  16. sticker_convert/resources/help.json +2 -1
  17. sticker_convert/resources/input.json +20 -0
  18. sticker_convert/uploaders/upload_signal.py +5 -4
  19. sticker_convert/uploaders/upload_telegram.py +11 -10
  20. sticker_convert/utils/auth/get_discord_auth.py +115 -0
  21. sticker_convert/utils/auth/get_signal_auth.py +115 -114
  22. sticker_convert/utils/auth/get_viber_auth.py +10 -214
  23. sticker_convert/utils/chrome_remotedebug.py +152 -0
  24. sticker_convert/utils/emoji.py +16 -0
  25. sticker_convert/utils/files/run_bin.py +1 -1
  26. sticker_convert/utils/media/codec_info.py +45 -60
  27. sticker_convert/utils/process.py +187 -0
  28. sticker_convert/utils/url_detect.py +3 -0
  29. sticker_convert/version.py +1 -1
  30. {sticker_convert-2.9.3.dist-info → sticker_convert-2.10.0.dist-info}/METADATA +42 -44
  31. {sticker_convert-2.9.3.dist-info → sticker_convert-2.10.0.dist-info}/RECORD +35 -29
  32. {sticker_convert-2.9.3.dist-info → sticker_convert-2.10.0.dist-info}/WHEEL +1 -1
  33. {sticker_convert-2.9.3.dist-info → sticker_convert-2.10.0.dist-info}/LICENSE +0 -0
  34. {sticker_convert-2.9.3.dist-info → sticker_convert-2.10.0.dist-info}/entry_points.txt +0 -0
  35. {sticker_convert-2.9.3.dist-info → sticker_convert-2.10.0.dist-info}/top_level.txt +0 -0
sticker_convert/cli.py CHANGED
@@ -14,6 +14,7 @@ from mergedeep import merge # type: ignore
14
14
  from sticker_convert.definitions import CONFIG_DIR, DEFAULT_DIR
15
15
  from sticker_convert.job import Job
16
16
  from sticker_convert.job_option import CompOption, CredOption, InputOption, OutputOption
17
+ from sticker_convert.utils.auth.get_discord_auth import GetDiscordAuth
17
18
  from sticker_convert.utils.auth.get_kakao_auth import GetKakaoAuth
18
19
  from sticker_convert.utils.auth.get_line_auth import GetLineAuth
19
20
  from sticker_convert.utils.auth.get_signal_auth import GetSignalAuth
@@ -164,7 +165,12 @@ class CLI:
164
165
  )
165
166
 
166
167
  parser_cred = parser.add_argument_group("Credentials options")
167
- flags_cred_bool = ("signal_get_auth", "kakao_get_auth", "line_get_auth")
168
+ flags_cred_bool = (
169
+ "signal_get_auth",
170
+ "kakao_get_auth",
171
+ "line_get_auth",
172
+ "discord_get_auth",
173
+ )
168
174
  for k, v in self.help["cred"].items():
169
175
  keyword_args = {}
170
176
  if k in flags_cred_bool:
@@ -220,6 +226,8 @@ class CLI:
220
226
  "telegram": args.download_telegram,
221
227
  "kakao": args.download_kakao,
222
228
  "viber": args.download_viber,
229
+ "discord": args.download_discord,
230
+ "discord_emoji": args.download_discord_emoji,
223
231
  }
224
232
 
225
233
  download_option = "local"
@@ -456,6 +464,9 @@ class CLI:
456
464
  viber_auth=args.viber_auth
457
465
  if args.viber_auth
458
466
  else creds.get("viber", {}).get("auth"),
467
+ discord_token=args.discord_token
468
+ if args.discord_token
469
+ else creds.get("discord", {}).get("token"),
459
470
  )
460
471
 
461
472
  if args.kakao_get_auth:
@@ -473,23 +484,16 @@ class CLI:
473
484
  self.cb.msg(f"Got auth_token successfully: {auth_token}")
474
485
 
475
486
  if args.signal_get_auth:
476
- get_signal_auth = GetSignalAuth()
477
-
478
- signal_bin_path = None
479
- signal_user_data_dir = None
480
- if args.signal_data_dir:
481
- signal_bin_path = "(User specified)"
482
- signal_user_data_dir = args.signal_data_dir
483
-
484
- uuid, password, msg = get_signal_auth.get_cred(
485
- signal_bin_path, signal_user_data_dir
486
- )
487
+ m = GetSignalAuth(cb_msg=self.cb.msg, cb_ask_str=self.cb.ask_str)
487
488
 
489
+ uuid, password = m.get_cred()
488
490
  if uuid and password:
489
491
  opt_cred.signal_uuid = uuid
490
492
  opt_cred.signal_password = password
491
493
 
492
- self.cb.msg(msg)
494
+ self.cb.msg(f"Got uuid and password successfully: {uuid}, {password}")
495
+
496
+ self.cb.msg("Failed to get uuid and password")
493
497
 
494
498
  if args.line_get_auth:
495
499
  get_line_auth = GetLineAuth()
@@ -519,6 +523,15 @@ class CLI:
519
523
 
520
524
  self.cb.msg(msg)
521
525
 
526
+ if args.discord_get_auth:
527
+ get_discord_auth = GetDiscordAuth(self.cb.msg)
528
+ discord_token, msg = get_discord_auth.get_cred()
529
+
530
+ if discord_token:
531
+ opt_cred.discord_token = discord_token
532
+
533
+ self.cb.msg(msg)
534
+
522
535
  if args.save_cred:
523
536
  creds_path = CONFIG_DIR / "creds.json"
524
537
  JsonManager.save_json(creds_path, opt_cred.to_dict())
@@ -6,23 +6,24 @@ from pathlib import Path
6
6
  from typing import Any, List, Optional, Tuple
7
7
 
8
8
  import anyio
9
+ import httpx
9
10
  import requests
10
11
 
11
- from sticker_convert.job_option import CredOption
12
+ from sticker_convert.job_option import CredOption, InputOption
12
13
  from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
13
14
 
14
15
 
15
16
  class DownloadBase:
16
17
  def __init__(
17
18
  self,
18
- url: str,
19
- out_dir: Path,
19
+ opt_input: InputOption,
20
20
  opt_cred: Optional[CredOption],
21
21
  cb: CallbackProtocol,
22
22
  cb_return: CallbackReturn,
23
23
  ) -> None:
24
- self.url = url
25
- self.out_dir = out_dir
24
+ self.url = opt_input.url
25
+ self.out_dir = opt_input.dir
26
+ self.input_option = opt_input.option
26
27
  self.opt_cred = opt_cred
27
28
  self.cb = cb
28
29
  self.cb_return = cb_return
@@ -42,36 +43,32 @@ class DownloadBase:
42
43
  ("bar", None, {"set_progress_mode": "determinate", "steps": len(targets)})
43
44
  )
44
45
 
45
- async with anyio.create_task_group() as tg:
46
- for url, dest in targets:
47
- tg.start_soon(self.download_file_async, url, dest, retries, **kwargs)
46
+ async with httpx.AsyncClient() as client:
47
+ async with anyio.create_task_group() as tg:
48
+ for url, dest in targets:
49
+ tg.start_soon(
50
+ self.download_file_async, client, url, dest, retries, **kwargs
51
+ )
48
52
 
49
53
  async def download_file_async(
50
54
  self,
55
+ client: httpx.AsyncClient,
51
56
  url: str,
52
57
  dest: Path,
53
58
  retries: int = 3,
54
59
  **kwargs: Any,
55
60
  ) -> None:
61
+ self.cb.put(f"Downloading {url}")
56
62
  for retry in range(retries):
57
- try:
58
- response = requests.get(url, allow_redirects=True, **kwargs)
59
-
60
- if not response.ok:
61
- self.cb.put("update_bar")
62
- raise requests.exceptions.RequestException(
63
- f"Error {response.status_code}"
64
- )
63
+ response = await client.get(url, follow_redirects=True, **kwargs)
65
64
 
66
- self.cb.put(f"Downloading {url}")
67
- with open(dest, "wb+") as f:
68
- f.write(response.content)
65
+ if response.is_success:
66
+ async with await anyio.open_file(dest, "wb+") as f:
67
+ await f.write(response.content)
69
68
  self.cb.put(f"Downloaded {url}")
70
- break
71
-
72
- except requests.exceptions.RequestException as e:
69
+ else:
73
70
  self.cb.put(
74
- f"Cannot download {url} (tried {retry+1}/{retries} times): {e}"
71
+ f"Error {response.status_code}: {url} (tried {retry+1}/{retries} times)"
75
72
  )
76
73
 
77
74
  self.cb.put("update_bar")
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env python3
2
+ import json
3
+ from pathlib import Path
4
+ from typing import Dict, List, Optional, Tuple, cast
5
+ from urllib.parse import urlparse
6
+
7
+ import requests
8
+
9
+ from sticker_convert.downloaders.download_base import DownloadBase
10
+ from sticker_convert.job_option import CredOption, InputOption
11
+ from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
12
+ from sticker_convert.utils.emoji import extract_emojis
13
+ from sticker_convert.utils.files.metadata_handler import MetadataHandler
14
+
15
+ # References:
16
+ # https://github.com/ThaTiemsz/Discord-Emoji-Downloader/blob/master/assets/app.js
17
+ # https://github.com/zgibberish/discord-emoji-scraper/blob/main/emoji_scraper.py
18
+
19
+
20
+ class DownloadDiscord(DownloadBase):
21
+ # def __init__(self, *args: Any, **kwargs: Any) -> None:
22
+ # super().__init__(*args, **kwargs)
23
+
24
+ def download_stickers_discord(self) -> bool:
25
+ if self.opt_cred is None or self.opt_cred.discord_token == "":
26
+ self.cb.put("Error: Downloading from Discord requires token")
27
+ return False
28
+
29
+ gid: Optional[str] = None
30
+ if self.url.isnumeric():
31
+ gid = self.url
32
+ else:
33
+ url_parsed = urlparse(self.url)
34
+ if url_parsed.netloc == "discord.com":
35
+ gid = url_parsed.path.split("/")[2]
36
+
37
+ if gid is None or gid.isnumeric() is False:
38
+ self.cb.put("Error: Invalid url")
39
+ return False
40
+
41
+ headers = {
42
+ "Authorization": self.opt_cred.discord_token,
43
+ }
44
+
45
+ r = requests.get(f"https://discord.com/api/v10/guilds/{gid}", headers=headers)
46
+ r_json = json.loads(r.text)
47
+
48
+ if self.input_option == "discord_emoji":
49
+ stickers = r_json["emojis"]
50
+ else:
51
+ stickers = r_json["stickers"]
52
+
53
+ targets: List[Tuple[str, Path]] = []
54
+ emoji_dict: Dict[str, str] = {}
55
+ for i, sticker in enumerate(stickers):
56
+ f_id = str(i).zfill(3)
57
+ sticker_id = sticker["id"]
58
+ if self.input_option == "discord_emoji":
59
+ f_ext = ".gif" if sticker["animated"] else ".png"
60
+ sticker_url = f"https://cdn.discordapp.com/emojis/{sticker_id}{f_ext}?size=4096&quality=lossless"
61
+ else:
62
+ # https://discord.com/developers/docs/resources/sticker#sticker-object-sticker-format-types
63
+ format_type = cast(int, sticker["format_type"])
64
+ f_ext = [".png", ".png", ".json", ".gif"][format_type - 1]
65
+ sticker_url = f"https://cdn.discordapp.com/stickers/{sticker_id}{f_ext}?size=4096&quality=lossless"
66
+ emoji_dict[f_id] = extract_emojis(sticker["tags"])
67
+ f_name = f_id + f_ext
68
+ f_path = Path(self.out_dir, f_name)
69
+ targets.append((sticker_url, f_path))
70
+
71
+ self.download_multiple_files(targets)
72
+
73
+ server_name = r_json["name"]
74
+ MetadataHandler.set_metadata(
75
+ self.out_dir,
76
+ title=server_name,
77
+ author=server_name,
78
+ emoji_dict=emoji_dict if self.input_option == "discord" else None,
79
+ )
80
+
81
+ return True
82
+
83
+ @staticmethod
84
+ def start(
85
+ opt_input: InputOption,
86
+ opt_cred: Optional[CredOption],
87
+ cb: CallbackProtocol,
88
+ cb_return: CallbackReturn,
89
+ ) -> bool:
90
+ downloader = DownloadDiscord(opt_input, opt_cred, cb, cb_return)
91
+ return downloader.download_stickers_discord()
@@ -12,7 +12,7 @@ from bs4 import BeautifulSoup
12
12
  from py_mini_racer import MiniRacer
13
13
 
14
14
  from sticker_convert.downloaders.download_base import DownloadBase
15
- from sticker_convert.job_option import CredOption
15
+ from sticker_convert.job_option import CredOption, InputOption
16
16
  from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
17
17
  from sticker_convert.utils.files.metadata_handler import MetadataHandler
18
18
  from sticker_convert.utils.media.decrypt_kakao import DecryptKakao
@@ -326,11 +326,10 @@ class DownloadKakao(DownloadBase):
326
326
 
327
327
  @staticmethod
328
328
  def start(
329
- url: str,
330
- out_dir: Path,
329
+ opt_input: InputOption,
331
330
  opt_cred: Optional[CredOption],
332
331
  cb: CallbackProtocol,
333
332
  cb_return: CallbackReturn,
334
333
  ) -> bool:
335
- downloader = DownloadKakao(url, out_dir, opt_cred, cb, cb_return)
334
+ downloader = DownloadKakao(opt_input, opt_cred, cb, cb_return)
336
335
  return downloader.download_stickers_kakao()
@@ -15,7 +15,7 @@ from bs4 import BeautifulSoup
15
15
  from PIL import Image
16
16
 
17
17
  from sticker_convert.downloaders.download_base import DownloadBase
18
- from sticker_convert.job_option import CredOption
18
+ from sticker_convert.job_option import CredOption, InputOption
19
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
@@ -462,11 +462,10 @@ class DownloadLine(DownloadBase):
462
462
 
463
463
  @staticmethod
464
464
  def start(
465
- url: str,
466
- out_dir: Path,
465
+ opt_input: InputOption,
467
466
  opt_cred: Optional[CredOption],
468
467
  cb: CallbackProtocol,
469
468
  cb_return: CallbackReturn,
470
469
  ) -> bool:
471
- downloader = DownloadLine(url, out_dir, opt_cred, cb, cb_return)
470
+ downloader = DownloadLine(opt_input, opt_cred, cb, cb_return)
472
471
  return downloader.download_stickers_line()
@@ -8,7 +8,7 @@ from signalstickers_client.models import StickerPack
8
8
  from signalstickers_client.stickersclient import StickersClient
9
9
 
10
10
  from sticker_convert.downloaders.download_base import DownloadBase
11
- from sticker_convert.job_option import CredOption
11
+ from sticker_convert.job_option import CredOption, InputOption
12
12
  from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
13
13
  from sticker_convert.utils.files.metadata_handler import MetadataHandler
14
14
  from sticker_convert.utils.media.codec_info import CodecInfo
@@ -82,11 +82,10 @@ class DownloadSignal(DownloadBase):
82
82
 
83
83
  @staticmethod
84
84
  def start(
85
- url: str,
86
- out_dir: Path,
85
+ opt_input: InputOption,
87
86
  opt_cred: Optional[CredOption],
88
87
  cb: CallbackProtocol,
89
88
  cb_return: CallbackReturn,
90
89
  ) -> bool:
91
- downloader = DownloadSignal(url, out_dir, opt_cred, cb, cb_return)
90
+ downloader = DownloadSignal(opt_input, opt_cred, cb, cb_return)
92
91
  return downloader.download_stickers_signal()
@@ -9,7 +9,7 @@ from telegram.error import TelegramError
9
9
  from telegram.ext import AIORateLimiter, ApplicationBuilder
10
10
 
11
11
  from sticker_convert.downloaders.download_base import DownloadBase
12
- from sticker_convert.job_option import CredOption
12
+ from sticker_convert.job_option import CredOption, InputOption
13
13
  from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
14
14
  from sticker_convert.utils.files.metadata_handler import MetadataHandler
15
15
 
@@ -120,11 +120,10 @@ class DownloadTelegram(DownloadBase):
120
120
 
121
121
  @staticmethod
122
122
  def start(
123
- url: str,
124
- out_dir: Path,
123
+ opt_input: InputOption,
125
124
  opt_cred: Optional[CredOption],
126
125
  cb: CallbackProtocol,
127
126
  cb_return: CallbackReturn,
128
127
  ) -> bool:
129
- downloader = DownloadTelegram(url, out_dir, opt_cred, cb, cb_return)
128
+ downloader = DownloadTelegram(opt_input, opt_cred, cb, cb_return)
130
129
  return downloader.download_stickers_telegram()
@@ -10,7 +10,7 @@ import requests
10
10
  from bs4 import BeautifulSoup
11
11
 
12
12
  from sticker_convert.downloaders.download_base import DownloadBase
13
- from sticker_convert.job_option import CredOption
13
+ from sticker_convert.job_option import CredOption, InputOption
14
14
  from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
15
15
  from sticker_convert.utils.files.metadata_handler import MetadataHandler
16
16
 
@@ -85,11 +85,10 @@ class DownloadViber(DownloadBase):
85
85
 
86
86
  @staticmethod
87
87
  def start(
88
- url: str,
89
- out_dir: Path,
88
+ opt_input: InputOption,
90
89
  opt_cred: Optional[CredOption],
91
90
  cb: CallbackProtocol,
92
91
  cb_return: CallbackReturn,
93
92
  ) -> bool:
94
- downloader = DownloadViber(url, out_dir, opt_cred, cb, cb_return)
93
+ downloader = DownloadViber(opt_input, opt_cred, cb, cb_return)
95
94
  return downloader.download_stickers_viber()
sticker_convert/gui.py CHANGED
@@ -150,7 +150,6 @@ class GUI(Window):
150
150
  # Credentials
151
151
  self.signal_uuid_var = StringVar(self)
152
152
  self.signal_password_var = StringVar(self)
153
- self.signal_data_dir_var = StringVar(self)
154
153
  self.telegram_token_var = StringVar(self)
155
154
  self.telegram_userid_var = StringVar(self)
156
155
  self.kakao_auth_token_var = StringVar(self)
@@ -161,6 +160,7 @@ class GUI(Window):
161
160
  self.line_cookies_var = StringVar(self)
162
161
  self.viber_auth_var = StringVar(self)
163
162
  self.viber_bin_path_var = StringVar(self)
163
+ self.discord_token_var = StringVar(self)
164
164
 
165
165
  # Config
166
166
  self.settings_save_cred_var = BooleanVar()
@@ -388,6 +388,7 @@ class GUI(Window):
388
388
  )
389
389
  self.line_cookies_var.set(self.creds.get("line", {}).get("cookies", ""))
390
390
  self.viber_auth_var.set(self.creds.get("viber", {}).get("auth", ""))
391
+ self.discord_token_var.set(self.creds.get("discord", {}).get("token", ""))
391
392
 
392
393
  def get_input_name(self) -> str:
393
394
  return [
@@ -549,6 +550,7 @@ class GUI(Window):
549
550
  kakao_phone_number=self.kakao_phone_number_var.get(),
550
551
  line_cookies=self.line_cookies_var.get(),
551
552
  viber_auth=self.viber_auth_var.get(),
553
+ discord_token=self.discord_token_var.get(),
552
554
  )
553
555
 
554
556
  def start_process(self) -> None:
@@ -702,8 +704,13 @@ class GUI(Window):
702
704
  if not url:
703
705
  self.input_frame.address_entry.config(bootstyle="warning") # type: ignore
704
706
 
705
- elif download_option != input_option and not (
706
- input_option in ("kakao", "line") and url.isnumeric()
707
+ elif (
708
+ download_option is None
709
+ or input_option.startswith(download_option) is False
710
+ and not (
711
+ input_option in ("kakao", "line", "discord", "discord_emoji")
712
+ and url.isnumeric()
713
+ )
707
714
  ):
708
715
  self.input_frame.address_entry.config(bootstyle="danger") # type: ignore
709
716
  self.input_frame.address_tip.config(
@@ -788,6 +795,11 @@ class GUI(Window):
788
795
  else:
789
796
  self.cred_frame.kakao_auth_token_entry.config(bootstyle="default") # type: ignore
790
797
 
798
+ if input_option.startswith("discord") and not self.discord_token_var.get():
799
+ self.cred_frame.discord_token_entry.config(bootstyle="warning") # type: ignore
800
+ else:
801
+ self.cred_frame.discord_token_entry.config(bootstyle="default") # type: ignore
802
+
791
803
  # Check for Input and Compression mismatch
792
804
  if (
793
805
  not self.no_compress_var.get()
@@ -5,6 +5,7 @@ from typing import TYPE_CHECKING, Any
5
5
  from ttkbootstrap import Button, Entry, Label, LabelFrame # type: ignore
6
6
 
7
7
  from sticker_convert.gui_components.frames.right_clicker import RightClicker
8
+ from sticker_convert.gui_components.windows.discord_get_auth_window import DiscordGetAuthWindow
8
9
  from sticker_convert.gui_components.windows.kakao_get_auth_window import KakaoGetAuthWindow
9
10
  from sticker_convert.gui_components.windows.line_get_auth_window import LineGetAuthWindow
10
11
  from sticker_convert.gui_components.windows.signal_get_auth_window import SignalGetAuthWindow
@@ -118,6 +119,20 @@ class CredFrame(LabelFrame):
118
119
  bootstyle="secondary", # type: ignore
119
120
  )
120
121
 
122
+ self.discord_token_lbl = Label(
123
+ self, text="Discord token", width=18, justify="left", anchor="w"
124
+ )
125
+ self.discord_token_entry = Entry(
126
+ self, textvariable=self.gui.discord_token_var, width=35
127
+ )
128
+ self.discord_token_entry.bind("<Button-3><ButtonRelease-3>", RightClicker)
129
+ self.discord_get_auth_btn = Button(
130
+ self,
131
+ text="Generate",
132
+ command=self.cb_discord_get_auth,
133
+ bootstyle="secondary", # type: ignore
134
+ )
135
+
121
136
  self.help_btn = Button(
122
137
  self,
123
138
  text="Get help",
@@ -151,7 +166,10 @@ class CredFrame(LabelFrame):
151
166
  self.viber_auth_lbl.grid(column=0, row=7, sticky="w", padx=3, pady=3)
152
167
  self.viber_auth_entry.grid(column=1, row=7, sticky="w", padx=3, pady=3)
153
168
  self.viber_get_auth_btn.grid(column=2, row=7, sticky="e", padx=3, pady=3)
154
- self.help_btn.grid(column=2, row=8, sticky="e", padx=3, pady=3)
169
+ self.discord_token_lbl.grid(column=0, row=8, sticky="w", padx=3, pady=3)
170
+ self.discord_token_entry.grid(column=1, row=8, sticky="w", padx=3, pady=3)
171
+ self.discord_get_auth_btn.grid(column=2, row=8, sticky="e", padx=3, pady=3)
172
+ self.help_btn.grid(column=2, row=9, sticky="e", padx=3, pady=3)
155
173
 
156
174
  def cb_cred_help(self, *_: Any) -> None:
157
175
  faq_site = "https://github.com/laggykiller/sticker-convert#faq"
@@ -171,6 +189,9 @@ class CredFrame(LabelFrame):
171
189
  def cb_viber_get_auth(self, *_: Any) -> None:
172
190
  ViberGetAuthWindow(self.gui)
173
191
 
192
+ def cb_discord_get_auth(self, *_: Any) -> None:
193
+ DiscordGetAuthWindow(self.gui)
194
+
174
195
  def set_states(self, state: str) -> None:
175
196
  self.signal_uuid_entry.config(state=state)
176
197
  self.signal_password_entry.config(state=state)
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env python3
2
+ from functools import partial
3
+ from threading import Thread
4
+ from typing import Any
5
+
6
+ from ttkbootstrap import Button, Frame, Label # type: ignore
7
+
8
+ from sticker_convert.gui_components.gui_utils import GUIUtils
9
+ from sticker_convert.gui_components.windows.base_window import BaseWindow
10
+ from sticker_convert.utils.auth.get_discord_auth import GetDiscordAuth
11
+
12
+
13
+ class DiscordGetAuthWindow(BaseWindow):
14
+ def __init__(self, *args: Any, **kwargs: Any):
15
+ super(DiscordGetAuthWindow, self).__init__(*args, **kwargs)
16
+
17
+ self.title("Get Discord token")
18
+
19
+ self.cb_msg_block_discord = partial(self.gui.cb_msg_block, parent=self)
20
+ self.cb_ask_str_discord = partial(self.gui.cb_ask_str, parent=self)
21
+
22
+ self.frame_info = Frame(self.scrollable_frame)
23
+ self.frame_start_btn = Frame(self.scrollable_frame)
24
+
25
+ self.frame_info.grid(column=0, row=0, sticky="news", padx=3, pady=3)
26
+ self.frame_start_btn.grid(column=0, row=1, sticky="news", padx=3, pady=3)
27
+
28
+ # Info frame
29
+ self.explanation1_lbl = Label(
30
+ self.frame_info,
31
+ text="Please install Discord Desktop or Chrome",
32
+ justify="left",
33
+ anchor="w",
34
+ )
35
+ self.explanation2_lbl = Label(
36
+ self.frame_info,
37
+ text="After installation, you need to login to Discord",
38
+ justify="left",
39
+ anchor="w",
40
+ )
41
+ self.explanation3_lbl = Label(
42
+ self.frame_info,
43
+ text="Token will be automatically fetched",
44
+ justify="left",
45
+ anchor="w",
46
+ )
47
+
48
+ self.explanation1_lbl.grid(
49
+ column=0, row=0, columnspan=3, sticky="w", padx=3, pady=3
50
+ )
51
+ self.explanation2_lbl.grid(
52
+ column=0, row=1, columnspan=3, sticky="w", padx=3, pady=3
53
+ )
54
+ self.explanation3_lbl.grid(
55
+ column=0, row=2, columnspan=3, sticky="w", padx=3, pady=3
56
+ )
57
+
58
+ # Start button frame
59
+ self.login_btn = Button(
60
+ self.frame_start_btn, text="Get token", command=self.cb_login
61
+ )
62
+
63
+ self.login_btn.pack()
64
+
65
+ GUIUtils.finalize_window(self)
66
+
67
+ def cb_login(self):
68
+ Thread(target=self.cb_login_thread, daemon=True).start()
69
+
70
+ def cb_login_thread(self, *args: Any):
71
+ m = GetDiscordAuth(cb_msg=self.gui.cb_msg)
72
+ discord_token, msg = m.get_cred()
73
+ if discord_token:
74
+ if not self.gui.creds.get("discord"):
75
+ self.gui.creds["discord"] = {}
76
+ self.gui.creds["discord"]["token"] = discord_token
77
+ self.gui.discord_token_var.set(discord_token)
78
+
79
+ self.gui.save_creds()
80
+ self.gui.highlight_fields()
81
+
82
+ self.cb_msg_block_discord(msg)