sticker-convert 2.13.3.0__py3-none-any.whl → 2.17.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 (93) hide show
  1. sticker_convert/__main__.py +24 -27
  2. sticker_convert/auth/__init__.py +0 -0
  3. sticker_convert/auth/auth_base.py +19 -0
  4. sticker_convert/{utils/auth/get_discord_auth.py → auth/auth_discord.py} +149 -118
  5. sticker_convert/{utils/auth/get_kakao_auth.py → auth/auth_kakao_android_login.py} +331 -330
  6. sticker_convert/auth/auth_kakao_desktop_login.py +327 -0
  7. sticker_convert/{utils/auth/get_kakao_desktop_auth.py → auth/auth_kakao_desktop_memdump.py} +281 -263
  8. sticker_convert/{utils/auth/get_line_auth.py → auth/auth_line.py} +98 -80
  9. sticker_convert/{utils/auth/get_signal_auth.py → auth/auth_signal.py} +139 -135
  10. sticker_convert/auth/auth_telethon.py +161 -0
  11. sticker_convert/{utils/auth/get_viber_auth.py → auth/auth_viber.py} +250 -235
  12. sticker_convert/{utils/auth → auth}/telegram_api.py +736 -675
  13. sticker_convert/cli.py +623 -608
  14. sticker_convert/converter.py +1093 -1084
  15. sticker_convert/definitions.py +4 -0
  16. sticker_convert/downloaders/download_band.py +111 -110
  17. sticker_convert/downloaders/download_base.py +171 -166
  18. sticker_convert/downloaders/download_discord.py +92 -91
  19. sticker_convert/downloaders/download_kakao.py +417 -404
  20. sticker_convert/downloaders/download_line.py +484 -475
  21. sticker_convert/downloaders/download_ogq.py +80 -79
  22. sticker_convert/downloaders/download_signal.py +108 -105
  23. sticker_convert/downloaders/download_telegram.py +56 -55
  24. sticker_convert/downloaders/download_viber.py +121 -120
  25. sticker_convert/gui.py +788 -873
  26. sticker_convert/gui_components/frames/comp_frame.py +180 -166
  27. sticker_convert/gui_components/frames/config_frame.py +156 -113
  28. sticker_convert/gui_components/frames/control_frame.py +32 -30
  29. sticker_convert/gui_components/frames/cred_frame.py +232 -233
  30. sticker_convert/gui_components/frames/input_frame.py +139 -137
  31. sticker_convert/gui_components/frames/output_frame.py +112 -110
  32. sticker_convert/gui_components/frames/right_clicker.py +25 -23
  33. sticker_convert/gui_components/windows/advanced_compression_window.py +757 -757
  34. sticker_convert/gui_components/windows/base_window.py +7 -2
  35. sticker_convert/gui_components/windows/discord_get_auth_window.py +79 -82
  36. sticker_convert/gui_components/windows/kakao_get_auth_window.py +511 -321
  37. sticker_convert/gui_components/windows/line_get_auth_window.py +94 -102
  38. sticker_convert/gui_components/windows/signal_get_auth_window.py +84 -89
  39. sticker_convert/gui_components/windows/viber_get_auth_window.py +168 -168
  40. sticker_convert/ios-message-stickers-template/.github/FUNDING.yml +3 -3
  41. sticker_convert/ios-message-stickers-template/README.md +10 -10
  42. sticker_convert/ios-message-stickers-template/stickers/Info.plist +43 -43
  43. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Info.plist +31 -31
  44. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/Contents.json +6 -6
  45. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/Contents.json +20 -20
  46. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/Sticker 1.sticker/Contents.json +9 -9
  47. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/Sticker 2.sticker/Contents.json +9 -9
  48. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/Sticker 3.sticker/Contents.json +9 -9
  49. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/Contents.json +91 -91
  50. sticker_convert/ios-message-stickers-template/stickers.xcodeproj/project.pbxproj +364 -364
  51. sticker_convert/ios-message-stickers-template/stickers.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -7
  52. sticker_convert/ios-message-stickers-template/stickers.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -8
  53. sticker_convert/ios-message-stickers-template/stickers.xcodeproj/xcuserdata/niklaspeterson.xcuserdatad/xcschemes/xcschememanagement.plist +14 -14
  54. sticker_convert/job.py +166 -130
  55. sticker_convert/job_option.py +1 -0
  56. sticker_convert/locales/en_US/LC_MESSAGES/base.mo +0 -0
  57. sticker_convert/locales/ja_JP/LC_MESSAGES/base.mo +0 -0
  58. sticker_convert/locales/zh_CN/LC_MESSAGES/base.mo +0 -0
  59. sticker_convert/locales/zh_TW/LC_MESSAGES/base.mo +0 -0
  60. sticker_convert/py.typed +0 -0
  61. sticker_convert/resources/NotoColorEmoji.ttf +0 -0
  62. sticker_convert/resources/help.ja_JP.json +88 -0
  63. sticker_convert/resources/help.json +10 -7
  64. sticker_convert/resources/help.zh_CN.json +88 -0
  65. sticker_convert/resources/help.zh_TW.json +88 -0
  66. sticker_convert/resources/input.ja_JP.json +74 -0
  67. sticker_convert/resources/input.json +121 -121
  68. sticker_convert/resources/input.zh_CN.json +74 -0
  69. sticker_convert/resources/input.zh_TW.json +74 -0
  70. sticker_convert/resources/output.ja_JP.json +38 -0
  71. sticker_convert/resources/output.zh_CN.json +38 -0
  72. sticker_convert/resources/output.zh_TW.json +38 -0
  73. sticker_convert/uploaders/compress_wastickers.py +186 -177
  74. sticker_convert/uploaders/upload_base.py +44 -35
  75. sticker_convert/uploaders/upload_signal.py +218 -203
  76. sticker_convert/uploaders/upload_telegram.py +353 -338
  77. sticker_convert/uploaders/upload_viber.py +178 -169
  78. sticker_convert/uploaders/xcode_imessage.py +295 -286
  79. sticker_convert/utils/callback.py +238 -6
  80. sticker_convert/utils/emoji.py +16 -4
  81. sticker_convert/utils/files/json_resources_loader.py +24 -19
  82. sticker_convert/utils/files/metadata_handler.py +3 -3
  83. sticker_convert/utils/translate.py +108 -0
  84. sticker_convert/utils/url_detect.py +40 -37
  85. sticker_convert/version.py +1 -1
  86. {sticker_convert-2.13.3.0.dist-info → sticker_convert-2.17.0.0.dist-info}/METADATA +89 -74
  87. {sticker_convert-2.13.3.0.dist-info → sticker_convert-2.17.0.0.dist-info}/RECORD +91 -74
  88. sticker_convert/utils/auth/telethon_setup.py +0 -97
  89. sticker_convert/utils/singletons.py +0 -18
  90. {sticker_convert-2.13.3.0.dist-info → sticker_convert-2.17.0.0.dist-info}/WHEEL +0 -0
  91. {sticker_convert-2.13.3.0.dist-info → sticker_convert-2.17.0.0.dist-info}/entry_points.txt +0 -0
  92. {sticker_convert-2.13.3.0.dist-info → sticker_convert-2.17.0.0.dist-info}/licenses/LICENSE +0 -0
  93. {sticker_convert-2.13.3.0.dist-info → sticker_convert-2.17.0.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,327 @@
1
+ #!/usr/bin/env python3
2
+ import base64
3
+ import hashlib
4
+ import json
5
+ import os
6
+ import platform
7
+ import re
8
+ import shutil
9
+ import socket
10
+ import subprocess
11
+ import time
12
+ import uuid
13
+ from typing import Any, Optional, Tuple
14
+
15
+ import requests
16
+ from bs4 import BeautifulSoup
17
+ from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
18
+
19
+ from sticker_convert.auth.auth_base import AuthBase
20
+ from sticker_convert.utils.translate import I
21
+
22
+
23
+ class AuthKakaoDesktopLogin(AuthBase):
24
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
25
+ self.OK_MSG = I("Login successful, auth_token={}")
26
+
27
+ super().__init__(*args, **kwargs)
28
+ self.username = self.opt_cred.kakao_username
29
+ self.password = self.opt_cred.kakao_password
30
+
31
+ if platform.system() == "Darwin":
32
+ self.plat = "mac"
33
+ user_agent_os = "Mc"
34
+ self.os_version = platform.mac_ver()[0]
35
+ version = self.macos_get_ver()
36
+ if version is None:
37
+ version = "25.2.0"
38
+ else:
39
+ self.plat = "win32"
40
+ user_agent_os = "Wd"
41
+ if platform.system() == "Windows":
42
+ self.os_version = platform.uname().version
43
+ else:
44
+ self.os_version = "10.0"
45
+ version = self.windows_get_ver()
46
+ if version is None:
47
+ version = "25.8.2"
48
+
49
+ user_agent = f"KT/{version} {user_agent_os}/{self.os_version} en"
50
+ self.headers = {
51
+ "user-agent": user_agent,
52
+ "a": f"{self.plat}/{version}/en",
53
+ "accept": "*/*",
54
+ "accept-encoding": "gzip, deflate, br",
55
+ "accept-language": "en",
56
+ "host": "katalk.kakao.com",
57
+ "Connection": "close",
58
+ }
59
+
60
+ self.device_name = socket.gethostname()
61
+ if platform.system() != "Darwin":
62
+ self.device_name = self.device_name.upper()
63
+ self.device_uuid = self.get_device_uuid()
64
+
65
+ hash = hashlib.sha512(
66
+ f"KLEAL|{self.username}|{self.device_uuid}|LCNUE|{user_agent}".encode(
67
+ "utf-8"
68
+ )
69
+ ).hexdigest()
70
+ xvc = hash[:16]
71
+
72
+ self.headers_login = self.headers.copy()
73
+ self.headers_login["x-vc"] = xvc
74
+
75
+ def pkcs7_pad(self, m: str) -> str:
76
+ return m + chr(16 - len(m) % 16) * (16 - len(m) % 16)
77
+
78
+ def windows_get_ver(self) -> Optional[str]:
79
+ r = requests.get(
80
+ "https://api.github.com/repos/microsoft/winget-pkgs/contents/manifests/k/Kakao/KakaoTalk"
81
+ )
82
+ rjson = json.loads(r.text)
83
+ if len(rjson) == 0:
84
+ return None
85
+ ver = rjson[-1]["name"]
86
+ return ".".join(ver.split(".")[:3])
87
+
88
+ def macos_get_ver(self) -> Optional[str]:
89
+ country = "us"
90
+ app_name = "kakaotalk-messenger"
91
+ app_id = "362057947"
92
+
93
+ url = f"https://apps.apple.com/{country}/app/{app_name}/id{app_id}"
94
+
95
+ r = requests.get(url)
96
+ soup = BeautifulSoup(r.text, "html.parser")
97
+ version_tag = soup.find("p", {"class": re.compile(".*latest__version")})
98
+ version_str = None
99
+ if version_tag is not None:
100
+ version_str = version_tag.text.replace("Version ", "")
101
+ return version_str
102
+
103
+ def windows_get_pragma(self, use_wine: bool = False) -> Optional[str]:
104
+ sys_uuid = None
105
+ hdd_model = None
106
+ hdd_serial = None
107
+
108
+ if use_wine and shutil.which("wine") is None:
109
+ return None
110
+
111
+ regkey = "HKEY_CURRENT_USER\\Software\\Kakao\\KakaoTalk\\DeviceInfo"
112
+ wine = "wine " if use_wine else ""
113
+ cmd = f"{wine}reg query '{regkey}' /v Last"
114
+ last_device_info = subprocess.run(
115
+ cmd, stdout=subprocess.PIPE, shell=True
116
+ ).stdout.decode()
117
+ if "REG_SZ" not in last_device_info:
118
+ return None
119
+ last_device_info = last_device_info.split("\n")[2].split()[2]
120
+
121
+ if self.opt_cred.kakao_device_uuid:
122
+ sys_uuid = self.opt_cred.kakao_device_uuid
123
+ else:
124
+ cmd = f"{wine}reg query '{regkey}\\{last_device_info}' /v sys_uuid"
125
+ sys_uuid = subprocess.run(
126
+ cmd, stdout=subprocess.PIPE, shell=True
127
+ ).stdout.decode()
128
+ if "REG_SZ" in sys_uuid:
129
+ sys_uuid = sys_uuid.split("\n")[2].split()[2]
130
+
131
+ cmd = f"{wine}reg query '{regkey}\\{last_device_info}' /v hdd_model"
132
+ hdd_model = subprocess.run(
133
+ cmd, stdout=subprocess.PIPE, shell=True
134
+ ).stdout.decode()
135
+ if "REG_SZ" in hdd_model:
136
+ hdd_model = hdd_model.split("\n")[2].split()[2]
137
+
138
+ cmd = f"{wine}reg query '{regkey}\\{last_device_info}' /v hdd_serial"
139
+ hdd_serial = subprocess.run(
140
+ cmd, stdout=subprocess.PIPE, shell=True
141
+ ).stdout.decode()
142
+ if "REG_SZ" in hdd_serial:
143
+ hdd_serial = hdd_serial.split("\n")[2].split()[2]
144
+
145
+ if sys_uuid and hdd_model and hdd_serial:
146
+ return f"{sys_uuid}|{hdd_model}|{hdd_serial}"
147
+ else:
148
+ return None
149
+
150
+ def get_device_uuid(self) -> str:
151
+ if platform.system() == "Darwin":
152
+ cmd = "ioreg -rd1 -c IOPlatformExpertDevice | grep IOPlatformUUID | awk '{print $3}'"
153
+ result = subprocess.run(cmd, stdout=subprocess.PIPE, shell=True, check=True)
154
+ hwid = result.stdout.decode().strip().replace('"', "")
155
+
156
+ hwid_sha1 = bytes.fromhex(hashlib.sha1(hwid.encode()).hexdigest())
157
+ hwid_sha256 = bytes.fromhex(hashlib.sha256(hwid.encode()).hexdigest())
158
+
159
+ return base64.b64encode(hwid_sha1 + hwid_sha256).decode()
160
+ else:
161
+ use_wine = True if platform.system() != "Windows" else False
162
+ pragma = self.windows_get_pragma(use_wine=use_wine)
163
+ if pragma is None:
164
+ if platform.system() == "Windows":
165
+ if self.opt_cred.kakao_device_uuid:
166
+ sys_uuid = self.opt_cred.kakao_device_uuid
167
+ else:
168
+ cmd = "wmic csproduct get uuid"
169
+ result = subprocess.run(cmd, stdout=subprocess.PIPE, shell=True)
170
+ sys_uuid = result.stdout.decode().split("\n")[1].strip()
171
+ cmd = "wmic diskdrive get Model"
172
+ result = subprocess.run(cmd, stdout=subprocess.PIPE, shell=True)
173
+ hdd_model = result.stdout.decode().split("\n")[1].strip()
174
+ cmd = "wmic diskdrive get SerialNumber"
175
+ result = subprocess.run(cmd, stdout=subprocess.PIPE, shell=True)
176
+ hdd_serial = result.stdout.decode().split("\n")[1].strip()
177
+ else:
178
+ if self.opt_cred.kakao_device_uuid:
179
+ sys_uuid = self.opt_cred.kakao_device_uuid
180
+ else:
181
+ product_uuid_path = "/sys/devices/virtual/dmi/id/product_uuid"
182
+ sys_uuid = None
183
+ if os.access(product_uuid_path, os.R_OK):
184
+ cmd = f"cat {product_uuid_path}"
185
+ result = subprocess.run(
186
+ cmd, stdout=subprocess.PIPE, shell=True
187
+ )
188
+ if result.returncode == 0:
189
+ sys_uuid = result.stdout.decode().strip()
190
+ if sys_uuid is None:
191
+ sys_uuid = str(uuid.uuid4()).upper()
192
+ self.opt_cred.kakao_device_uuid = sys_uuid
193
+ hdd_model = "Wine Disk Drive"
194
+ hdd_serial = ""
195
+ pragma = f"{sys_uuid}|{hdd_model}|{hdd_serial}"
196
+
197
+ aes_key = bytes.fromhex("9FBAE3118FDE5DEAEB8279D08F1D4C79")
198
+ aes_iv = bytes.fromhex("00000000000000000000000000000000")
199
+
200
+ cipher = Cipher(algorithms.AES(aes_key), modes.CBC(aes_iv))
201
+ encryptor = cipher.encryptor()
202
+ padded = self.pkcs7_pad(pragma).encode()
203
+ encrypted_pragma = encryptor.update(padded) + encryptor.finalize()
204
+ pragma_hash = hashlib.sha512(encrypted_pragma).digest()
205
+
206
+ return base64.b64encode(pragma_hash).decode()
207
+
208
+ def login(self, forced: bool = False):
209
+ data = {
210
+ "device_name": self.device_name,
211
+ "device_uuid": self.device_uuid,
212
+ "email": self.username,
213
+ "os_version": self.os_version,
214
+ "password": self.password,
215
+ "permanent": "1",
216
+ }
217
+
218
+ if forced:
219
+ data["forced"] = "1"
220
+
221
+ headers = self.headers_login.copy()
222
+ headers["content-type"] = "application/x-www-form-urlencoded"
223
+ response = requests.post(
224
+ f"https://katalk.kakao.com/{self.plat}/account/login.json",
225
+ headers=headers,
226
+ data=data,
227
+ )
228
+
229
+ return json.loads(response.text)
230
+
231
+ def generate_passcode(self):
232
+ data = {
233
+ "password": self.password,
234
+ "permanent": True,
235
+ "device": {
236
+ "name": self.device_name,
237
+ "osVersion": self.os_version,
238
+ "uuid": self.device_uuid,
239
+ },
240
+ "email": self.username,
241
+ }
242
+
243
+ if platform.system() == "Darwin":
244
+ cmd = "sysctl -n hw.model"
245
+ result = subprocess.run(cmd, stdout=subprocess.PIPE, shell=True, check=True)
246
+ data["device"]["model"] = result.stdout.decode().strip() # type: ignore
247
+
248
+ headers = self.headers_login.copy()
249
+ headers["content-type"] = "application/json"
250
+ response = requests.post(
251
+ f"https://katalk.kakao.com/{self.plat}/account/passcodeLogin/generate",
252
+ headers=headers,
253
+ json=data,
254
+ )
255
+
256
+ return json.loads(response.text)
257
+
258
+ def register_device(self):
259
+ data = {
260
+ "device": {"uuid": self.device_uuid},
261
+ "email": self.username,
262
+ "password": self.password,
263
+ }
264
+
265
+ headers = self.headers_login.copy()
266
+ headers["content-type"] = "application/json"
267
+ response = None
268
+
269
+ response = requests.post(
270
+ f"https://katalk.kakao.com/{self.plat}/account/passcodeLogin/registerDevice",
271
+ headers=headers,
272
+ json=data,
273
+ )
274
+ return json.loads(response.text)
275
+
276
+ def get_cred(self) -> Tuple[Optional[str], str]:
277
+ msg = I("Getting Kakao authorization token by desktop login...")
278
+ self.cb.put(("msg_dynamic", (msg,), None))
279
+ rjson = self.login()
280
+ access_token = rjson.get("access_token")
281
+ if access_token is not None:
282
+ auth_token = access_token + "-" + self.device_uuid
283
+ self.cb.put(("msg_dynamic", (None,), None))
284
+ return auth_token, self.OK_MSG.format(auth_token)
285
+
286
+ rjson = self.generate_passcode()
287
+ if rjson.get("status") != 0:
288
+ return None, I("Failed to generate passcode: {}").format(rjson)
289
+ passcode = rjson["passcode"]
290
+
291
+ fail_reason = None
292
+ self.cb.put(("msg_dynamic", (None,), None))
293
+ while True:
294
+ rjson = self.register_device()
295
+ if rjson["status"] == 0:
296
+ break
297
+ elif rjson["status"] == -110:
298
+ fail_reason = "Timeout"
299
+ break
300
+ elif rjson["status"] != -100:
301
+ fail_reason = str(rjson)
302
+ break
303
+ time_remaining = rjson.get("remainingSeconds")
304
+ next_req_time = rjson.get("nextRequestIntervalInSeconds")
305
+ if time_remaining is None or next_req_time is None:
306
+ fail_reason = str(rjson)
307
+ msg = I(
308
+ "Please enter passcode in Kakao app on mobile device within {} seconds: {}"
309
+ ).format(time_remaining, passcode)
310
+ msg_dynamic_window_exist = self.cb.put(("msg_dynamic", (msg,), None))
311
+ if msg_dynamic_window_exist is False:
312
+ fail_reason = "Cancelled"
313
+ break
314
+ time.sleep(next_req_time)
315
+ self.cb.put(("msg_dynamic", (None,), None))
316
+ if fail_reason is not None:
317
+ return None, I("Failed to register device: {}").format(fail_reason)
318
+
319
+ rjson = self.login()
320
+ if rjson.get("status") == -101:
321
+ rjson = self.login(forced=True)
322
+ access_token = rjson.get("access_token")
323
+ if access_token is None:
324
+ return None, I("Failed to login after registering device: {}").format(rjson)
325
+
326
+ auth_token = access_token + "-" + self.device_uuid
327
+ return auth_token, self.OK_MSG.format(auth_token)