sticker-convert 2.12.4__py3-none-any.whl → 2.13.1.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 (37) hide show
  1. sticker_convert/cli.py +3 -0
  2. sticker_convert/converter.py +61 -58
  3. sticker_convert/downloaders/download_band.py +110 -0
  4. sticker_convert/downloaders/download_kakao.py +84 -22
  5. sticker_convert/downloaders/download_line.py +8 -4
  6. sticker_convert/gui.py +6 -3
  7. sticker_convert/gui_components/windows/advanced_compression_window.py +1 -1
  8. sticker_convert/gui_components/windows/discord_get_auth_window.py +3 -3
  9. sticker_convert/gui_components/windows/kakao_get_auth_window.py +25 -4
  10. sticker_convert/gui_components/windows/signal_get_auth_window.py +3 -3
  11. sticker_convert/gui_components/windows/viber_get_auth_window.py +16 -1
  12. sticker_convert/job.py +6 -0
  13. sticker_convert/resources/compression.json +47 -0
  14. sticker_convert/resources/help.json +1 -1
  15. sticker_convert/resources/input.json +10 -0
  16. sticker_convert/resources/memdump_linux.sh +0 -1
  17. sticker_convert/utils/auth/get_discord_auth.py +2 -2
  18. sticker_convert/utils/auth/get_kakao_desktop_auth.py +38 -43
  19. sticker_convert/utils/auth/get_signal_auth.py +2 -2
  20. sticker_convert/utils/auth/get_viber_auth.py +3 -5
  21. sticker_convert/utils/auth/telegram_api.py +3 -1
  22. sticker_convert/utils/auth/telethon_setup.py +21 -8
  23. sticker_convert/utils/chrome_remotedebug.py +27 -29
  24. sticker_convert/utils/chromiums/linux.py +52 -0
  25. sticker_convert/utils/chromiums/osx.py +68 -0
  26. sticker_convert/utils/chromiums/windows.py +45 -0
  27. sticker_convert/utils/media/codec_info.py +1 -1
  28. sticker_convert/utils/process.py +152 -108
  29. sticker_convert/utils/singletons.py +18 -0
  30. sticker_convert/utils/url_detect.py +3 -0
  31. sticker_convert/version.py +1 -1
  32. {sticker_convert-2.12.4.dist-info → sticker_convert-2.13.1.0.dist-info}/METADATA +37 -29
  33. {sticker_convert-2.12.4.dist-info → sticker_convert-2.13.1.0.dist-info}/RECORD +37 -32
  34. {sticker_convert-2.12.4.dist-info → sticker_convert-2.13.1.0.dist-info}/WHEEL +1 -1
  35. {sticker_convert-2.12.4.dist-info → sticker_convert-2.13.1.0.dist-info}/entry_points.txt +0 -0
  36. {sticker_convert-2.12.4.dist-info → sticker_convert-2.13.1.0.dist-info}/licenses/LICENSE +0 -0
  37. {sticker_convert-2.12.4.dist-info → sticker_convert-2.13.1.0.dist-info}/top_level.txt +0 -0
sticker_convert/cli.py CHANGED
@@ -232,6 +232,7 @@ class CLI:
232
232
  "telegram": args.download_telegram,
233
233
  "telegram_telethon": args.download_telegram_telethon,
234
234
  "kakao": args.download_kakao,
235
+ "band": args.download_band,
235
236
  "viber": args.download_viber,
236
237
  "discord": args.download_discord,
237
238
  "discord_emoji": args.download_discord_emoji,
@@ -550,6 +551,8 @@ class CLI:
550
551
  opt_cred.telethon_api_hash = telethon_api_hash
551
552
 
552
553
  self.cb.msg("Telethon setup successful")
554
+ else:
555
+ self.cb.msg("Telethon setup failed")
553
556
 
554
557
  if args.line_get_auth:
555
558
  get_line_auth = GetLineAuth()
@@ -19,6 +19,7 @@ from sticker_convert.utils.chrome_remotedebug import CRD
19
19
  from sticker_convert.utils.files.cache_store import CacheStore
