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
File without changes
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env python3
2
+ from typing import Optional
3
+
4
+ from sticker_convert.job_option import CredOption
5
+ from sticker_convert.utils.callback import CallbackCli, CallbackProtocol
6
+
7
+
8
+ class AuthBase:
9
+ def __init__(
10
+ self,
11
+ opt_cred: CredOption,
12
+ cb: Optional[CallbackProtocol] = None,
13
+ ) -> None:
14
+ self.opt_cred = opt_cred
15
+ self.cb: CallbackProtocol
16
+ if cb is None:
17
+ self.cb = CallbackCli()
18
+ else:
19
+ self.cb = cb
@@ -4,23 +4,27 @@ import os
4
4
  import platform
5
5
  import shutil
6
6
  import time
7
- from typing import Callable, Optional, Tuple
7
+ from pathlib import Path
8
+ from typing import Any, Optional, Tuple
8
9
  from urllib.parse import urlparse
9
10
 
11
+ from sticker_convert.auth.auth_base import AuthBase
10
12
  from sticker_convert.definitions import CONFIG_DIR
11
13
  from sticker_convert.utils.chrome_remotedebug import CRD
12
- from sticker_convert.utils.process import killall
14
+ from sticker_convert.utils.process import find_pid_by_name, killall
13
15
 
16
+ OK_MSG = "Got token successfully:\ntoken={token}"
17
+ FAIL_MSG = "Failed to get token"
14
18
 
15
- class GetDiscordAuth:
16
- def __init__(self, cb_msg: Callable[..., None] = print) -> None:
19
+
20
+ class AuthDiscord(AuthBase):
21
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
22
+ super().__init__(*args, **kwargs)
17
23
  chromedriver_download_dir = CONFIG_DIR / "bin"
18
24
  os.makedirs(chromedriver_download_dir, exist_ok=True)
19
25
 
20
26
  self.chromedriver_download_dir = chromedriver_download_dir
21
27
 
22
- self.cb_msg = cb_msg
23
-
24
28
  def get_discord_bin_path(self) -> Optional[str]:
25
29
  discord_bin: Optional[str]
26
30
  if platform.system() == "Windows":
@@ -42,6 +46,8 @@ class GetDiscordAuth:
42
46
  for discord_dir, discord_bin in discord_win_dirs:
43
47
  app_dir: Optional[str] = None
44
48
  chrome_path: Optional[str] = None
49
+ if os.path.isdir(discord_dir) is False:
50
+ continue
45
51
  for i in [j for j in os.listdir(discord_dir) if j.startswith("app-")]:
46
52
  app_dir = os.path.join(discord_dir, i)
47
53
  chrome_path = os.path.join(app_dir, discord_bin)
@@ -67,6 +73,9 @@ class GetDiscordAuth:
67
73
  return None
68
74
 
69
75
  def get_cred(self) -> Tuple[Optional[str], str]:
76
+ msg = "Getting Discord authorization token..."
77
+ self.cb.put(("msg_dynamic", (msg,), None))
78
+
70
79
  using_discord_app = False
71
80
  chrome_path = self.get_discord_bin_path()
72
81
  if chrome_path is not None:
@@ -74,14 +83,26 @@ class GetDiscordAuth:
74
83
  else:
75
84
  chrome_path = CRD.get_chromium_path()
76
85
  if chrome_path is None:
86
+ self.cb.put(("msg_dynamic", (None,), None))
77
87
  return (
78
88
  None,
79
89
  "Please install Discord Desktop or Chrome/Chromium and try again",
80
90
  )
81
91
 
82
92
  token = None
83
- if using_discord_app:
84
- killall("discord")
93
+
94
+ if find_pid_by_name(Path(chrome_path).name):
95
+ response = self.cb.put(
96
+ (
97
+ "ask_bool",
98
+ (f"All {Path(chrome_path).name} will be closed. Continue?",),
99
+ None,
100
+ )
101
+ )
102
+ if response is True:
103
+ killall(Path(chrome_path).name.lower())
104
+ else:
105
+ return None, FAIL_MSG
85
106
 
86
107
  crd = CRD(chrome_path)
87
108
  while True:
@@ -98,9 +119,14 @@ class GetDiscordAuth:
98
119
 
99
120
  while True:
100
121
  try:
101
- r = crd.exec_js(
102
- "(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();"
103
- )
122
+ if using_discord_app:
123
+ r = crd.exec_js(
124
+ "(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();"
125
+ )
126
+ else:
127
+ r = crd.exec_js(
128
+ "const iframe=document.createElement('iframe');JSON.parse(document.body.appendChild(iframe).contentWindow.localStorage.token);"
129
+ )
104
130
  except RuntimeError:
