sticker-convert 2.9.4__py3-none-any.whl → 2.10.1__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 (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 +21 -1
  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 +154 -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.4.dist-info → sticker_convert-2.10.1.dist-info}/METADATA +41 -43
  31. {sticker_convert-2.9.4.dist-info → sticker_convert-2.10.1.dist-info}/RECORD +35 -29
  32. {sticker_convert-2.9.4.dist-info → sticker_convert-2.10.1.dist-info}/LICENSE +0 -0
  33. {sticker_convert-2.9.4.dist-info → sticker_convert-2.10.1.dist-info}/WHEEL +0 -0
  34. {sticker_convert-2.9.4.dist-info → sticker_convert-2.10.1.dist-info}/entry_points.txt +0 -0
  35. {sticker_convert-2.9.4.dist-info → sticker_convert-2.10.1.dist-info}/top_level.txt +0 -0
@@ -1,11 +1,9 @@
1
1
  #!/usr/bin/env python3
2
2
  from functools import partial
3
- from pathlib import Path
4
- from subprocess import Popen
5
- from tkinter import filedialog
3
+ from threading import Thread
6
4
  from typing import Any
7
5
 
8
- from ttkbootstrap import Button, Entry, Frame, Label # type: ignore
6
+ from ttkbootstrap import Button, Frame, Label # type: ignore
9
7
 
10
8
  from sticker_convert.gui_components.gui_utils import GUIUtils
11
9
  from sticker_convert.gui_components.windows.base_window import BaseWindow
@@ -13,8 +11,8 @@ from sticker_convert.utils.auth.get_signal_auth import GetSignalAuth
13
11
 
14
12
 
15
13
  class SignalGetAuthWindow(BaseWindow):
16
- def __init__(self, *args: Any, **kwargs: Any) -> None:
17
- super().__init__(*args, **kwargs)
14
+ def __init__(self, *args: Any, **kwargs: Any):
15
+ super(SignalGetAuthWindow, self).__init__(*args, **kwargs)
18
16
 
19
17
  self.title("Get Signal uuid and password")
20
18
 
@@ -22,79 +20,57 @@ class SignalGetAuthWindow(BaseWindow):
22
20
  self.cb_ask_str_signal = partial(self.gui.cb_ask_str, parent=self)
23
21
 
24
22
  self.frame_info = Frame(self.scrollable_frame)
25
- self.frame_btns = Frame(self.scrollable_frame)
26
- self.frame_config = Frame(self.scrollable_frame)
23
+ self.frame_start_btn = Frame(self.scrollable_frame)
27
24
 
28
25
  self.frame_info.grid(column=0, row=0, sticky="news", padx=3, pady=3)
29
- self.frame_btns.grid(column=0, row=1, sticky="news", padx=3, pady=3)
30
- self.frame_config.grid(column=0, row=2, sticky="news", padx=3, pady=3)
26
+ self.frame_start_btn.grid(column=0, row=1, sticky="news", padx=3, pady=3)
31
27
 
32
28
  # Info frame