20
20
  from sticker_convert.utils.media.codec_info import CodecInfo, rounding
21
21
  from sticker_convert.utils.media.format_verify import FormatVerify
22
+ from sticker_convert.utils.singletons import singletons
22
23
 
23
24
  if TYPE_CHECKING:
24
25
  from av.video.frame import VideoFrame
@@ -435,26 +436,30 @@ class StickerConvert:
435
436
  width = self.codec_info_orig.res[0]
436
437
  height = self.codec_info_orig.res[1]
437
438
 
438
- chrome_path: Optional[str]
439
- if self.opt_comp.chromium_path:
440
- chrome_path = self.opt_comp.chromium_path
441
- else:
442
- chrome_path = CRD.get_chrome_path()
443
- args = [
444
- "--headless",
445
- "--kiosk",
446
- "--disable-extensions",
447
- "--disable-infobars",
448
- "--disable-gpu",
449
- "--disable-gpu-rasterization",
450
- "--hide-scrollbars",
451
- f"--window-size={width + 200},{height + 200}",
452
- "about:blank",
453
- ]
454
- if chrome_path is None:
455
- raise RuntimeError("[F] Chrome/Chromium required for importing svg")
456
- self.cb.put("[W] Importing SVG takes long time")
457
-
439
+ if singletons.objs.get("crd") is None:
440
+ chrome_path: Optional[str]
441
+ if self.opt_comp.chromium_path:
442
+ chrome_path = self.opt_comp.chromium_path
443
+ else:
444
+ chrome_path = CRD.get_chromium_path()
445
+ args = [
446
+ "--headless",
447
+ "--kiosk",
448
+ "--disable-extensions",
449
+ "--disable-infobars",
450
+ "--disable-gpu",
451
+ "--disable-gpu-rasterization",
452
+ "--hide-scrollbars",
453
+ "--force-device-scale-factor=1",
454
+ "about:blank",
455
+ ]
456
+ if chrome_path is None:
457
+ raise RuntimeError("[F] Chrome/Chromium required for importing svg")
458
+ self.cb.put("[W] Importing SVG takes long time")
459
+ singletons.objs["crd"] = CRD(chrome_path, args=args)
460
+ singletons.objs["crd"].connect(-1) # type: ignore
461
+
462
+ crd = cast(CRD, singletons.objs["crd"])
458
463
  if isinstance(self.in_f, bytes):
459
464
  svg = self.in_f.decode()
460
465
  else:
@@ -469,39 +474,35 @@ class StickerConvert:
469
474
  svg_tag["height"] = height
470
475
  svg = str(soup)
471
476
 
472
- crd = None
473
- try:
474
- crd = CRD(chrome_path, args=args)
475
- crd.connect(-1)
476
- crd.open_html_str(svg)
477
- crd.set_transparent_bg()
478
- crd.exec_js('svg = document.getElementsByTagName("svg")[0]')
479
- x = json.loads(crd.exec_js("svg.getBoundingClientRect().x"))["result"][
480
- "result"
481
- ]["value"]
482
- y = json.loads(crd.exec_js("svg.getBoundingClientRect().y"))["result"][
483
- "result"
484
- ]["value"]
485
- clip = {"x": x, "y": y, "width": width, "height": height, "scale": 1}
486
-
487
- if self.codec_info_orig.fps > 0:
488
- crd.exec_js("svg.pauseAnimations()")
489
- for i in range(self.codec_info_orig.frames):
490
- curr_time = (
491
- i
492
- / self.codec_info_orig.frames
493
- * self.codec_info_orig.duration
494
- / 1000
495
- )
496
- crd.exec_js(f"svg.setCurrentTime({curr_time})")
497
- self.frames_raw.append(
498
- np.asarray(crd.screenshot(clip).convert("RGBA"))
499
- )
500
- else:
501
- self.frames_raw.append(np.asarray(crd.screenshot(clip).convert("RGBA")))
502
- finally:
503
- if crd is not None:
504
- crd.close()
477
+ crd.open_html_str(svg)
478
+ crd.set_transparent_bg()
479
+ init_js = 'svg = document.getElementsByTagName("svg")[0];'
480
+ if self.codec_info_orig.fps > 0:
481
+ init_js += "svg.pauseAnimations();"
482
+ init_js += "JSON.stringify(svg.getBoundingClientRect());"
483
+ bound = json.loads(
484
+ json.loads(crd.exec_js(init_js))["result"]["result"]["value"]
485
+ )
486
+ clip = {
487
+ "x": bound["x"],
488
+ "y": bound["y"],
489
+ "width": width,
490
+ "height": height,
491
+ "scale": 1,
492
+ }
493
+
494
+ if self.codec_info_orig.fps > 0:
495
+ for i in range(self.codec_info_orig.frames):
496
+ curr_time = (
497
+ i
498
+ / self.codec_info_orig.frames
499
+ * self.codec_info_orig.duration
500
+ / 1000
501
+ )
502
+ crd.exec_js(f"svg.setCurrentTime({curr_time})")
503
+ self.frames_raw.append(np.asarray(crd.screenshot(clip)))
504
+ else:
505
+ self.frames_raw.append(np.asarray(crd.screenshot(clip)))
505
506
 
