sticker-convert 2.10.1__py3-none-any.whl → 2.10.2__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
sticker_convert/cli.py CHANGED
@@ -16,6 +16,7 @@ from sticker_convert.job import Job
16
16
  from sticker_convert.job_option import CompOption, CredOption, InputOption, OutputOption
17
17
  from sticker_convert.utils.auth.get_discord_auth import GetDiscordAuth
18
18
  from sticker_convert.utils.auth.get_kakao_auth import GetKakaoAuth
19
+ from sticker_convert.utils.auth.get_kakao_desktop_auth import GetKakaoDesktopAuth
19
20
  from sticker_convert.utils.auth.get_line_auth import GetLineAuth
20
21
  from sticker_convert.utils.auth.get_signal_auth import GetSignalAuth
21
22
  from sticker_convert.utils.auth.get_viber_auth import GetViberAuth
@@ -168,6 +169,7 @@ class CLI:
168
169
  flags_cred_bool = (
169
170
  "signal_get_auth",
170
171
  "kakao_get_auth",
172
+ "kakao_get_auth_desktop",
171
173
  "line_get_auth",
172
174
  "discord_get_auth",
173
175
  )
@@ -483,6 +485,20 @@ class CLI:
483
485
 
484
486
  self.cb.msg(f"Got auth_token successfully: {auth_token}")
485
487
 
488
+ if args.kakao_get_auth_desktop:
489
+ get_kakao_desktop_auth = GetKakaoDesktopAuth(
490
+ cb_ask_str=self.cb.ask_str,
491
+ )
492
+ kakao_bin_path = None
493
+ if args.kakao_bin_path:
494
+ kakao_bin_path = args.kakao_bin_path
495
+ auth_token, msg = get_kakao_desktop_auth.get_cred(kakao_bin_path)
496
+
497
+ if auth_token:
498
+ opt_cred.kakao_auth_token = auth_token
499
+
500
+ self.cb.msg(msg)
501
+
486
502
  if args.signal_get_auth:
487
503
  m = GetSignalAuth(cb_msg=self.cb.msg, cb_ask_str=self.cb.ask_str)
488
504
 
@@ -29,14 +29,24 @@ class DownloadBase:
29
29
  self.cb_return = cb_return
30
30
 
31
31
  def download_multiple_files(
32
- self, targets: List[Tuple[str, Path]], retries: int = 3, **kwargs: Any
32
+ self,
33
+ targets: List[Tuple[str, Path]],
34
+ retries: int = 3,
35
+ headers: Optional[dict[Any, Any]] = None,
36
+ **kwargs: Any,
33
37
  ) -> None:
34
38
  anyio.run(
35
- partial(self.download_multiple_files_async, targets, retries, **kwargs)
39
+ partial(
40
+ self.download_multiple_files_async, targets, retries, headers, **kwargs
41
+ )
36
42
  )
37
43
 
38
44
  async def download_multiple_files_async(
39
- self, targets: List[Tuple[str, Path]], retries: int = 3, **kwargs: Any
45
+ self,
46
+ targets: List[Tuple[str, Path]],
47
+ retries: int = 3,
48
+ headers: Optional[dict[Any, Any]] = None,
49
+ **kwargs: Any,
40
50
  ) -> None:
41
51
  # targets format: [(url1, dest2), (url2, dest2), ...]