33
- self.explanation_lbl = Label(
29
+ self.explanation1_lbl = Label(
34
30
  self.frame_info,
35
- text="Please install Signal Desktop and login first.",
31
+ text="Please install Signal Desktop",
36
32
  justify="left",
37
33
  anchor="w",
38
34
  )
39
-
40
- self.explanation_lbl.grid(column=0, row=0, sticky="w", padx=3, pady=3)
41
-
42
- # Start button frame
43
- self.launch_btn = Button(
44
- self.frame_btns,
45
- text="Launch Signal Desktop",
46
- command=self.cb_launch_signal,
47
- bootstyle="secondary", # type: ignore
48
- )
49
-
50
- self.get_cred_btn = Button(
51
- self.frame_btns,
52
- text="Get uuid and password",
53
- command=self.cb_get_cred,
54
- bootstyle="default", # type: ignore
35
+ self.explanation2_lbl = Label(
36
+ self.frame_info,
37
+ text="After installation, you need to login to Signal Desktop",
38
+ justify="left",
39
+ anchor="w",
55
40
  )
56
-
57
- self.launch_btn.pack()
58
- self.get_cred_btn.pack()
59
-
60
- # Config frame
61
- self.setdir_lbl = Label(
62
- self.frame_config,
63
- text=self.gui.help["cred"]["signal_data_dir"],
41
+ self.explanation3_lbl = Label(
42
+ self.frame_info,
43
+ text="uuid and password will be automatically fetched",
64
44
  justify="left",
65
45
  anchor="w",
66
46
  )
67
47
 
68
- self.setdir_entry = Entry(
69
- self.frame_config,
70
- textvariable=self.gui.signal_data_dir_var,
71
- width=32,
48
+ self.explanation1_lbl.grid(
49
+ column=0, row=0, columnspan=3, sticky="w", padx=3, pady=3
72
50
  )
73
- self.setdir_btn = Button(
74
- self.frame_config,
75
- text="Choose",
76
- command=self.cb_setdir,
77
- width=8,
78
- bootstyle="secondary", # type: ignore
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
79
56
  )
80
57
 
81
- self.setdir_lbl.grid(column=0, row=0, columnspan=2, sticky="w", padx=3, pady=3)
82
- self.setdir_entry.grid(column=0, row=1, sticky="w", padx=3, pady=3)
83
- self.setdir_btn.grid(column=1, row=1, sticky="e", padx=3, pady=3)
58
+ # Start button frame
59
+ self.login_btn = Button(
60
+ self.frame_start_btn, text="Get uuid and password", command=self.cb_login
61
+ )
84
62
 
85
- GUIUtils.finalize_window(self)
63
+ self.login_btn.pack()
86
64
 
87
- def cb_get_cred(self) -> None:
88
- m = GetSignalAuth()
65
+ GUIUtils.finalize_window(self)
89
66
 
90
- signal_bin_path = None
91
- signal_user_data_dir = None
92
- if self.gui.signal_data_dir_var.get():
93
- signal_bin_path = "(User specified)"
94
- signal_user_data_dir = self.gui.signal_data_dir_var.get()
67
+ def cb_login(self):
68
+ Thread(target=self.cb_login_thread, daemon=True).start()
95
69
 
96
- uuid, password, msg = m.get_cred(signal_bin_path, signal_user_data_dir)
70
+ def cb_login_thread(self, *args: Any):
71
+ m = GetSignalAuth(cb_msg=self.gui.cb_msg, cb_ask_str=self.cb_ask_str_signal)
97
72
 
73
+ uuid, password = m.get_cred()
98
74
  if uuid and password:
99
75
  if not self.gui.creds.get("signal"):
100
76
  self.gui.creds["signal"] = {}
@@ -103,33 +79,11 @@ class SignalGetAuthWindow(BaseWindow):
103
79
  self.gui.signal_uuid_var.set(uuid)
104
80
  self.gui.signal_password_var.set(password)
105
81
 
82
+ self.cb_msg_block_signal(
83
+ f"Got uuid and password successfully:\nuuid={uuid}\npassword={password}"
84
+ )
106
85
  self.gui.save_creds()
107
86
  self.gui.highlight_fields()
87
+ return
108
88
 
109
- self.cb_msg_block_signal(msg)
110
-
111
- def cb_launch_signal(self) -> None:
112
- m = GetSignalAuth()
113
- signal_bin_path, signal_user_data_dir = m.get_signal_desktop()
114
-
115
- if self.gui.signal_data_dir_var.get():
116
- signal_user_data_dir = self.gui.signal_data_dir_var.get()
117
-
118
- if signal_bin_path:
119
- Popen(
120
- [
121
- signal_bin_path,
122
- "--no-sandbox",
123
- f"--user-data-dir={signal_user_data_dir}",
124
- ]
125
- )
126
- else:
127
- self.cb_msg_block_signal("Error: Signal Desktop not installed.")
128
-
129
- def cb_setdir(self) -> None:
130
- orig_input_dir = self.gui.signal_data_dir_var.get()
131
- if not Path(orig_input_dir).is_dir():
132
- orig_input_dir = ""
133
- input_dir = filedialog.askdirectory(initialdir=orig_input_dir)
134
- if input_dir:
135
- self.gui.signal_data_dir_var.set(input_dir)
89
+ self.cb_msg_block_signal("Failed to get uuid and password")
sticker_convert/job.py CHANGED
@@ -12,6 +12,7 @@ from typing import Any, Callable, Dict, List, Optional, Tuple
12
12
  from urllib.parse import urlparse
13
13
 
14
14
  from sticker_convert.converter import StickerConvert
15
+ from sticker_convert.downloaders.download_discord import DownloadDiscord
15
16
  from sticker_convert.downloaders.download_kakao import DownloadKakao
16
17
  from sticker_convert.downloaders.download_line import DownloadLine
17
18
  from sticker_convert.downloaders.download_signal import DownloadSignal
@@ -295,6 +296,12 @@ class Job:
295
296
  )
296
297
  error_msg += save_to_local_tip
297
298
 
299
+ if (
300
+ self.opt_input.option.startswith("discord")
301
+ and not self.opt_cred.discord_token
302
+ ):
303
+ error_msg += "[X] Downloading from Discord requires token.\n"
304
+
298
305
  if self.opt_output.option == "telegram" and not self.opt_cred.telegram_userid:
299
306
  error_msg += "[X] Uploading to telegram requires user_id \n"
300
307
  error_msg += " (From real account, not bot account).\n"
@@ -536,6 +543,9 @@ class Job:
536
543
  if self.opt_input.option == "viber":
537
544
  downloaders.append(DownloadViber.start)
538
545
 
546
+ if self.opt_input.option.startswith("discord"):
547
+ downloaders.append(DownloadDiscord.start)
548
+
539
549
  if len(downloaders) > 0:
540
550
  self.executor.cb("Downloading...")
541
551
  else:
@@ -547,7 +557,7 @@ class Job:
547
557
  for downloader in downloaders:
548
558
  self.executor.add_work(
549
559
  work_func=downloader,
550
- work_args=(self.opt_input.url, self.opt_input.dir, self.opt_cred),
560
+ work_args=(self.opt_input, self.opt_cred),
551
561
  )
552
562
 
553
563
  self.executor.join_workers()
@@ -223,6 +223,7 @@ class CredOption(BaseOption):
223
223
  kakao_phone_number: str = ""
224
224
  line_cookies: str = ""
225
225
  viber_auth: str = ""
226
+ discord_token: str = ""
226
227
 
227
228
  def to_dict(self) -> Dict[Any, Any]:
228
229
  return {
@@ -237,4 +238,5 @@ class CredOption(BaseOption):
237
238
  },
238
239
  "line": {"cookies": self.line_cookies},
239
240
  "viber": {"auth": self.viber_auth},
241
+ "discord": {"token": self.discord_token},
240
242
  }
@@ -375,6 +375,100 @@
375
375
  "quantize_method": "imagequant",
376
376
  "default_emoji": "😀"
377
377
  },
378
+ "discord": {
379
+ "size_max": {
380
+ "img": 512000,
381
+ "vid": 512000
382
+ },
383
+ "format": {
384
+ "img": ".png",
385
+ "vid": ".png"
386
+ },
387
+ "fps": {
388
+ "min": 1,
389
+ "max": 60,
390
+ "power": -0.3
391
+ },
392
+ "res": {
393
+ "w": {
394
+ "min": 320,
395
+ "max": 320
396
+ },
397
+ "h": {
398
+ "min": 320,
399
+ "max": 320
400
+ },
401
+ "power": 1
402
+ },
403
+ "quality": {
404
+ "min": 10,
405
+ "max": 95,
406
+ "power": 5
407
+ },
408
+ "color": {
409
+ "min": 32,
410
+ "max": 257,
411
+ "power": 3
412
+ },
413
+ "duration": {
414
+ "min": 0,
415
+ "max": 5000
416
+ },
417
+ "padding_percent": 0,
418
+ "bg_color": "",
419
+ "steps": 16,
420
+ "fake_vid": false,
421
+ "scale_filter": "bicubic",
422
+ "quantize_method": "imagequant",
423
+ "default_emoji": "😀"
424
+ },
425
+ "discord_emoji": {
426
+ "size_max": {
427
+ "img": 256000,
428
+ "vid": 256000
429
+ },
430
+ "format": {
431
+ "img": ".png",
432
+ "vid": ".gif"
433
+ },
434
+ "fps": {
435
+ "min": 1,
436
+ "max": 60,
437
+ "power": -0.3
438
+ },
439
+ "res": {
440
+ "w": {
441
+ "min": 32,
442
+ "max": 128
443
+ },
444
+ "h": {
445
+ "min": 32,
446
+ "max": 128
447
+ },
448
+ "power": 1
449
+ },
450
+ "quality": {
451
+ "min": 10,
452
+ "max": 95,
453
+ "power": 5
454
+ },
455
+ "color": {
456
+ "min": 32,
457
+ "max": 257,
458
+ "power": 3
459
+ },
460
+ "duration": {
461
+ "min": 0,
462
+ "max": 5000
463
+ },
464
+ "padding_percent": 0,
465
+ "bg_color": "",
466
+ "steps": 16,
467
+ "fake_vid": false,
468
+ "scale_filter": "bicubic",
469
+ "quantize_method": "imagequant",
470
+ "default_emoji": "😀"
471
+ },
378
472
  "imessage_small": {
379
473
  "size_max": {
380
474
  "img": 500000,
@@ -58,7 +58,6 @@
58
58
  "signal_uuid": "Set Signal uuid. Required for uploading Signal stickers.",
59
59
  "signal_password": "Set Signal password. Required for uploading Signal stickers.",
60
60
  "signal_get_auth": "Generate Signal uuid and password.",
61
- "signal_data_dir": "Optionally specify Signal data directory\nfor getting uuid and password. Useful for portable Signal.",
62
61
  "telegram_token": "Set Telegram token. Required for uploading and downloading Telegram stickers.",
63
62
  "telegram_userid": "Set telegram user_id (From real account, not bot account). Required for uploading Telegram stickers.",
64
63
  "kakao_auth_token": "Set Kakao auth_token. Required for downloading animated stickers from https://e.kakao.com/t/xxxxx",
@@ -72,6 +71,8 @@
72
71
  "viber_auth": "Set Viber authentication data.\nRequired for uploading Viber stickers.",
73
72
  "viber_get_auth": "Generate Viber authentication data.",
74
73
  "viber_bin_path": "Specify location of Viber Desktop application.\nUseful for portable installation.",
74
+ "discord_get_auth": "Get Discord token.",
75
+ "discord_token": "Set Discord token. Required for downloading Discord stickers and emojis.",
75
76
  "save_cred": "Save Signal and Telegram credentials."
76
77
  }
77
78
  }
@@ -2,7 +2,7 @@
2
2
  "auto": {
3
3
  "full_name": "Download (Auto detect)",
4
4
  "help": "Auto detect URL type and download",
5
- "example": "Supported input sources: Signal, Telegram, Line, Kakao, Viber",
5
+ "example": "Supported input sources: Signal, Telegram, Line, Kakao, Viber, Discord",
6
6
  "address_lbls": "URL address",
7
7
  "metadata_provides": {
8
8
  "title": false,
@@ -59,6 +59,26 @@
59
59
  "author": false
60
60
  }
61
61
  },
62
+ "discord": {
63
+ "full_name": "Download from Discord",
64
+ "help": "Download discord stickers from a channel URL / ID as input",
65
+ "example": "Example: https://discord.com/channels/169256939211980800/@home\nOR 169256939211980800",
66
+ "address_lbls": "URL address / ID",
67
+ "metadata_provides": {
68
+ "title": true,
69
+ "author": true
70
+ }
71
+ },
72
+ "discord_emoji": {
73
+ "full_name": "Download from Discord (emoji)",
74
+ "help": "Download discord emojis from a channel URL / ID as input",
75
+ "example": "Example: https://discord.com/channels/169256939211980800/@home\nOR 169256939211980800",
76
+ "address_lbls": "URL address / ID",
77
+ "metadata_provides": {
78
+ "title": true,
79
+ "author": true
80
+ }
81
+ },
62
82
  "local": {
63
83
  "full_name": "From local directory",
64
84
  "help": "Load files from local directory on computer",
@@ -12,6 +12,7 @@ from sticker_convert.converter import StickerConvert
12
12
  from sticker_convert.job_option import CompOption, CredOption, OutputOption
13
13
  from sticker_convert.uploaders.upload_base import UploadBase
14
14
  from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
15
+ from sticker_convert.utils.emoji import extract_emojis
15
16
  from sticker_convert.utils.files.metadata_handler import MetadataHandler
16
17
  from sticker_convert.utils.media.codec_info import CodecInfo
17
18
  from sticker_convert.utils.media.format_verify import FormatVerify
@@ -55,12 +56,12 @@ class UploadSignal(UploadBase):
55
56
  sticker = Sticker()
56
57
  sticker.id = pack.nb_stickers
57
58
 
58
- emoji = emoji_dict.get(Path(src).stem, None)
59
- if not emoji:
59
+ emoji = extract_emojis(emoji_dict.get(Path(src).stem, ""))
60
+ if emoji == "":
60
61
  self.cb.put(
61
- f"Warning: Cannot find emoji for file {Path(src).name}, skip uploading this file..."
62
+ f"Warning: Cannot find emoji for file {Path(src).name}, using default emoji..."
62
63
  )
63
- continue
64
+ emoji = self.opt_comp.default_emoji
64
65
  sticker.emoji = emoji[:1]
65
66
 
66
67
  if Path(src).suffix == ".webp":
@@ -13,6 +13,7 @@ from sticker_convert.converter import StickerConvert
13
13
  from sticker_convert.job_option import CompOption, CredOption, OutputOption
14
14
  from sticker_convert.uploaders.upload_base import UploadBase
15
15
  from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
16
+ from sticker_convert.utils.emoji import extract_emojis
16
17
  from sticker_convert.utils.files.metadata_handler import MetadataHandler
17
18
  from sticker_convert.utils.media.format_verify import FormatVerify
18
19
 
@@ -158,18 +159,18 @@ class UploadTelegram(UploadBase):
158
159
  for count, src in enumerate(stickers):
159
160
  self.cb.put(f"Verifying {src} for uploading to telegram")
160
161
 
161
- emoji = emoji_dict.get(Path(src).stem, None)
162
- if emoji:
163
- if len(emoji) > 20:
164
- self.cb.put(
165
- f"Warning: {len(emoji)} emoji for file {Path(src).name}, exceeding limit of 20, keep first 20 only..."
166
- )
167
- emoji_list = [*emoji][:20]
168
- else:
162
+ emoji = extract_emojis(emoji_dict.get(Path(src).stem, ""))
163
+ if emoji == "":
164
+ self.cb.put(
165
+ f"Warning: Cannot find emoji for file {Path(src).name}, using default emoji..."
166
+ )
167
+ emoji_list = [self.opt_comp.default_emoji]
168
+
169
+ if len(emoji) > 20:
169
170
  self.cb.put(
170
- f"Warning: Cannot find emoji for file {Path(src).name}, skip uploading this file..."
171
+ f"Warning: {len(emoji)} emoji for file {Path(src).name}, exceeding limit of 20, keep first 20 only..."
171
172
  )
172
- continue
173
+ emoji_list = [*emoji][:20]
173
174
 
174
175
  ext = Path(src).suffix
175
176
  if ext == ".tgs":
@@ -0,0 +1,115 @@
1
+ #!/usr/bin/env python3
2
+ import json
3
+ import os
4
+ import platform
5
+ import shutil
6
+ import time
7
+ from typing import Callable, Optional, Tuple
8
+ from urllib.parse import urlparse
9
+
10
+ from sticker_convert.definitions import CONFIG_DIR
11
+ from sticker_convert.utils.chrome_remotedebug import CRD
12
+ from sticker_convert.utils.process import killall
13
+
14
+
15
+ class GetDiscordAuth:
16
+ def __init__(self, cb_msg: Callable[..., None] = print):
17
+ chromedriver_download_dir = CONFIG_DIR / "bin"
18
+ os.makedirs(chromedriver_download_dir, exist_ok=True)
19
+
20
+ self.chromedriver_download_dir = chromedriver_download_dir
21
+
22
+ self.cb_msg = cb_msg
23
+
24
+ def get_discord_bin_path(self) -> Optional[str]:
25
+ discord_bin: Optional[str]
26
+ if platform.system() == "Windows":
27
+ discord_win_dirs: Tuple[Tuple[str, str], ...]
28
+ discord_win_dirs = (
29
+ (
30
+ os.path.expandvars("%localappdata%/Discord"),
31
+ "Discord.exe",
32
+ ),
33
+ (
34
+ os.path.expandvars("%localappdata%/DiscordCanary"),
35
+ "DiscordCanary.exe",
36
+ ),
37
+ (
38
+ os.path.expandvars("%localappdata%/DiscordPTB"),
39
+ "DiscordPTB.exe",
40
+ ),
41
+ )
42
+ for discord_dir, discord_bin in discord_win_dirs:
43
+ app_dir: Optional[str] = None
44
+ chrome_path: Optional[str] = None
45
+ for i in [j for j in os.listdir(discord_dir) if j.startswith("app-")]:
46
+ app_dir = os.path.join(discord_dir, i)
47
+ chrome_path = os.path.join(app_dir, discord_bin)
48
+ if os.path.isfile(chrome_path):
49
+ return chrome_path
50
+ else:
51
+ discord_dirs: Tuple[Optional[str], ...]
52
+ if platform.system() == "Darwin":
53
+ discord_dirs = (
54
+ "/Applications/Discord.app/Contents/MacOS/Discord",
55
+ "/Applications/Discord Canary.app/Contents/MacOS/Discord Canary",
56
+ "/Applications/Discord PTB.app/Contents/MacOS/Discord PTB",
57
+ )
58
+ else:
59
+ discord_dirs = (
60
+ shutil.which("discord"),
61
+ shutil.which("discord-canary"),
62
+ shutil.which("discord-ptb"),
63
+ )
64
+ for discord_bin in discord_dirs:
65
+ if discord_bin is not None and os.path.isfile(discord_bin):
66
+ return discord_bin
67
+ return None
68
+
69
+ def get_cred(self) -> Tuple[Optional[str], str]:
70
+ using_discord_app = False
71
+ chrome_path = self.get_discord_bin_path()
72
+ if chrome_path is not None:
73
+ using_discord_app = True
74
+ else:
75
+ chrome_path = CRD.get_chrome_path()
76
+ if chrome_path is None:
77
+ return None, "Please install Discord Desktop or Chrome and try again"
78
+
79
+ token = None
80
+ if using_discord_app:
81
+ killall("discord")
82
+
83
+ crd = CRD(chrome_path)
84
+ while True:
85
+ crd.connect()
86
+ if using_discord_app is False:
87
+ crd.navigate("https://discord.com/channels/@me")
88
+ break
89
+ else:
90
+ curr_url = crd.get_curr_url()
91
+ netloc = urlparse(curr_url).netloc
92
+ if netloc in ("discordapp.com", "discord.com"):
93
+ break
94
+ time.sleep(1)
95
+
96
+ while True:
97
+ try:
98
+ r = crd.exec_js(
99
+ "(webpackChunkdiscord_app.push([[''],{},e=>{m=[];for(let c in e.c)m.push(e.c[c])}]),m).find(m=>m?.exports?.default?.getToken!==void 0).exports.default.getToken();"
100
+ )
101
+ except RuntimeError:
102
+ break
103
+ if (
104
+ json.loads(r).get("result", {}).get("result", {}).get("type", "")
105
+ == "string"
106
+ ):
107
+ token = json.loads(r)["result"]["result"]["value"]
108
+ break
109
+ time.sleep(1)
110
+ crd.close()
111
+
112
+ if token is None:
113
+ return None, "Failed to get token"
114
+
115
+ return token, f"Got token successfully:\ntoken={token}"