506
507
  def _frames_import_pillow(self) -> None:
507
508
  with Image.open(self.in_f) as im:
@@ -563,7 +564,7 @@ class StickerConvert:
563
564
  container = cast(InputContainer, container)
564
565
  context = container.streams.video[0].codec_context
565
566
  if context.name == "vp8":
566
- context = cast(VideoCodecContext, CodecContext.create("libvpx", "r"))
567
+ context = CodecContext.create("libvpx", "r")
567
568
  elif context.name == "vp9":
568
569
  context = cast(
569
570
  VideoCodecContext, CodecContext.create("libvpx-vp9", "r")
@@ -596,7 +597,12 @@ class StickerConvert:
596
597
  else:
597
598
  frame_resized = frame
598
599
 
599
- if frame_resized.format.name == "yuv420p":
600
+ # yuva420p may cause crash for pyav < 14
601
+ # Not safe to directly call frame.to_ndarray(format="rgba")
602
+ # https://github.com/PyAV-Org/PyAV/discussions/1510
603
+ if int(av.__version__.split(".")[0]) >= 14:
604
+ rgba_array = frame_resized.to_ndarray(format="rgba")
605
+ elif frame_resized.format.name == "yuv420p":
600
606
  rgb_array = frame_resized.to_ndarray(format="rgb24")
601
607
  rgba_array = np.dstack(
602
608
  (
@@ -608,9 +614,6 @@ class StickerConvert:
608
614
  )
609
615
  )
610
616
  else:
611
- # yuva420p may cause crash
612
- # Not safe to directly call frame.to_ndarray(format="rgba")
613
- # https://github.com/laggykiller/sticker-convert/issues/114
614
617
  frame_resized = frame_resized.reformat(
615
618
  format="yuva420p",
616
619
  dst_colorspace=1,
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/env python3
2
+ from __future__ import annotations
3
+
4
+ import json
5
+ import zipfile
6
+ from io import BytesIO
7
+ from pathlib import Path
8
+ from typing import Any, Dict, Optional, Tuple
9
+ from urllib.parse import urlparse
10
+
11
+ import requests
12
+
13
+ from sticker_convert.downloaders.download_base import DownloadBase
14
+ from sticker_convert.job_option import CredOption, InputOption
15
+ from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
16
+ from sticker_convert.utils.files.metadata_handler import MetadataHandler
17
+
18
+
19
+ class DownloadBand(DownloadBase):
20
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
21
+ super().__init__(*args, **kwargs)
22
+
23
+ def decompress(self, zip_file: bytes) -> int:
24
+ with zipfile.ZipFile(BytesIO(zip_file)) as zf:
25
+ self.cb.put("Unzipping...")
26
+
27
+ zf_files = zf.namelist()
28
+ animated = [i for i in zf_files if "animation/" in i]
29
+ if len(animated) > 0:
30
+ pack_files = animated
31
+ else:
32
+ pack_files = [
33
+ i
34
+ for i in zf_files
35
+ if i.endswith(".meta") is False and "_key" not in i
36
+ ]
37
+
38
+ self.cb.put(
39
+ (
40
+ "bar",
41
+ None,
42
+ {"set_progress_mode": "determinate", "steps": len(pack_files)},
43
+ )
44
+ )
45
+
46
+ for num, sticker in enumerate(pack_files):
47
+ data = zf.read(sticker)
48
+ self.cb.put(f"Read {sticker}")
49
+ ext = sticker.split(".")[-1]
50
+
51
+ out_path = Path(self.out_dir, str(num).zfill(3) + f".{ext}")
52
+ with open(out_path, "wb") as f:
53
+ f.write(data)
54
+
55
+ self.cb.put("update_bar")
56
+
57
+ return len(pack_files)
58
+
59
+ def get_metadata(self, pack_no: str) -> Optional[Dict[Any, Any]]:
60
+ r = requests.get(
61
+ f"https://sapi.band.us/v1.0.0/get_sticker_info?pack_no={pack_no}"
62
+ )
63
+ if r.text:
64
+ return json.loads(r.text)
65
+ else:
66
+ return None
67
+
68
+ def download_stickers_band(self) -> Tuple[int, int]:
69
+ if urlparse(self.url).netloc != "www.band.us" and self.url.isnumeric() is False:
70
+ self.cb.put("Download failed: Unsupported URL format")
71
+ return 0, 0
72
+
73
+ if self.url.isnumeric():
74
+ pack_no = self.url
75
+ else:
76
+ pack_no = urlparse(self.url).path.split("/")[-1]
77
+ metadata = self.get_metadata(pack_no)
78
+ if metadata:
79
+ self.title = metadata["result_data"]["sticker"]["name"]
80
+ else:
81
+ self.cb.put("Download failed: Failed to get metadata")
82
+ return 0, 0
83
+
84
+ MetadataHandler.set_metadata(self.out_dir, title=self.title)
85
+
86
+ pack_url = f"http://s.cmstatic.net/band/sticker/v2/{pack_no}/shop/pack"
87
+ zip_file = self.download_file(pack_url)
88
+
89
+ if zip_file:
90
+ self.cb.put(f"Downloaded {pack_url}")
91
+ else:
92
+ self.cb.put(f"Cannot download {pack_url}")
93
+ return 0, 0
94
+
95
+ pack_files_no = self.decompress(zip_file)
96
+
97
+ cover_url = f"http://s.cmstatic.net/band/sticker/v2/{pack_no}/shop/main"
98
+ self.download_file(cover_url, self.out_dir / "cover.png")
99
+
100
+ return pack_files_no, pack_files_no
101
+
102
+ @staticmethod
103
+ def start(
104
+ opt_input: InputOption,
105
+ opt_cred: Optional[CredOption],
106
+ cb: CallbackProtocol,
107
+ cb_return: CallbackReturn,
108
+ ) -> Tuple[int, int]:
109
+ downloader = DownloadBand(opt_input, opt_cred, cb, cb_return)
110
+ return downloader.download_stickers_band()
@@ -4,7 +4,7 @@ from __future__ import annotations
4
4
  import itertools
5
5
  import json
6
6
  from pathlib import Path
7
- from typing import Any, List, Optional, Tuple
7
+ from typing import Any, Dict, List, Optional, Tuple
8
8
  from urllib.parse import urlparse
9
9
 
10
10
  import requests
@@ -17,6 +17,13 @@ from sticker_convert.utils.media.decrypt_kakao import DecryptKakao
17
17
 
18
18
 
19
19
  class MetadataKakao:
20
+ @staticmethod
21
+ def share_link_to_public_link(share_link: str) -> str:
22
+ # Share link redirect to preview link if use desktop headers
23
+ headers_desktop = {"User-Agent": "Chrome"}
24
+ r = requests.get(share_link, headers=headers_desktop, allow_redirects=True)
25
+ return r.url
26
+
20
27
  @staticmethod
21
28
  def get_item_code_from_hash(hash: str, auth_token: str) -> Optional[str]:
22
29
  headers = {
@@ -40,12 +47,14 @@ class MetadataKakao:
40
47
  return item_code
41
48
 
42
49
  @staticmethod
43
- def get_item_code_from_title(title_ko: str, auth_token: str) -> Optional[str]:
50
+ def get_item_code_from_search(
51
+ pack_title: str, search_term: str, by_author: bool, auth_token: str
52
+ ) -> str:
44
53
  headers = {
45
54
  "Authorization": auth_token,
46
55
  }
47
56
 
48
- data = {"query": title_ko}
57
+ data = {"query": search_term}
49
58
 
50
59
  response = requests.post(
51
60
  "https://talk-pilsner.kakao.com/emoticon/item_store/instant_search",
@@ -54,12 +63,53 @@ class MetadataKakao:
54
63
  )
55
64
 
56
65
  if response.status_code != 200:
57
- return None
66
+ return "auth_error"
67
+
68
+ def check_pack_match(pack_info: Dict[str, Any]) -> bool:
69
+ share_link = pack_info["itemMetaInfo"]["shareData"]["linkUrl"]
70
+ public_url = MetadataKakao.share_link_to_public_link(share_link)
71
+ if pack_title == urlparse(public_url).path.split("/")[-1]:
72
+ return True
73
+ return False
58
74
 
59
75
  response_json = json.loads(response.text)
60
- item_code = response_json["emoticons"][0]["item_code"]
76
+ for emoticon in response_json["emoticons"]:
77
+ item_code = emoticon["item_code"]
78
+ pack_info = MetadataKakao.get_pack_info_authed(item_code, auth_token)
79
+ if pack_info is None:
80
+ continue
81
+ if check_pack_match(pack_info):
82
+ return item_code
83
+ if by_author:
84
+ cid = pack_info["itemMetaInfo"]["itemMetaData"]["cid"]
85
+ for item_code in MetadataKakao.get_items_by_creator(cid, auth_token):
86
+ pack_info = MetadataKakao.get_pack_info_authed(
87
+ item_code, auth_token
88
+ )
89
+ if pack_info is None:
90
+ continue
91
+ if check_pack_match(pack_info):
92
+ return item_code
61
93
 
62
- return item_code
94
+ return "code_not_found"
95
+
96
+ @staticmethod
97
+ def get_items_by_creator(cid: str, auth_token: str) -> List[str]:
98
+ headers = {"Authorization": auth_token}
99
+
100
+ params = {
101
+ "itemSort": "NEW",
102
+ "offset": "0",
103
+ "size": "30",
104
+ }
105
+
106
+ response = requests.get(
107
+ f"https://talk-pilsner.kakao.com/emoticon/api/store/v3/creators/{cid}",
108
+ headers=headers,
109
+ params=params,
110
+ )
111
+
112
+ return [i["item_id"] for i in json.loads(response.text)["items"]]
63
113
 
64
114
  @staticmethod
65
115
  def get_pack_info_unauthed(
@@ -119,13 +169,8 @@ class DownloadKakao(DownloadBase):
119
169
  hash = urlparse(self.url).path.split("/")[-1]
120
170
  item_code = MetadataKakao.get_item_code_from_hash(hash, self.auth_token)
121
171
 
122
- # Share link redirect to preview link if use desktop headers
123
- # This allows us to find pack author
124
- headers_desktop = {"User-Agent": "Chrome"}
125
-
126
- r = requests.get(self.url, headers=headers_desktop, allow_redirects=True)
127
-
128
- self.pack_title = urlparse(r.url).path.split("/")[-1]
172
+ public_url = MetadataKakao.share_link_to_public_link(self.url)
173
+ self.pack_title = urlparse(public_url).path.split("/")[-1]
129
174
  pack_info_unauthed = MetadataKakao.get_pack_info_unauthed(self.pack_title)
130
175
  if pack_info_unauthed is None:
131
176
  self.cb.put(
@@ -184,14 +229,33 @@ class DownloadKakao(DownloadBase):
184
229
  thumbnail_urls = self.pack_info_unauthed["result"]["thumbnailUrls"]
185
230
 
186
231
  if self.auth_token:
187
- item_code = MetadataKakao.get_item_code_from_title(
188
- title_ko, self.auth_token
232
+ item_code = MetadataKakao.get_item_code_from_search(
233
+ self.pack_title, title_ko, False, self.auth_token
189
234
  )
190
- if item_code:
235
+ if item_code == "auth_error":
236
+ msg = "Warning: Cannot get item code.\n"
237
+ msg += "Is auth_token invalid / expired? Try to regenerate it.\n"
238
+ msg += "Continue to download static stickers instead?"
239
+ elif item_code == "code_not_found":
240
+ self.cb.put(
241
+ "Cannot get item code, trying to search by author name, this may take long time..."
242
+ )
243
+ self.cb.put(
244
+ "Hint: Use share link instead to download more reliably"
245
+ )
246
+ if self.author is not None:
247
+ item_code = MetadataKakao.get_item_code_from_search(
248
+ self.pack_title, self.author, True, self.auth_token
249
+ )
250
+ if item_code == "code_not_found":
251
+ msg = "Warning: Cannot get item code.\n"
252
+ msg += "Please use share link instead.\n"
253
+ msg += "Continue to download static stickers instead?"
254
+ else:
255
+ return self.download_animated(item_code)
256
+ else:
191
257
  return self.download_animated(item_code)
192
- msg = "Warning: Cannot get item code.\n"
193
- msg += "Is auth_token invalid / expired? Try to regenerate it.\n"
194
- msg += "Continue to download static stickers instead?"
258
+
195
259
  self.cb.put(("ask_bool", (msg,), None))
196
260
  if self.cb_return:
197
261
  response = self.cb_return.get_response()
@@ -249,9 +313,7 @@ class DownloadKakao(DownloadBase):
249
313
  if not self.pack_info_unauthed:
250
314
  public_url = None
251
315
  if urlparse(self.url).netloc == "emoticon.kakao.com":
252
- r = requests.get(self.url)
253
- # Share url would redirect to public url without headers
254
- public_url = r.url
316
+ public_url = MetadataKakao.share_link_to_public_link(self.url)
255
317
  elif urlparse(self.url).netloc == "e.kakao.com":
256
318
  public_url = self.url
257
319
  if public_url:
@@ -77,7 +77,7 @@ class MetadataLine:
77
77
  @staticmethod
78
78
  def get_metadata_sticon(
79
79
  pack_id: str, region: str
80
- ) -> Optional[Tuple[str, str, List[Dict[str, Any]], str, bool]]:
80
+ ) -> Optional[Tuple[str, str, List[Dict[str, Any]], str, bool, bool]]:
81
81
  pack_meta_r = requests.get(
82
82
  f"https://stickershop.line-scdn.net/sticonshop/v1/{pack_id}/sticon/iphone/meta.json"
83
83
  )
@@ -114,14 +114,15 @@ class MetadataLine:
114
114
  files = pack_meta["orders"]
115
115
 
116
116
  resource_type = pack_meta.get("sticonResourceType")
117
+ has_animation = True if resource_type == "ANIMATION" else False
117
118
  has_sound = False
118
119
 
119
- return title, author, files, resource_type, has_sound
120
+ return title, author, files, resource_type, has_animation, has_sound
120
121
 
121
122
  @staticmethod
122
123
  def get_metadata_stickers(
123
124
  pack_id: str, region: str
124
- ) -> Optional[Tuple[str, str, List[Dict[str, Any]], str, bool]]:
125
+ ) -> Optional[Tuple[str, str, List[Dict[str, Any]], str, bool, bool]]:
125
126
  pack_meta_r = requests.get(
126
127
  f"https://stickershop.line-scdn.net/stickershop/v1/product/{pack_id}/android/productInfo.meta"
127
128
  )
@@ -153,9 +154,10 @@ class MetadataLine:
153
154
  files = pack_meta["stickers"]
154
155
 
155
156
  resource_type = pack_meta.get("stickerResourceType")
157
+ has_animation = pack_meta.get("hasAnimation")
156
158
  has_sound = pack_meta.get("hasSound")
157
159
 
158
- return title, author, files, resource_type, has_sound
160
+ return title, author, files, resource_type, has_animation, has_sound
159
161
 
160
162
 
161
163
  class DownloadLine(DownloadBase):
@@ -207,6 +209,7 @@ class DownloadLine(DownloadBase):
207
209
  if (
208
210
  self.resource_type in ("ANIMATION", "ANIMATION_SOUND", "POPUP")
209
211
  or self.has_sound is True
212
+ or self.has_animation is True
210
213
  ):
211
214
  pack_url = f"https://stickershop.line-scdn.net/stickershop/v1/product/{self.pack_id}/iphone/stickerpack@2x.zip"
212
215
  elif self.resource_type == "PER_STICKER_TEXT":
@@ -419,6 +422,7 @@ class DownloadLine(DownloadBase):
419
422
  self.author,
420
423
  self.pack_files,
421
424
  self.resource_type,
425
+ self.has_animation,
422
426
  self.has_sound,
423
427
  ) = metadata
424
428
  else:
sticker_convert/gui.py CHANGED
@@ -714,9 +714,9 @@ class GUI(Window):
714
714
  set_progress_mode, steps, update_bar, *args, **kwargs
715
715
  )
716
716
 
717
- def highlight_fields(self):
717
+ def highlight_fields(self) -> bool:
718
718
  if not self.init_done:
719
- return
719
+ return True
720
720
 
721
721
  input_option = self.get_input_name()
722
722
  input_option_display = self.get_input_display_name()
@@ -762,7 +762,8 @@ class GUI(Window):
762
762
  download_option is None
763
763
  or input_option.startswith(download_option) is False
764
764
  and not (
765
- input_option in ("kakao", "line", "discord", "discord_emoji")
765
+ input_option
766
+ in ("kakao", "band", "line", "discord", "discord_emoji")
766
767
  and url.isnumeric()
767
768
  )
768
769
  ):
@@ -866,3 +867,5 @@ class GUI(Window):
866
867
  else:
867
868
  self.comp_frame.comp_preset_opt.config(bootstyle="secondary") # type: ignore
868
869
  self.output_frame.output_option_opt.config(bootstyle="secondary") # type: ignore
870
+
871
+ return True
@@ -609,7 +609,7 @@ class AdvancedCompressionWindow(BaseWindow):
609
609
  )[1]