42
52
  self.cb.put(
@@ -47,7 +57,13 @@ class DownloadBase:
47
57
  async with anyio.create_task_group() as tg:
48
58
  for url, dest in targets:
49
59
  tg.start_soon(
50
- self.download_file_async, client, url, dest, retries, **kwargs
60
+ self.download_file_async,
61
+ client,
62
+ url,
63
+ dest,
64
+ retries,
65
+ headers,
66
+ **kwargs,
51
67
  )
52
68
 
53
69
  async def download_file_async(
@@ -56,11 +72,14 @@ class DownloadBase:
56
72
  url: str,
57
73
  dest: Path,
58
74
  retries: int = 3,
75
+ headers: Optional[dict[Any, Any]] = None,
59
76
  **kwargs: Any,
60
77
  ) -> None:
61
78
  self.cb.put(f"Downloading {url}")
62
79
  for retry in range(retries):
63
- response = await client.get(url, follow_redirects=True, **kwargs)
80
+ response = await client.get(
81
+ url, follow_redirects=True, headers=headers, **kwargs
82
+ )
64
83
 
65
84
  if response.is_success:
66
85
  async with await anyio.open_file(dest, "wb+") as f:
@@ -231,6 +231,8 @@ class DownloadKakao(DownloadBase):
231
231
  sound_path_format = None
232
232
  stickers_count = 32 # https://emoticonstudio.kakao.com/pages/start
233
233
 
234
+ headers = {"User-Agent": "Android"}
235
+
234
236
  if not self.pack_info_authed and self.auth_token:
235
237
  self.pack_info_authed = MetadataKakao.get_pack_info_authed(
236
238
  item_code, self.auth_token
@@ -263,7 +265,8 @@ class DownloadKakao(DownloadBase):
263
265
  if play_path_format is None:
264
266
  for play_type, play_ext in itertools.product(play_types, play_exts):
265
267
  r = requests.get(
266
- f"https://item.kakaocdn.net/dw/{item_code}.{play_type}_001{play_ext}"
268
+ f"https://item.kakaocdn.net/dw/{item_code}.{play_type}_001{play_ext}",
269
+ headers=headers,
267
270
  )
268
271
  if r.ok:
269
272
  break
@@ -279,7 +282,8 @@ class DownloadKakao(DownloadBase):
279
282
  if sound_path_format is None:
280
283
  for sound_ext in sound_exts:
281
284
  r = requests.get(
282
- f"https://item.kakaocdn.net/dw/{item_code}.sound_001{sound_ext}"
285
+ f"https://item.kakaocdn.net/dw/{item_code}.sound_001{sound_ext}",
286
+ headers=headers,
283
287
  )
284
288
  if r.ok:
285
289
  break
@@ -304,7 +308,7 @@ class DownloadKakao(DownloadBase):
304
308
  sound_dl_path = Path(self.out_dir, str(num).zfill(3) + sound_ext)
305
309
  targets.append((sound_url, sound_dl_path))
306
310
 
307
- self.download_multiple_files(targets)
311
+ self.download_multiple_files(targets, headers=headers)
308
312
 
309
313
  for target in targets:
310
314
  f_path = target[1]
sticker_convert/gui.py CHANGED
@@ -157,6 +157,7 @@ class GUI(Window):
157
157
  self.kakao_password_var = StringVar(self)
158
158
  self.kakao_country_code_var = StringVar(self)
159
159
  self.kakao_phone_number_var = StringVar(self)
160
+ self.kakao_bin_path_var = StringVar(self)
160
161
  self.line_cookies_var = StringVar(self)
161
162
  self.viber_auth_var = StringVar(self)
162
163
  self.viber_bin_path_var = StringVar(self)
@@ -1,7 +1,9 @@
1
1
  #!/usr/bin/env python3
2
+ import platform
3
+ import subprocess
2
4
  from functools import partial
3
5
  from threading import Thread
4
- from typing import Any
6
+ from typing import Any, Optional
5
7
 
6
8
  from ttkbootstrap import Button, Entry, Frame, Label, LabelFrame # type: ignore
7
9
 
@@ -9,6 +11,7 @@ from sticker_convert.gui_components.frames.right_clicker import RightClicker
9
11
  from sticker_convert.gui_components.gui_utils import GUIUtils
10
12
  from sticker_convert.gui_components.windows.base_window import BaseWindow
11
13
  from sticker_convert.utils.auth.get_kakao_auth import GetKakaoAuth
14
+ from sticker_convert.utils.auth.get_kakao_desktop_auth import GetKakaoDesktopAuth
12
15
 
13
16
 
14
17
  class KakaoGetAuthWindow(BaseWindow):
@@ -20,36 +23,99 @@ class KakaoGetAuthWindow(BaseWindow):
20
23
  self.cb_msg_block_kakao = partial(self.gui.cb_msg_block, parent=self)
21
24
  self.cb_ask_str_kakao = partial(self.gui.cb_ask_str, parent=self)
22
25
 
23
- self.frame_login_info = LabelFrame(
24
- self.scrollable_frame, text="Kakao login info"
26
+ self.frame_from_desktop = LabelFrame(
27
+ self.scrollable_frame, text="Method 1: From KakaoTalk Desktop"
28
+ )
29
+ self.frame_simulate_login = LabelFrame(
30
+ self.scrollable_frame, text="Method 2: Simulate login"
25
31
  )
26
32
  self.frame_login_btn = Frame(self.scrollable_frame)
27
33
 
28
- self.frame_login_info.grid(column=0, row=0, sticky="news", padx=3, pady=3)
29
- self.frame_login_btn.grid(column=0, row=1, sticky="news", padx=3, pady=3)
34
+ self.frame_from_desktop.grid(column=0, row=0, sticky="news", padx=3, pady=3)
35
+ self.frame_simulate_login.grid(column=0, row=1, sticky="news", padx=3, pady=3)
30
36
 
31
- # Login info frame
32
- self.explanation1_lbl = Label(
33
- self.frame_login_info,
37
+ # Method 1 frame
38
+ self.explanation1_1_lbl = Label(
39
+ self.frame_from_desktop,
40
+ text="This will get Kakao auth_token from Kakao Desktop (Windows only)",
41
+ justify="left",
42
+ anchor="w",
43
+ )
44
+ self.explanation1_2_lbl = Label(
45
+ self.frame_from_desktop,
46
+ text="Download Kakao Desktop, login and press 'Get auth_token'",
47
+ justify="left",
48
+ anchor="w",
49
+ )
50
+ self.explanation1_3_lbl = Label(
51
+ self.frame_from_desktop,
52
+ text="This can take about a minute.",
53
+ justify="left",
54
+ anchor="w",
55
+ )
56
+ self.kakao_bin_path_lbl = Label(
57
+ self.frame_from_desktop,
58
+ text="Kakao app path (Optional):",
59
+ justify="left",
60
+ anchor="w",
61
+ )
62
+ self.kakao_bin_path_entry = Entry(
63
+ self.frame_from_desktop,
64
+ textvariable=self.gui.kakao_bin_path_var,
65
+ width=30,
66
+ )
67
+ self.launch_desktop_btn = Button(
68
+ self.frame_from_desktop,
69
+ text="Launch Desktop app",
70
+ command=self.cb_launch_desktop,
71
+ width=24,
72
+ bootstyle="secondary", # type: ignore
73
+ state="normal" if platform.system() == "Windows" else "disabled",
74
+ )
75
+ self.get_auth_desktop_btn = Button(
76
+ self.frame_from_desktop,
77
+ text="Get auth_token",
78
+ command=self.cb_from_desktop,
79
+ width=24,
80
+ state="normal" if platform.system() == "Windows" else "disabled",
81
+ )
82
+
83
+ self.explanation1_1_lbl.grid(
84
+ column=0, row=0, columnspan=2, sticky="w", padx=3, pady=3
85
+ )
86
+ self.explanation1_2_lbl.grid(
87
+ column=0, row=1, columnspan=2, sticky="w", padx=3, pady=3
88
+ )
89
+ self.explanation1_3_lbl.grid(
90
+ column=0, row=2, columnspan=2, sticky="w", padx=3, pady=3
91
+ )
92
+ self.kakao_bin_path_lbl.grid(column=0, row=3, sticky="w", padx=3, pady=3)
93
+ self.kakao_bin_path_entry.grid(column=1, row=3, sticky="w", padx=3, pady=3)
94
+ self.launch_desktop_btn.grid(column=0, row=4, columnspan=2, padx=3, pady=3)
95
+ self.get_auth_desktop_btn.grid(column=0, row=5, columnspan=2, padx=3, pady=3)
96
+
97
+ # Method 2 frame
98
+ self.explanation2_1_lbl = Label(
99
+ self.frame_simulate_login,
34
100
  text="This will simulate login to Android Kakao app",
35
101
  justify="left",
36
102
  anchor="w",
37
103
  )
38
- self.explanation2_lbl = Label(
39
- self.frame_login_info,
104
+ self.explanation2_2_lbl = Label(
105
+ self.frame_simulate_login,
40
106
  text="You will send / receive verification code via SMS",
41
107
  justify="left",
42
108
  anchor="w",
43
109
  )
44
- self.explanation3_lbl = Label(
45
- self.frame_login_info,
46
- text="You maybe logged out of existing device",
110
+ self.explanation2_3_lbl = Label(
111
+ self.frame_simulate_login,
112
+ text="You will be logged out of existing device",
47
113
  justify="left",
48
114
  anchor="w",
49
115
  )
50
116
 
51
117
  self.kakao_username_help_btn = Button(
52
- self.frame_login_info,
118
+ self.frame_simulate_login,
53
119
  text="?",
54
120
  width=1,
55
121
  command=lambda: self.cb_msg_block_kakao(
@@ -58,15 +124,21 @@ class KakaoGetAuthWindow(BaseWindow):
58
124
  bootstyle="secondary", # type: ignore
59
125
  )
60
126
  self.kakao_username_lbl = Label(
61
- self.frame_login_info, text="Username", width=18, justify="left", anchor="w"
127
+ self.frame_simulate_login,
128
+ text="Username",
129
+ width=18,
130
+ justify="left",
131
+ anchor="w",
62
132
  )
63
133
  self.kakao_username_entry = Entry(
64
- self.frame_login_info, textvariable=self.gui.kakao_username_var, width=30
134
+ self.frame_simulate_login,
135
+ textvariable=self.gui.kakao_username_var,
136
+ width=30,
65
137
  )
66
138
  self.kakao_username_entry.bind("<Button-3><ButtonRelease-3>", RightClicker)
67
139
 
68
140
  self.kakao_password_help_btn = Button(
69
- self.frame_login_info,
141
+ self.frame_simulate_login,
70
142
  text="?",
71
143
  width=1,
72
144
  command=lambda: self.cb_msg_block_kakao(
@@ -75,15 +147,17 @@ class KakaoGetAuthWindow(BaseWindow):
75
147
  bootstyle="secondary", # type: ignore
76
148
  )
77
149
  self.kakao_password_lbl = Label(
78
- self.frame_login_info, text="Password", justify="left", anchor="w"
150
+ self.frame_simulate_login, text="Password", justify="left", anchor="w"
79
151
  )
80
152
  self.kakao_password_entry = Entry(
81
- self.frame_login_info, textvariable=self.gui.kakao_password_var, width=30
153
+ self.frame_simulate_login,
154
+ textvariable=self.gui.kakao_password_var,
155
+ width=30,
82
156
  )
83
157
  self.kakao_password_entry.bind("<Button-3><ButtonRelease-3>", RightClicker)
84
158
 
85
159
  self.kakao_country_code_help_btn = Button(
86
- self.frame_login_info,
160
+ self.frame_simulate_login,
87
161
  text="?",
88
162
  width=1,
89
163
  command=lambda: self.cb_msg_block_kakao(
@@ -92,17 +166,17 @@ class KakaoGetAuthWindow(BaseWindow):
92
166
  bootstyle="secondary", # type: ignore
93
167
  )
94
168
  self.kakao_country_code_lbl = Label(
95
- self.frame_login_info, text="Country code", justify="left", anchor="w"
169
+ self.frame_simulate_login, text="Country code", justify="left", anchor="w"
96
170
  )
97
171
  self.kakao_country_code_entry = Entry(
98
- self.frame_login_info,
172
+ self.frame_simulate_login,
99
173
  textvariable=self.gui.kakao_country_code_var,
100
174
  width=30,
101
175
  )
102
176
  self.kakao_country_code_entry.bind("<Button-3><ButtonRelease-3>", RightClicker)
103
177
 
104
178
  self.kakao_phone_number_help_btn = Button(
105
- self.frame_login_info,
179
+ self.frame_simulate_login,
106
180
  text="?",
107
181
  width=1,
108
182
  command=lambda: self.cb_msg_block_kakao(
@@ -111,22 +185,29 @@ class KakaoGetAuthWindow(BaseWindow):
111
185
  bootstyle="secondary", # type: ignore
112
186
  )
113
187
  self.kakao_phone_number_lbl = Label(
114
- self.frame_login_info, text="Phone number", justify="left", anchor="w"
188
+ self.frame_simulate_login, text="Phone number", justify="left", anchor="w"
115
189
  )
116
190
  self.kakao_phone_number_entry = Entry(
117
- self.frame_login_info,
191
+ self.frame_simulate_login,
118
192
  textvariable=self.gui.kakao_phone_number_var,
119
193
  width=30,
120
194
  )
121
195
  self.kakao_phone_number_entry.bind("<Button-3><ButtonRelease-3>", RightClicker)
122
196
 
123
- self.explanation1_lbl.grid(
197
+ self.login_btn = Button(
198
+ self.frame_simulate_login,
199
+ text="Login and get auth_token",
200
+ command=self.cb_simulate_login,
201
+ width=24,
202
+ )
203
+
204
+ self.explanation2_1_lbl.grid(
124
205
  column=0, row=0, columnspan=3, sticky="w", padx=3, pady=3
125
206
  )
126
- self.explanation2_lbl.grid(
207
+ self.explanation2_2_lbl.grid(
127
208
  column=0, row=1, columnspan=3, sticky="w", padx=3, pady=3
128
209
  )
129
- self.explanation3_lbl.grid(
210
+ self.explanation2_3_lbl.grid(
130
211
  column=0, row=2, columnspan=3, sticky="w", padx=3, pady=3
131
212
  )
132
213
 
@@ -149,20 +230,14 @@ class KakaoGetAuthWindow(BaseWindow):
149
230
  )
150
231
  self.kakao_phone_number_lbl.grid(column=1, row=6, sticky="w", padx=3, pady=3)
151
232
  self.kakao_phone_number_entry.grid(column=2, row=6, sticky="w", padx=3, pady=3)
152
-
153
- # Login button frame
154
- self.login_btn = Button(
155
- self.frame_login_btn, text="Login and get auth_token", command=self.cb_login
156
- )
157
-
158
- self.login_btn.pack()
233
+ self.login_btn.grid(column=0, row=7, columnspan=3, padx=3, pady=3)
159
234
 
160
235
  GUIUtils.finalize_window(self)
161
236
 
162
- def cb_login(self) -> None:
163
- Thread(target=self.cb_login_thread, daemon=True).start()
237
+ def cb_simulate_login(self) -> None:
238
+ Thread(target=self.cb_simulate_login_thread, daemon=True).start()
164
239
 
165
- def cb_login_thread(self, *_: Any) -> None:
240
+ def cb_simulate_login_thread(self, *_: Any) -> None:
166
241
  self.gui.save_creds()
167
242
  m = GetKakaoAuth(
168
243
  opt_cred=self.gui.get_opt_cred(),
@@ -184,3 +259,46 @@ class KakaoGetAuthWindow(BaseWindow):
184
259
  self.gui.highlight_fields()
185
260
  else:
186
261
  self.cb_msg_block_kakao("Failed to get auth_token")
262
+
263
+ def cb_launch_desktop(self) -> None:
264
+ m = GetKakaoDesktopAuth(
265
+ cb_ask_str=self.cb_ask_str_kakao,
266
+ )
267
+ if self.gui.kakao_bin_path_var.get() != "":
268
+ bin_path = self.gui.kakao_bin_path_var.get()
269
+ else:
270
+ bin_path = m.get_kakao_desktop()
271
+
272
+ if bin_path is not None:
273
+ subprocess.Popen([bin_path])
274
+ else:
275
+ self.cb_msg_block_kakao(
276
+ "Error: Cannot launch Kakao Desktop. Is it installed?"
277
+ )
278
+
279
+ def cb_from_desktop(self) -> None:
280
+ Thread(target=self.cb_from_desktop_thread, daemon=True).start()
281
+
282
+ def cb_from_desktop_thread(self, *_: Any) -> None:
283
+ self.gui.save_creds()
284
+ m = GetKakaoDesktopAuth(
285
+ cb_ask_str=self.cb_ask_str_kakao,
286
+ )
287
+
288
+ bin_path: Optional[str]
289
+ if self.gui.kakao_bin_path_var.get() != "":
290
+ bin_path = self.gui.kakao_bin_path_var.get()
291
+ else:
292
+ bin_path = None
293
+ auth_token, msg = m.get_cred(bin_path)
294
+
295
+ if auth_token:
296
+ if not self.gui.creds.get("kakao"):
297
+ self.gui.creds["kakao"] = {}
298
+ self.gui.creds["kakao"]["auth_token"] = auth_token
299
+ self.gui.kakao_auth_token_var.set(auth_token)
300
+
301
+ self.gui.save_creds()
302
+ self.gui.highlight_fields()
303
+
304
+ self.cb_msg_block_kakao(msg)
@@ -3,6 +3,7 @@ import platform
3
3
  from functools import partial
4
4
  from pathlib import Path
5
5
  from subprocess import Popen
6
+ from threading import Thread
6
7
  from tkinter import filedialog
7
8
  from typing import Any
8
9
 
@@ -108,7 +109,10 @@ class ViberGetAuthWindow(BaseWindow):
108
109
 
109
110
  GUIUtils.finalize_window(self)
110
111
 
111
- def cb_get_cred(self) -> None:
112
+ def cb_get_cred(self):
113
+ Thread(target=self.cb_get_cred_thread, daemon=True).start()
114
+
115
+ def cb_get_cred_thread(self) -> None:
112
116
  m = GetViberAuth(self.cb_ask_str_viber)
113
117
 
114
118
  viber_bin_path = None
@@ -61,7 +61,9 @@
61
61
  "telegram_token": "Set Telegram token. Required for uploading and downloading Telegram stickers.",
62
62
  "telegram_userid": "Set telegram user_id (From real account, not bot account). Required for uploading Telegram stickers.",
63
63
  "kakao_auth_token": "Set Kakao auth_token. Required for downloading animated stickers from https://e.kakao.com/t/xxxxx",
64
- "kakao_get_auth": "Generate Kakao auth_token. Kakao username, password, country code and phone number are also required.",
64
+ "kakao_get_auth": "Generate Kakao auth_token by simulating login. Kakao username, password, country code and phone number are also required.",
65
+ "kakao_get_auth_desktop": "Get Kakao auth_token from Kakao Desktop application.\n(Only working on Windows.)",
66
+ "kakao_bin_path": "Set Kakao Desktop application path for launching and getting auth_token.\nUseful for portable installation.",
65
67
  "kakao_username": "Set Kakao username, which is email or phone number used for signing up Kakao account\nExample: +447700900142\nRequired for generating Kakao auth_token.",
66
68
  "kakao_password": "Set Kakao password (Password of Kakao account).\nRequired for generating Kakao auth_token.",
67
69
  "kakao_country_code": "Set Kakao country code of phone.\nExample: 82 (For korea), 44 (For UK), 1 (For USA).\nRequired for generating Kakao auth_token.",
@@ -0,0 +1,180 @@
1
+ #!/usr/bin/env python3
2
+ import importlib.util
3
+ import os
4
+ import platform
5
+ import re
6
+ import subprocess
7
+ import time
8
+ from functools import partial
9
+ from getpass import getpass
10
+ from pathlib import Path
11
+ from typing import Callable, List, Optional, Tuple, cast
12
+
13
+ from sticker_convert.utils.process import check_admin, find_pid_by_name, get_mem, killall
14
+
15
+ MSG_NO_BIN = """Kakao Desktop not detected.
16
+ Download and install Kakao Desktop,
17
+ then login to Kakao Desktop and try again."""
18
+ MSG_NO_AUTH = """Kakao Desktop installed,
19
+ but kakao_auth not found.
20
+ Please login to Kakao Desktop and try again."""
21
+ MSG_LAUNCH_FAIL = "Failed to launch Kakao"
22
+ MSG_PERMISSION_ERROR = "Failed to read Kakao process memory"
23
+ MSG_UNSUPPORTED = "Only Windows is supported for this method"
24
+
25
+
26
+ class GetKakaoDesktopAuth:
27
+ def __init__(self, cb_ask_str: Callable[..., str] = input):
28
+ self.cb_ask_str = cb_ask_str
29
+
30
+ def relaunch_kakao(self, kakao_bin_path: str) -> Optional[int]:
31
+ killed = killall("kakaotalk")
32
+ if killed:
33
+ time.sleep(5)
34
+
35
+ subprocess.Popen([kakao_bin_path])
36
+ time.sleep(20)
37
+
38
+ return find_pid_by_name("kakaotalk")
39
+
40
+ def get_auth_by_pme(
41
+ self, kakao_bin_path: str, relaunch: bool = True
42
+ ) -> Tuple[Optional[str], str]:
43
+ from PyMemoryEditor import OpenProcess # type: ignore
44
+
45
+ auth_token = None
46
+
47
+ if relaunch:
48
+ kakao_pid = self.relaunch_kakao(kakao_bin_path)
49
+ else:
50
+ kakao_pid = find_pid_by_name("kakaotalk")
51
+ if kakao_pid is None:
52
+ return None, MSG_LAUNCH_FAIL
53
+
54
+ try:
55
+ with OpenProcess(pid=int(kakao_pid)) as process:
56
+ for address in process.search_by_value( # type: ignore
57
+ str, 15, "\x00authorization\x00"
58
+ ):
59
+ auth_token_addr = cast(int, address) + 15
60
+ auth_token_bytes = process.read_process_memory(
61
+ auth_token_addr, bytes, 200
62
+ )
63
+ auth_token_term = auth_token_bytes.find(b"\x00")
64
+ if auth_token_term == -1:
65
+ continue
66
+ auth_token_candidate = auth_token_bytes[:auth_token_term].decode(
67
+ encoding="ascii"
68
+ )
69
+ if len(auth_token_candidate) > 150:
70
+ auth_token = auth_token_candidate
71
+ break
72
+ except PermissionError:
73
+ return None, MSG_PERMISSION_ERROR
74
+
75
+ if auth_token is None:
76
+ return None, MSG_NO_AUTH
77
+ else:
78
+ msg = "(Note: auth_token will be invalid if you quit Kakao Desktop)"
79
+ msg += "Got auth_token successfully:\n"
80
+ msg += f"{auth_token=}\n"
81
+
82
+ return auth_token, msg
83
+
84
+ def get_auth_by_dump(
85
+ self, kakao_bin_path: str, relaunch: bool = True
86
+ ) -> Tuple[Optional[str], str]:
87
+ auth_token = None
88
+
89
+ if relaunch:
90
+ kakao_pid = self.relaunch_kakao(kakao_bin_path)
91
+ else:
92
+ kakao_pid = find_pid_by_name("kakaotalk")
93
+ if kakao_pid is None:
94
+ return None, MSG_LAUNCH_FAIL
95
+
96
+ if self.cb_ask_str == input:
97
+ pw_func = getpass
98
+ else:
99
+ pw_func = partial(
100
+ self.cb_ask_str, initialvalue="", cli_show_initialvalue=False
101
+ )
102
+ s, msg = get_mem(kakao_pid, pw_func)
103
+
104
+ if s is None:
105
+ return None, msg
106
+
107
+ auth_token = None
108
+ for i in re.finditer(b"\x00authorization\x00", s):
109
+ auth_token_addr = i.start() + 15
110
+
111
+ auth_token_bytes = s[auth_token_addr : auth_token_addr + 200]
112
+ auth_token_term = auth_token_bytes.find(b"\x00")
113
+ if auth_token_term == -1:
114
+ return None, MSG_NO_AUTH
115
+ auth_token_candidate = auth_token_bytes[:auth_token_term].decode(
116
+ encoding="ascii"
117
+ )
118
+ if len(auth_token_candidate) > 150:
119
+ auth_token = auth_token_candidate
120
+ break
121
+
122
+ if auth_token is None:
123
+ return None, MSG_NO_AUTH
124
+ else:
125
+ msg = "Got auth_token successfully:\n"
126
+ msg += f"{auth_token=}\n"
127
+
128
+ return auth_token, msg
129
+
130
+ def get_kakao_desktop(self) -> Optional[str]:
131
+ kakao_bin_path = os.path.expandvars(
132
+ "%programfiles(x86)%\\Kakao\\KakaoTalk\\KakaoTalk.exe"
133
+ )
134
+ if Path(kakao_bin_path).is_file():
135
+ return kakao_bin_path
136
+
137
+ return None
138
+
139
+ def get_cred(
140
+ self,
141
+ kakao_bin_path: Optional[str] = None,
142
+ ) -> Tuple[Optional[str], str]:
143
+ if platform.system() != "Windows":
144
+ return None, MSG_UNSUPPORTED
145
+
146
+ if not kakao_bin_path:
147
+ kakao_bin_path = self.get_kakao_desktop()
148
+
149
+ if not kakao_bin_path:
150
+ return None, MSG_NO_BIN
151
+
152
+ # get_auth_by_dump()
153
+ # + Fast
154
+ # - Requires admin
155
+
156
+ # get_auth_by_pme()
157
+ # + No admin (If have permission to read process)
158
+ # - Slow
159
+ # - Cannot run on macOS
160
+
161
+ # If admin, prefer get_auth_by_dump() over get_auth_by_pme(), vice versa
162
+ methods: List[Callable[[str, bool], Tuple[Optional[str], str]]] = []
163
+ relaunch = True
164
+ kakao_auth = None
165
+ msg = ""
166
+
167
+ pme_present = importlib.util.find_spec("PyMemoryEditor") is not None
168
+ methods.append(self.get_auth_by_dump)
169
+ if pme_present:
170
+ methods.append(self.get_auth_by_pme)
171
+ if check_admin() is False:
172
+ methods.reverse()
173
+
174
+ for method in methods:
175
+ kakao_auth, msg = method(kakao_bin_path, relaunch)
176
+ relaunch = False
177
+ if kakao_auth is not None:
178
+ break
179
+
180
+ return kakao_auth, msg
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env python3
2
2
 
3
- __version__ = "2.10.1"
3
+ __version__ = "2.10.2"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sticker-convert
3
- Version: 2.10.1
3
+ Version: 2.10.2
4
4
  Summary: Convert (animated) stickers to/from WhatsApp, Telegram, Signal, Line, Kakao, Viber, Discord, iMessage. Written in Python.
5
5
  Author-email: laggykiller <chaudominic2@gmail.com>
6
6
  Maintainer-email: laggykiller <chaudominic2@gmail.com>
@@ -488,13 +488,20 @@ To run in CLI mode, pass on any arguments
488
488
  ```
489
489
  usage: sticker-convert.py [-h] [--version] [--no-confirm] [--no-progress] [--custom-presets CUSTOM_PRESETS] [--input-dir INPUT_DIR]
490
490
  [--download-auto DOWNLOAD_AUTO | --download-signal DOWNLOAD_SIGNAL | --download-telegram DOWNLOAD_TELEGRAM | --download-line DOWNLOAD_LINE | --download-kakao DOWNLOAD_KAKAO | --download-viber DOWNLOAD_VIBER | --download-discord DOWNLOAD_DISCORD | --download-discord-emoji DOWNLOAD_DISCORD_EMOJI]
491
- [--output-dir OUTPUT_DIR] [--author AUTHOR] [--title TITLE] [--export-signal | --export-telegram | --export-telegram-emoji | --export-viber | --export-whatsapp | --export-imessage] [--no-compress]
492
- [--preset {auto,signal,telegram,telegram_emoji,whatsapp,line,kakao,viber,discord,discord_emoji,imessage_small,imessage_medium,imessage_large,custom}] [--steps STEPS] [--processes PROCESSES] [--fps-min FPS_MIN] [--fps-max FPS_MAX] [--fps-power FPS_POWER]
493
- [--res-min RES_MIN] [--res-max RES_MAX] [--res-w-min RES_W_MIN] [--res-w-max RES_W_MAX] [--res-h-min RES_H_MIN] [--res-h-max RES_H_MAX] [--res-power RES_POWER] [--quality-min QUALITY_MIN] [--quality-max QUALITY_MAX] [--quality-power QUALITY_POWER]
494
- [--color-min COLOR_MIN] [--color-max COLOR_MAX] [--color-power COLOR_POWER] [--duration-min DURATION_MIN] [--duration-max DURATION_MAX] [--padding-percent PADDING_PERCENT] [--bg-color BG_COLOR] [--vid-size-max VID_SIZE_MAX] [--img-size-max IMG_SIZE_MAX]
495
- [--vid-format VID_FORMAT] [--img-format IMG_FORMAT] [--fake-vid] [--scale-filter SCALE_FILTER] [--quantize-method QUANTIZE_METHOD] [--cache-dir CACHE_DIR] [--default-emoji DEFAULT_EMOJI] [--signal-uuid SIGNAL_UUID] [--signal-password SIGNAL_PASSWORD] [--signal-get-auth]
496
- [--telegram-token TELEGRAM_TOKEN] [--telegram-userid TELEGRAM_USERID] [--kakao-auth-token KAKAO_AUTH_TOKEN] [--kakao-get-auth] [--kakao-username KAKAO_USERNAME] [--kakao-password KAKAO_PASSWORD] [--kakao-country-code KAKAO_COUNTRY_CODE]
497
- [--kakao-phone-number KAKAO_PHONE_NUMBER] [--line-get-auth] [--line-cookies LINE_COOKIES] [--viber-auth VIBER_AUTH] [--viber-get-auth VIBER_GET_AUTH] [--viber-bin-path VIBER_BIN_PATH] [--discord-get-auth] [--discord-token DISCORD_TOKEN] [--save-cred SAVE_CRED]
491
+ [--output-dir OUTPUT_DIR] [--author AUTHOR] [--title TITLE]
492
+ [--export-signal | --export-telegram | --export-telegram-emoji | --export-viber | --export-whatsapp | --export-imessage] [--no-compress]
493
+ [--preset {auto,signal,telegram,telegram_emoji,whatsapp,line,kakao,viber,discord,discord_emoji,imessage_small,imessage_medium,imessage_large,custom}]
494
+ [--steps STEPS] [--processes PROCESSES] [--fps-min FPS_MIN] [--fps-max FPS_MAX] [--fps-power FPS_POWER] [--res-min RES_MIN] [--res-max RES_MAX]
495
+ [--res-w-min RES_W_MIN] [--res-w-max RES_W_MAX] [--res-h-min RES_H_MIN] [--res-h-max RES_H_MAX] [--res-power RES_POWER]
496
+ [--quality-min QUALITY_MIN] [--quality-max QUALITY_MAX] [--quality-power QUALITY_POWER] [--color-min COLOR_MIN] [--color-max COLOR_MAX]
497
+ [--color-power COLOR_POWER] [--duration-min DURATION_MIN] [--duration-max DURATION_MAX] [--padding-percent PADDING_PERCENT]
498
+ [--bg-color BG_COLOR] [--vid-size-max VID_SIZE_MAX] [--img-size-max IMG_SIZE_MAX] [--vid-format VID_FORMAT] [--img-format IMG_FORMAT]
499
+ [--fake-vid] [--scale-filter SCALE_FILTER] [--quantize-method QUANTIZE_METHOD] [--cache-dir CACHE_DIR] [--default-emoji DEFAULT_EMOJI]
500
+ [--signal-uuid SIGNAL_UUID] [--signal-password SIGNAL_PASSWORD] [--signal-get-auth] [--telegram-token TELEGRAM_TOKEN]
501
+ [--telegram-userid TELEGRAM_USERID] [--kakao-auth-token KAKAO_AUTH_TOKEN] [--kakao-get-auth] [--kakao-get-auth-desktop]
502
+ [--kakao-bin-path KAKAO_BIN_PATH] [--kakao-username KAKAO_USERNAME] [--kakao-password KAKAO_PASSWORD] [--kakao-country-code KAKAO_COUNTRY_CODE]
503
+ [--kakao-phone-number KAKAO_PHONE_NUMBER] [--line-get-auth] [--line-cookies LINE_COOKIES] [--viber-auth VIBER_AUTH]
504
+ [--viber-get-auth VIBER_GET_AUTH] [--viber-bin-path VIBER_BIN_PATH] [--discord-get-auth] [--discord-token DISCORD_TOKEN] [--save-cred SAVE_CRED]
498
505
 
499
506
  CLI for stickers-convert
500
507
 
@@ -647,7 +654,13 @@ Credentials options:
647
654
  Set telegram user_id (From real account, not bot account). Required for uploading Telegram stickers.
648
655
  --kakao-auth-token KAKAO_AUTH_TOKEN
649
656
  Set Kakao auth_token. Required for downloading animated stickers from https://e.kakao.com/t/xxxxx
650
- --kakao-get-auth Generate Kakao auth_token. Kakao username, password, country code and phone number are also required.
657
+ --kakao-get-auth Generate Kakao auth_token by simulating login. Kakao username, password, country code and phone number are also required.
658
+ --kakao-get-auth-desktop
659
+ Get Kakao auth_token from Kakao Desktop application.
660
+ (Only working on Windows.)
661
+ --kakao-bin-path KAKAO_BIN_PATH
662
+ Set Kakao Desktop application path for launching and getting auth_token.
663
+ Useful for portable installation.
651
664
  --kakao-username KAKAO_USERNAME
652
665
  Set Kakao username, which is email or phone number used for signing up Kakao account
653
666
  Example: +447700900142
@@ -1,16 +1,16 @@
1
1
  sticker_convert/__init__.py,sha256=iQnv6UOOA69c3soAn7ZOnAIubTIQSUxtq1Uhh8xRWvU,102
2
2
  sticker_convert/__main__.py,sha256=6RJauR-SCSSTT3TU7FFB6B6PVwsCxO2xZXtmZ3jc2Is,463
3
- sticker_convert/cli.py,sha256=a-RVi0afhpLSFPCC5WNIppEX0wcPtooE_9-q5Vrqfw4,19935
3
+ sticker_convert/cli.py,sha256=yI_56AfEi3Q2q8h1p8-l7wSK7wk3ktQNE_rwTAWwW1Q,20526
4
4
  sticker_convert/converter.py,sha256=XMiYzIzlcdvx_AFyyk7j-Zdyj3ablLFJFUZ6tjrlGIs,35861
5
5
  sticker_convert/definitions.py,sha256=ZhP2ALCEud-w9ZZD4c3TDG9eHGPZyaAL7zPUsJAbjtE,2073
6
- sticker_convert/gui.py,sha256=HYN7mOTIRiuBPWVLlt5-bTBtIihB6RY6c2unjxi0_8k,31779
6
+ sticker_convert/gui.py,sha256=5mJxeGgmbsniP2fpq5Ow7jNv1BQXFtWwvUyr2KWvBDo,31829
7
7
  sticker_convert/job.py,sha256=ae0DKz74nctDLSI0VU7BYI4dx3kwTM8ynky_aLspQVU,26491
8
8
  sticker_convert/job_option.py,sha256=lhcyioT6qPHrNYRBTv5wxPmmY9RkATo1-DE7-lzCwp0,7887
9
- sticker_convert/version.py,sha256=LEjpuQHNfordS9XijSLaJcY4y_Mjy8n74N7gUJEwBMs,47
9
+ sticker_convert/version.py,sha256=MMka4FopHFO0UAth4qBkny-QsgGsAkwDLnB1vTG4lqE,47
10
10
  sticker_convert/downloaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- sticker_convert/downloaders/download_base.py,sha256=9Pd3_8lz70BPP-OxIXZeRGc5PUTHB_1nv_o-IgO8mWg,4028
11
+ sticker_convert/downloaders/download_base.py,sha256=a34JcNBgZ5yf6gZnxc-B5uNaKVUG-vs3sjOJnLneWsw,4468
12
12
  sticker_convert/downloaders/download_discord.py,sha256=HeQFjJ7igb5KOk0aXQAUEuJ9OoPKyiE_mAD2_AW9PDw,3435
13
- sticker_convert/downloaders/download_kakao.py,sha256=Vei37ND_TPLsJoFE4PPzYoGFuhVDuiky8D6dUv1Zitc,11606
13
+ sticker_convert/downloaders/download_kakao.py,sha256=s1eKng2zUMXYTmdHCsSBb5B3GQ11TwfbZBCuHslcOKs,11744
14
14
  sticker_convert/downloaders/download_line.py,sha256=UwS_N_7DDnQUN63qA3RWFen7PtWSL36CXtk1tTU9cfc,17854
15
15
  sticker_convert/downloaders/download_signal.py,sha256=5mORHjGznERL60yOna3LmB2YvEoAFIzWkRv9BSFANfA,3064
16
16
  sticker_convert/downloaders/download_telegram.py,sha256=i6uuUFEfGiQbY_xY6aAQROKSQzP0c8TSZd0qFNZWydo,4615
@@ -30,10 +30,10 @@ sticker_convert/gui_components/windows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JC
30
30
  sticker_convert/gui_components/windows/advanced_compression_window.py,sha256=DT5SgSWWKXRbOD8fJK-9kch9U_P1N3ox6-bphlPr0Ss,31964
31
31
  sticker_convert/gui_components/windows/base_window.py,sha256=xBE1peGMPvWsdrFej0CJUVhmQ57GJGvz-cX03nIIhkE,1108
32
32
  sticker_convert/gui_components/windows/discord_get_auth_window.py,sha256=pUSarkXXmSr01VW9h4LgpJy7F53gw7X6ZNqunoFG-ys,2762
33
- sticker_convert/gui_components/windows/kakao_get_auth_window.py,sha256=AvXB2Q8pAPkKILHTvlLGV9jfBcvskCA4arko4nvBTdo,7115
33
+ sticker_convert/gui_components/windows/kakao_get_auth_window.py,sha256=bgqtF-LhCcqyIkuRKuEJSZ1-XrJP1UvQA6VPD3PzO0Y,11337
34
34
  sticker_convert/gui_components/windows/line_get_auth_window.py,sha256=S4ES_lk2-GDvPokZtYALnUc5zW1VbS4WulNqO9K1aSs,3375
35
35
  sticker_convert/gui_components/windows/signal_get_auth_window.py,sha256=lYvjADW3IRrqo065apSPZZtC2JCLXUqkX6lDWv79jyQ,3102
36
- sticker_convert/gui_components/windows/viber_get_auth_window.py,sha256=Ne0DG4wog7Pzw-fPsbr7HX40okFFo1INusVCSwSAQdQ,5051
36
+ sticker_convert/gui_components/windows/viber_get_auth_window.py,sha256=oHL4ipivtGT35tN5wzDKhsYsihLmoLwSDgI75g2XcCs,5183
37
37
  sticker_convert/ios-message-stickers-template/.gitignore,sha256=4uuTph_9eHfqXHUavLOmGOji6aIHOif2bUEU_hCBn4Y,9
38
38
  sticker_convert/ios-message-stickers-template/README.md,sha256=oN0FvJkCWWjSZ3PMrCvY3T1zCsdkZYFgGHAoFh0Kmt8,467
39
39
  sticker_convert/ios-message-stickers-template/.github/FUNDING.yml,sha256=3LlmdSAGDsBA2o_C1iBYTNLwkABnyZuN0zxgPPyd-f8,70
@@ -72,7 +72,7 @@ sticker_convert/resources/appicon.ico,sha256=-ldugcl2Yq2pBRTktnhGKWInpKyWzRjCiPv
72
72
  sticker_convert/resources/appicon.png,sha256=6XBEQz7PnerqS43aRkwpWolFG4WvKMuQ-st1ly-_JPg,5265
73
73
  sticker_convert/resources/compression.json,sha256=PocqDcmQ9VMPPU6HmbUGfPv6RVKMapfedoBX2Aupne0,14184
74
74
  sticker_convert/resources/emoji.json,sha256=sXSuKusyG1L2Stuf9BL5ZqfzOIOdeAeE3RXcrXAsLdY,413367
75
- sticker_convert/resources/help.json,sha256=nMDBEUZqCUJcyZVb4eoGlQeI3S7ifC9IzeBry55Dq2I,6926
75
+ sticker_convert/resources/help.json,sha256=ntzjF9fl9ExlIRR7mLEyR5JLULqUvPEm5Z7T5DL8ucs,7201
76
76
  sticker_convert/resources/input.json,sha256=1YfoqnXwUiynDZRxpyhyYSQGYR3bO8WJb_-NS1JGVBY,3476
77
77
  sticker_convert/resources/memdump_linux.sh,sha256=YbdX5C5RyCnoeDUE6JgTo8nQXKhrUw5-kFDx5bQp9tY,651
78
78
  sticker_convert/resources/memdump_windows.ps1,sha256=CfyNSSEW3HJOkTu-mKrP3qh5aprN-1VCBfj-R1fELA0,302
@@ -91,6 +91,7 @@ sticker_convert/utils/process.py,sha256=EAQZ9WpiKmkvToIv8G1HNY4V7m0jXyyePTmeP2XO
91
91
  sticker_convert/utils/url_detect.py,sha256=LTzHIHOD-L-nBE4WZEW3t0qFi1ABAegSZxLdURrPH2o,906
92
92
  sticker_convert/utils/auth/get_discord_auth.py,sha256=i5SaXU9Ly6Ci_iBYCYIPcQB5FaAehi9DidB4jbKJMVg,4215
93
93
  sticker_convert/utils/auth/get_kakao_auth.py,sha256=ipAZ1DUd5CMTpUoxRXHVOFC3DKIpxwxpTYAfrOJ6UZ8,9829
94
+ sticker_convert/utils/auth/get_kakao_desktop_auth.py,sha256=VbEec-yujlLJOBeM55Rm5deu4YE9G9Oi_AKTwOsmUMg,5815
94
95
  sticker_convert/utils/auth/get_line_auth.py,sha256=8l8ha2vQmk3rHGvDE7PkcxQXbH3oe62LKbI3qVUtvqc,2196
95
96
  sticker_convert/utils/auth/get_signal_auth.py,sha256=9L9kqpfJ4j9B10nJ8iLFKolPd6r_8TsGUDxCpTLR43o,4306
96
97
  sticker_convert/utils/auth/get_viber_auth.py,sha256=mUTrcxq5bTrzSXEVaeTPqVQIdZdwvIhrbMgBUb7dU30,8173
@@ -104,9 +105,9 @@ sticker_convert/utils/media/apple_png_normalize.py,sha256=LbrQhc7LlYX4I9ek4XJsZE
104
105
  sticker_convert/utils/media/codec_info.py,sha256=XoEWBfPWTzr4zSVQIU1XF1yh5viHxH5FytNEpdZR38c,14874
105
106
  sticker_convert/utils/media/decrypt_kakao.py,sha256=4wq9ZDRnFkx1WmFZnyEogBofiLGsWQM_X69HlA36578,1947
106
107
  sticker_convert/utils/media/format_verify.py,sha256=MH68GLJfXeL8WFT8emtj355K5BLAtUX64tQ59nugx2c,5673
107
- sticker_convert-2.10.1.dist-info/LICENSE,sha256=gXf5dRMhNSbfLPYYTY_5hsZ1r7UU1OaKQEAQUhuIBkM,18092
108
- sticker_convert-2.10.1.dist-info/METADATA,sha256=5OrR6Ep4kLN0RJhFRasKhKuYBZBer9BQiLR09Y869_I,51935
109
- sticker_convert-2.10.1.dist-info/WHEEL,sha256=R0nc6qTxuoLk7ShA2_Y-UWkN8ZdfDBG2B6Eqpz2WXbs,91
110
- sticker_convert-2.10.1.dist-info/entry_points.txt,sha256=MNJ7XyC--ugxi5jS1nzjDLGnxCyLuaGdsVLnJhDHCqs,66
111
- sticker_convert-2.10.1.dist-info/top_level.txt,sha256=r9vfnB0l1ZnH5pTH5RvkobnK3Ow9m0RsncaOMAtiAtk,16
112
- sticker_convert-2.10.1.dist-info/RECORD,,
108
+ sticker_convert-2.10.2.dist-info/LICENSE,sha256=gXf5dRMhNSbfLPYYTY_5hsZ1r7UU1OaKQEAQUhuIBkM,18092
109
+ sticker_convert-2.10.2.dist-info/METADATA,sha256=dRaXHpGKAHOllhohuhCskDSOMW0ouNp_hkCvFD5UAdU,52542
110
+ sticker_convert-2.10.2.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
111
+ sticker_convert-2.10.2.dist-info/entry_points.txt,sha256=MNJ7XyC--ugxi5jS1nzjDLGnxCyLuaGdsVLnJhDHCqs,66
112
+ sticker_convert-2.10.2.dist-info/top_level.txt,sha256=r9vfnB0l1ZnH5pTH5RvkobnK3Ow9m0RsncaOMAtiAtk,16
113
+ sticker_convert-2.10.2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (72.1.0)
2
+ Generator: setuptools (74.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5