105
131
  break
106
132
  if (
@@ -112,7 +138,8 @@ class GetDiscordAuth:
112
138
  time.sleep(1)
113
139
  crd.close()
114
140
 
141
+ self.cb.put(("msg_dynamic", (None,), None))
115
142
  if token is None:
116
- return None, "Failed to get token"
143
+ return None, FAIL_MSG
117
144
 
118
- return token, f"Got token successfully:\ntoken={token}"
145
+ return token, OK_MSG.format(token=token)
@@ -2,31 +2,24 @@
2
2
  import json
3
3
  import secrets
4
4
  import uuid
5
- from typing import Any, Callable, Dict, Optional
5
+ from typing import Any, Dict, Optional, Tuple
6
6
  from urllib.parse import parse_qs, urlparse
7
7
 
8
8
  import requests
9
9
  from bs4 import BeautifulSoup
10
10
 
11
- from sticker_convert.job_option import CredOption
11
+ from sticker_convert.auth.auth_base import AuthBase
12
12
 
13
+ OK_MSG = "Got auth_token successfully:\n{auth_token=}\n"
13
14
 
14
- class GetKakaoAuth:
15
- def __init__(
16
- self,
17
- opt_cred: CredOption,
18
- cb_msg: Callable[..., None] = print,
19
- cb_msg_block: Callable[..., Any] = input,
20
- cb_ask_str: Callable[..., str] = input,
21
- ) -> None:
22
- self.username = opt_cred.kakao_username
23
- self.password = opt_cred.kakao_password
24
- self.country_code = opt_cred.kakao_country_code
25
- self.phone_number = opt_cred.kakao_phone_number
26
15
 
27
- self.cb_msg = cb_msg
28
- self.cb_msg_block = cb_msg_block
29
- self.cb_ask_str = cb_ask_str
16
+ class AuthKakaoAndroidLogin(AuthBase):
17
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
18
+ super().__init__(*args, **kwargs)
19
+ self.username = self.opt_cred.kakao_username
20
+ self.password = self.opt_cred.kakao_password
21
+ self.country_code = self.opt_cred.kakao_country_code
22
+ self.phone_number = self.opt_cred.kakao_phone_number
30
23
 
31
24
  self.device_uuid = secrets.token_hex(32)
32
25
  self.device_ssaid = secrets.token_hex(20)
@@ -67,8 +60,9 @@ class GetKakaoAuth:
67
60
  return a.get("href").split("/")[-1]
68
61
  return "25.2.1"
69
62
 
70
- def login(self) -> bool:
71
- self.cb_msg("Logging in")
63
+ def login(self) -> Tuple[bool, str]:
64
+ msg = "Getting Kakao authorization token by Android login: Logging in"
65
+ self.cb.put(("msg_dynamic", (msg,), None))
72
66
 
73
67
  json_data = {
74
68
  "id": self.username,
@@ -83,29 +77,29 @@ class GetKakaoAuth:
83
77
 
84
78
  response_json = json.loads(response.text)
85
79
 
80
+ self.cb.put(("msg_dynamic", (None,), None))
86
81
  if response_json["status"] != 0:
87
- self.cb_msg_block(f"Failed at login: {response.text}")
88
- return False
82
+ return False, f"Failed at login: {response.text}"
89
83
 
90
84
  self.headers["Ss"] = response.headers["Set-SS"]
91
85
  self.country_dicts = response_json["viewData"]["countries"]["all"]
92
86
 
93
- return True
87
+ return True, ""
94
88
 
95
- def get_country_iso(self) -> bool:
89
+ def get_country_iso(self) -> Tuple[bool, str]:
96
90
  self.country_iso = None
97
91
  for country_dict in self.country_dicts:
98
92
  if country_dict["code"] == self.country_code:
99
93
  self.country_iso = country_dict["iso"]
100
94
 
101
95
  if not self.country_iso:
102
- self.cb_msg_block("Invalid country code")
103
- return False
96
+ return False, "Invalid country code"
104
97
 
105
- return True
98
+ return True, ""
106
99
 
107
- def enter_phone(self) -> bool:
108
- self.cb_msg("Submitting phone number")
100
+ def enter_phone(self) -> Tuple[bool, str]:
101
+ msg = "Getting Kakao authorization token by Android login: Submitting phone number"
102
+ self.cb.put(("msg_dynamic", (msg,), None))
109
103
 
110
104
  json_data: Dict[str, Any] = {
111
105
  "countryCode": self.country_code,
@@ -123,9 +117,9 @@ class GetKakaoAuth:
123
117
 
124
118
  response_json = json.loads(response.text)
125
119
 
120
+ self.cb.put(("msg_dynamic", (None,), None))
126
121
  if response_json["status"] != 0:
127
- self.cb_msg_block(f"Failed at entering phone number: {response.text}")
128
- return False
122
+ return False, f"Failed at entering phone number: {response.text}"
129
123
 
130
124
  self.verify_method = response_json["view"]
131
125
 
@@ -135,12 +129,9 @@ class GetKakaoAuth:
135
129
  dest_number = response_json["viewData"]["moNumber"]
136
130
  msg = response_json["viewData"]["moMessage"]
137
131
  return self.verify_send_sms(dest_number, msg)
138
- self.cb_msg_block(f"Unknown verification method: {response.text}")
139
- return False
140
-
141
- def verify_send_sms(self, dest_number: str, msg: str) -> bool:
142
- self.cb_msg("Verification by sending SMS")
132
+ return False, f"Unknown verification method: {response.text}"
143
133
 
134
+ def verify_send_sms(self, dest_number: str, verify_msg: str) -> Tuple[bool, str]:
144
135
  response = requests.post(
145
136
  "https://katalk.kakao.com/android/account2/mo-sent", headers=self.headers
146
137
  )
@@ -148,15 +139,20 @@ class GetKakaoAuth:
148
139
  response_json = json.loads(response.text)
149
140
 
150
141
  if response_json["status"] != 0:
151
- self.cb_msg_block(f"Failed at confirm sending SMS: {response.text}")
152
- return False
142
+ return False, f"Failed at confirm sending SMS: {response.text}"
153
143
 
154
144
  prompt = f"Send this SMS message to number {dest_number} then press enter:"
155
- self.cb_msg(msg)
156
- if self.cb_ask_str != input:
157
- self.cb_ask_str(prompt, initialvalue=msg, cli_show_initialvalue=False)
158
- else:
159
- input(prompt)
145
+ self.cb.put(
146
+ (
147
+ "ask_str",
148
+ None,
149
+ {
150
+ "msg": prompt,
151
+ "initialvalue": verify_msg,
152
+ "cli_show_initialvalue": False,
153
+ },
154
+ )
155
+ )
160
156
 
161
157
  response = requests.post(
162
158
  "https://katalk.kakao.com/android/account2/mo-confirm", headers=self.headers
@@ -165,21 +161,18 @@ class GetKakaoAuth:
165
161
  response_json = json.loads(response.text)
166
162
 
167
163
  if response_json["status"] != 0:
168
- self.cb_msg_block(f"Failed at verifying SMS sent: {response.text}")
169
- return False
164
+ return False, f"Failed at verifying SMS sent: {response.text}"
170
165
 
171
166
  if response_json.get("reason") or "error" in response_json.get("message", ""):
172
- self.cb_msg_block(f"Failed at verifying SMS sent: {response.text}")
173
- return False
167
+ return False, f"Failed at verifying SMS sent: {response.text}"
174
168
 
175
169
  self.confirm_url = response_json.get("viewData", {}).get("url")
176
170
 
177
- return True
178
-
179
- def verify_receive_sms(self) -> bool:
180
- self.cb_msg("Verification by receiving SMS")
171
+ return True, ""
181
172
 
182
- passcode = self.cb_ask_str("Enter passcode received from SMS:")
173
+ def verify_receive_sms(self) -> Tuple[bool, str]:
174
+ msg = "Enter passcode received from SMS:"
175
+ passcode = self.cb.put(("ask_str", (msg,), None))
183
176
 
184
177
  json_data = {
185
178
  "passcode": passcode,
@@ -193,16 +186,19 @@ class GetKakaoAuth:
193
186
 
194
187
  response_json = json.loads(response.text)
195
188
 
189
+ self.cb.put(("msg_dynamic", (None,), None))
196
190
  if response_json["status"] != 0:
197
- self.cb_msg_block(f"Failed at verifying passcode: {response.text}")
198
- return False
191
+ return False, f"Failed at verifying passcode: {response.text}"
199
192
 
200
193
  self.confirm_url = response_json.get("viewData", {}).get("url")
201
194
 
202
- return True
195
+ return True, ""
203
196
 
204
- def confirm_device_change(self) -> bool:
205
- self.cb_msg("Confirm device change")
197
+ def confirm_device_change(self) -> Tuple[bool, str]:
198
+ msg = (
199
+ "Getting Kakao authorization token by Android login: Confirm device change"
200
+ )
201
+ self.cb.put(("msg_dynamic", (msg,), None))
206
202
 
207
203
  confirm_url_parsed = urlparse(self.confirm_url) # type: ignore
208
204
  confirm_url_qs = parse_qs(confirm_url_parsed.query) # type: ignore
@@ -238,14 +234,15 @@ class GetKakaoAuth:
238
234
 
239
235
  response_json = json.loads(response.text)
240
236
 
237
+ self.cb.put(("msg_dynamic", (None,), None))
241
238
  if response_json["status"] != 0:
242
- self.cb_msg_block(f"Failed at confirm device change: {response.text}")
243
- return False
239
+ return False, f"Failed at confirm device change: {response.text}"
244
240
 
245
- return True
241
+ return True, ""
246
242
 
247
- def passcode_callback(self) -> bool:
248
- self.cb_msg("Passcode callback")
243
+ def passcode_callback(self) -> Tuple[bool, str]:
244
+ msg = "Getting Kakao authorization token by Android login: Passcode callback"
245
+ self.cb.put(("msg_dynamic", (msg,), None))
249
246
 
250
247
  response = requests.get(
251
248
  "https://katalk.kakao.com/android/account2/passcode/callback",
@@ -254,14 +251,15 @@ class GetKakaoAuth:
254
251
 
255
252
  response_json = json.loads(response.text)
256
253
 
254
+ self.cb.put(("msg_dynamic", (None,), None))
257
255
  if response_json["status"] != 0:
258
- self.cb_msg_block(f"Failed at passcode callback: {response.text}")
259
- return False
256
+ return False, f"Failed at passcode callback: {response.text}"
260
257
 
261
- return True
258
+ return True, ""
262
259
 
263
- def skip_restoration(self) -> bool:
264
- self.cb_msg("Skip restoration")
260
+ def skip_restoration(self) -> Tuple[bool, str]:
261
+ msg = "Getting Kakao authorization token by Android login: Skip restoration"
262
+ self.cb.put(("msg_dynamic", (msg,), None))
265
263
 
266
264
  response = requests.post(
267
265
  "https://katalk.kakao.com/android/account2/skip-restoration",
@@ -270,19 +268,19 @@ class GetKakaoAuth:
270
268
  response_json = json.loads(response.text)
271
269
 
272
270
  if response_json["status"] != 0:
273
- self.cb_msg_block(f"Failed at skip restoration: {response.text}")
274
- return False
271
+ return False, f"Failed at skip restoration: {response.text}"
275
272
 
276
273
  self.nickname = response_json.get("viewData", {}).get("nickname")
277
274
 
275
+ self.cb.put(("msg_dynamic", (None,), None))
278
276
  if self.nickname is None:
279
- self.cb_msg_block(f"Failed at passcode callback: {response.text}")
280
- return False
277
+ return False, f"Failed at passcode callback: {response.text}"
281
278
 
282
- return True
279
+ return True, ""
283
280
 
284
- def get_profile(self) -> bool:
285
- self.cb_msg("Get profile")
281
+ def get_profile(self) -> Tuple[bool, str]:
282
+ msg = "Getting Kakao authorization token by Android login: Get profile"
283
+ self.cb.put(("msg_dynamic", (msg,), None))
286
284
 
287
285
  json_data = {
288
286
  "nickname": self.nickname,
@@ -298,18 +296,16 @@ class GetKakaoAuth:
298
296
 
299
297
  response_json = json.loads(response.text)
300
298
 
299
+ self.cb.put(("msg_dynamic", (None,), None))
301
300
  if response_json["status"] != 0:
302
- self.cb_msg_block(f"Failed at get profile: {response.text}")
303
- return False
301
+ return False, f"Failed at get profile: {response.text}"
304
302
 
305
303
  self.access_token = response_json["signupData"]["oauth2Token"]["accessToken"]
306
304
 
307
- return True
308
-
309
- def get_cred(self) -> Optional[str]:
310
- self.cb_msg("Get authorization token")
305
+ return True, ""
311
306
 
312
- authorization_token = None
307
+ def get_cred(self) -> Tuple[Optional[str], str]:
308
+ auth_token = None
313
309
 
314
310
  steps = (
315
311
  self.login,
@@ -322,9 +318,9 @@ class GetKakaoAuth:
322
318
  )
323
319
 
324
320
  for step in steps:
325
- success = step()
321
+ success, msg = step()
326
322
  if not success:
327
- return None
323
+ return None, msg
328
324
 
329
- authorization_token = self.access_token + "-" + self.device_uuid
330
- return authorization_token
325
+ auth_token = self.access_token + "-" + self.device_uuid
326
+ return auth_token, OK_MSG.format(auth_token=auth_token)