610
610
  if color:
611
611
  self.gui.bg_color_var.set(color.replace("#", "") + "00")
612
- self.lift()
612
+ self.lift() # type: ignore
613
613
  self.attributes("-topmost", True) # type: ignore
614
614
  self.attributes("-topmost", False) # type: ignore
615
615
 
@@ -11,7 +11,7 @@ from sticker_convert.utils.auth.get_discord_auth import GetDiscordAuth
11
11
 
12
12
 
13
13
  class DiscordGetAuthWindow(BaseWindow):
14
- def __init__(self, *args: Any, **kwargs: Any):
14
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
15
15
  super(DiscordGetAuthWindow, self).__init__(*args, **kwargs)
16
16
 
17
17
  self.title("Get Discord token")
@@ -64,10 +64,10 @@ class DiscordGetAuthWindow(BaseWindow):
64
64
 
65
65
  GUIUtils.finalize_window(self)
66
66
 
67
- def cb_login(self):
67
+ def cb_login(self) -> None:
68
68
  Thread(target=self.cb_login_thread, daemon=True).start()
69
69
 
70
- def cb_login_thread(self, *args: Any):
70
+ def cb_login_thread(self, *args: Any) -> None:
71
71
  m = GetDiscordAuth(cb_msg=self.gui.cb_msg)
72
72
  discord_token, msg = m.get_cred()
73
73
  if discord_token:
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env python3
2
+ import platform
2
3
  from functools import partial
3
4
  from threading import Thread
4
5
  from typing import Any, Optional
@@ -51,6 +52,20 @@ class KakaoGetAuthWindow(BaseWindow):
51
52
  justify="left",
52
53
  anchor="w",
53
54
  )
55
+ if platform.system() != "Darwin":
56
+ self.explanation1_4_lbl = Label(
57
+ self.frame_from_desktop,
58
+ text="Note: This will download ProcDump and read memory of KakaoTalk Desktop",
59
+ justify="left",
60
+ anchor="w",
61
+ )
62
+ else:
63
+ self.explanation1_4_lbl = Label(
64
+ self.frame_from_desktop,
65
+ text="Note: This will read memory of KakaoTalk Desktop",
66
+ justify="left",
67
+ anchor="w",
68
+ )
54
69
  self.kakao_bin_path_lbl = Label(
55
70
  self.frame_from_desktop,
56
71
  text="Kakao app path (Optional):",
@@ -85,10 +100,13 @@ class KakaoGetAuthWindow(BaseWindow):
85
100
  self.explanation1_3_lbl.grid(
86
101
  column=0, row=2, columnspan=2, sticky="w", padx=3, pady=3
87
102
  )
88
- self.kakao_bin_path_lbl.grid(column=0, row=3, sticky="w", padx=3, pady=3)
89
- self.kakao_bin_path_entry.grid(column=1, row=3, sticky="w", padx=3, pady=3)
90
- self.launch_desktop_btn.grid(column=0, row=4, columnspan=2, padx=3, pady=3)
91
- self.get_auth_desktop_btn.grid(column=0, row=5, columnspan=2, padx=3, pady=3)
103
+ self.explanation1_4_lbl.grid(
104
+ column=0, row=3, columnspan=2, sticky="w", padx=3, pady=3
105
+ )
106
+ self.kakao_bin_path_lbl.grid(column=0, row=4, sticky="w", padx=3, pady=3)
107
+ self.kakao_bin_path_entry.grid(column=1, row=4, sticky="w", padx=3, pady=3)
108
+ self.launch_desktop_btn.grid(column=0, row=5, columnspan=2, padx=3, pady=3)
109
+ self.get_auth_desktop_btn.grid(column=0, row=6, columnspan=2, padx=3, pady=3)
92
110
 
93
111
  # Method 2 frame
94
112
  self.explanation2_1_lbl = Label(
@@ -277,6 +295,8 @@ class KakaoGetAuthWindow(BaseWindow):
277
295
 
278
296
  def cb_from_desktop_thread(self, *_: Any) -> None:
279
297
  self.gui.save_creds()
298
+ self.gui.cb_msg("Getting auth_token, this may take a minute...")
299
+ self.gui.cb_bar("indeterminate")
280
300
  m = GetKakaoDesktopAuth(
281
301
  cb_ask_str=self.cb_ask_str_kakao,
282
302
  )
@@ -298,3 +318,4 @@ class KakaoGetAuthWindow(BaseWindow):
298
318
  self.gui.highlight_fields()
299
319
 
300
320
  self.cb_msg_block_kakao(msg)
321
+ self.gui.cb_bar("clear")
@@ -11,7 +11,7 @@ from sticker_convert.utils.auth.get_signal_auth import GetSignalAuth
11
11
 
12
12
 
13
13
  class SignalGetAuthWindow(BaseWindow):
14
- def __init__(self, *args: Any, **kwargs: Any):
14
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
15
15
  super(SignalGetAuthWindow, self).__init__(*args, **kwargs)
16
16
 
17
17
  self.title("Get Signal uuid and password")
@@ -64,10 +64,10 @@ class SignalGetAuthWindow(BaseWindow):
64
64
 
65
65
  GUIUtils.finalize_window(self)
66
66
 
67
- def cb_login(self):
67
+ def cb_login(self) -> None:
68
68
  Thread(target=self.cb_login_thread, daemon=True).start()
69
69
 
70
- def cb_login_thread(self, *args: Any):
70
+ def cb_login_thread(self, *args: Any) -> None:
71
71
  m = GetSignalAuth(cb_msg=self.gui.cb_msg, cb_ask_str=self.cb_ask_str_signal)
72
72
 
73
73
  uuid, password = m.get_cred()