sticker-convert 2.12.4__py3-none-any.whl → 2.13.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 (28) hide show
  1. sticker_convert/cli.py +1 -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/gui.py +6 -3
  6. sticker_convert/gui_components/windows/discord_get_auth_window.py +3 -3
  7. sticker_convert/gui_components/windows/signal_get_auth_window.py +3 -3
  8. sticker_convert/gui_components/windows/viber_get_auth_window.py +1 -1
  9. sticker_convert/job.py +6 -0
  10. sticker_convert/resources/compression.json +47 -0
  11. sticker_convert/resources/input.json +10 -0
  12. sticker_convert/resources/memdump_linux.sh +0 -1
  13. sticker_convert/utils/auth/get_discord_auth.py +1 -1
  14. sticker_convert/utils/auth/get_kakao_desktop_auth.py +2 -2
  15. sticker_convert/utils/auth/get_signal_auth.py +2 -2
  16. sticker_convert/utils/auth/get_viber_auth.py +1 -1
  17. sticker_convert/utils/auth/telethon_setup.py +3 -1
  18. sticker_convert/utils/chrome_remotedebug.py +25 -13
  19. sticker_convert/utils/media/codec_info.py +1 -1
  20. sticker_convert/utils/singletons.py +18 -0
  21. sticker_convert/utils/url_detect.py +3 -0
  22. sticker_convert/version.py +1 -1
  23. {sticker_convert-2.12.4.dist-info → sticker_convert-2.13.0.dist-info}/METADATA +32 -24
  24. {sticker_convert-2.12.4.dist-info → sticker_convert-2.13.0.dist-info}/RECORD +28 -26
  25. {sticker_convert-2.12.4.dist-info → sticker_convert-2.13.0.dist-info}/WHEEL +1 -1
  26. {sticker_convert-2.12.4.dist-info → sticker_convert-2.13.0.dist-info}/entry_points.txt +0 -0
  27. {sticker_convert-2.12.4.dist-info → sticker_convert-2.13.0.dist-info}/licenses/LICENSE +0 -0
  28. {sticker_convert-2.12.4.dist-info → sticker_convert-2.13.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,
@@ -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_chrome_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:
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
@@ -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:
@@ -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()
@@ -109,7 +109,7 @@ class ViberGetAuthWindow(BaseWindow):
109
109
 
110
110
  GUIUtils.finalize_window(self)
111
111
 
112
- def cb_get_cred(self):
112
+ def cb_get_cred(self) -> None:
113
113
  Thread(target=self.cb_get_cred_thread, daemon=True).start()
114
114
 
115
115
  def cb_get_cred_thread(self) -> None:
sticker_convert/job.py CHANGED
@@ -12,6 +12,7 @@ from typing import Any, Callable, Dict, List, Optional, Tuple
12
12
  from urllib.parse import urlparse
13
13
 
14
14
  from sticker_convert.converter import StickerConvert
15
+ from sticker_convert.downloaders.download_band import DownloadBand
15
16
  from sticker_convert.downloaders.download_discord import DownloadDiscord
16
17
  from sticker_convert.downloaders.download_kakao import DownloadKakao
17
18
  from sticker_convert.downloaders.download_line import DownloadLine
@@ -28,6 +29,7 @@ from sticker_convert.utils.callback import CallbackReturn, CbQueueType, ResultsL
28
29
  from sticker_convert.utils.files.json_resources_loader import OUTPUT_JSON
29
30
  from sticker_convert.utils.files.metadata_handler import MetadataHandler
30
31
  from sticker_convert.utils.media.codec_info import CodecInfo
32
+ from sticker_convert.utils.singletons import singletons
31
33
 
32
34
 
33
35
  class Executor:
@@ -136,6 +138,7 @@ class Executor:
136
138
 
137
139
  work_queue.put(None)
138
140
  cb_queue.put("__PROCESS_DONE__")
141
+ singletons.close()
139
142
 
140
143
  def start_workers(self, processes: int = 1) -> None:
141
144
  self.cb_thread_instance = Thread(
@@ -564,6 +567,9 @@ class Job:
564
567
  if self.opt_input.option == "kakao":
565
568
  downloaders.append(DownloadKakao.start)
566
569
 
570
+ if self.opt_input.option == "band":
571
+ downloaders.append(DownloadBand.start)
572
+
567
573
  if self.opt_input.option == "viber":
568
574
  downloaders.append(DownloadViber.start)
569
575
 
@@ -328,6 +328,53 @@
328
328
  "quantize_method": "imagequant",
329
329
  "default_emoji": "😀"
330
330
  },
331
+ "band": {
332
+ "size_max": {
333
+ "img": 0,
334
+ "vid": 0
335
+ },
336
+ "format": {
337
+ "img": ".png",
338
+ "vid": ".png"
339
+ },
340
+ "fps": {
341
+ "min": 1,
342
+ "max": 30,
343
+ "power": -0.5
344
+ },
345
+ "res": {
346
+ "w": {
347
+ "min": 100,
348
+ "max": 370
349
+ },
350
+ "h": {
351
+ "min": 100,
352
+ "max": 320
353
+ },
354
+ "power": 3
355
+ },
356
+ "quality": {
357
+ "min": 10,
358
+ "max": 95,
359
+ "power": 5
360
+ },
361
+ "color": {
362
+ "min": 32,
363
+ "max": 257,
364
+ "power": 3
365
+ },
366
+ "duration": {
367
+ "min": 83,
368
+ "max": 4000
369
+ },
370
+ "padding_percent": 0,
371
+ "bg_color": "",
372
+ "steps": 16,
373
+ "fake_vid": false,
374
+ "scale_filter": "bicubic",
375
+ "quantize_method": "imagequant",
376
+ "default_emoji": "😀"
377
+ },
331
378
  "viber": {
332
379
  "size_max": {
333
380
  "img": 0,
@@ -59,6 +59,16 @@
59
59
  "author": true
60
60
  }
61
61
  },
62
+ "band": {
63
+ "full_name": "Download from Naver Band",
64
+ "help": "Download Naver Band stickers from a URL / ID as input",
65
+ "example": "Example: https://www.band.us/sticker/xxxx OR 2535",
66
+ "address_lbls": "URL address / ID",
67
+ "metadata_provides": {
68
+ "title": true,
69
+ "author": false
70
+ }
71
+ },
62
72
  "viber": {
63
73
  "full_name": "Download from Viber",
64
74
  "help": "Download viber stickers from a URL as input",
@@ -7,7 +7,6 @@ PID=$1
7
7
  PID_MAPS=/proc/$PID/maps
8
8
  PID_MEM=/proc/$PID/mem
9
9
 
10
- rm -f /tmp/viber.dmp.$PID
11
10
  grep rw-p $PID_MAPS |
12
11
  while IFS='' read -r line || [[ -n "$line" ]]; do
13
12
  range=`echo $line | awk '{print $1;}'`
@@ -13,7 +13,7 @@ from sticker_convert.utils.process import killall
13
13
 
14
14
 
15
15
  class GetDiscordAuth:
16
- def __init__(self, cb_msg: Callable[..., None] = print):
16
+ def __init__(self, cb_msg: Callable[..., None] = print) -> None:
17
17
  chromedriver_download_dir = CONFIG_DIR / "bin"
18
18
  os.makedirs(chromedriver_download_dir, exist_ok=True)
19
19
 
@@ -28,10 +28,10 @@ MSG_PERMISSION_ERROR = "Failed to read Kakao process memory"
28
28
 
29
29
 
30
30
  class GetKakaoDesktopAuth:
31
- def __init__(self, cb_ask_str: Callable[..., str] = input):
31
+ def __init__(self, cb_ask_str: Callable[..., str] = input) -> None:
32
32
  self.cb_ask_str = cb_ask_str
33
33
 
34
- def launch_kakao(self, kakao_bin_path: str):
34
+ def launch_kakao(self, kakao_bin_path: str) -> None:
35
35
  if platform.system() == "Windows":
36
36
  subprocess.Popen([kakao_bin_path])
37
37
  elif platform.system() == "Darwin":
@@ -17,7 +17,7 @@ class GetSignalAuth:
17
17
  self,
18
18
  cb_msg: Callable[..., None] = print,
19
19
  cb_ask_str: Callable[..., str] = input,
20
- ):
20
+ ) -> None:
21
21
  chromedriver_download_dir = CONFIG_DIR / "bin"
22
22
  os.makedirs(chromedriver_download_dir, exist_ok=True)
23
23
 
@@ -26,7 +26,7 @@ class GetSignalAuth:
26
26
  self.cb_ask_str = cb_ask_str
27
27
  self.cb_msg = cb_msg
28
28
 
29
- def download_signal_desktop(self):
29
+ def download_signal_desktop(self) -> None:
30
30
  download_url = "https://signal.org/en/download/"
31
31
 
32
32
  webbrowser.open(download_url)
@@ -28,7 +28,7 @@ MSG_PERMISSION_ERROR = "Failed to read Viber process memory"
28
28
 
29
29
 
30
30
  class GetViberAuth:
31
- def __init__(self, cb_ask_str: Callable[..., str] = input):
31
+ def __init__(self, cb_ask_str: Callable[..., str] = input) -> None:
32
32
  self.cb_ask_str = cb_ask_str
33
33
 
34
34
  def relaunch_viber(self, viber_bin_path: str) -> Optional[int]:
@@ -22,7 +22,9 @@ Continue when done"""
22
22
 
23
23
 
24
24
  class TelethonSetup:
25
- def __init__(self, opt_cred: CredOption, cb_ask_str: Callable[..., str] = input):
25
+ def __init__(
26
+ self, opt_cred: CredOption, cb_ask_str: Callable[..., str] = input
27
+ ) -> None:
26
28
  self.cb_ask_str = cb_ask_str
27
29
  self.opt_cred = opt_cred
28
30
 
@@ -5,12 +5,12 @@ import json
5
5
  import os
6
6
  import platform
7
7
  import shutil
8
+ import signal
8
9
  import socket
9
10
  import subprocess
10
11
  import time
11
12
  from typing import Any, Dict, List, Optional, Tuple, Union, cast
12
13
 
13
- import browsers # type: ignore
14
14
  import requests
15
15
  import websocket
16
16
  from PIL import Image
@@ -50,7 +50,7 @@ class CRD:
50
50
  chrome_bin: str,
51
51
  port: Optional[int] = None,
52
52
  args: Optional[List[str]] = None,
53
- ):
53
+ ) -> None:
54
54
  if port is None:
55
55
  port = get_free_port()
56
56
  self.port = port
@@ -84,6 +84,14 @@ class CRD:
84
84
 
85
85
  @staticmethod
86
86
  def get_chrome_path() -> Optional[str]:
87
+ import logging
88
+
89
+ import browsers # type: ignore
90
+
91
+ # browsers module would turn on info logging
92
+ logger = logging.getLogger()
93
+ logger.setLevel(logging.CRITICAL)
94
+
87
95
  bs: List[Tuple[int, str]] = []
88
96
  for b in browsers.browsers():
89
97
  browser_type = b["browser_type"]
@@ -98,7 +106,7 @@ class CRD:
98
106
  bs = sorted(bs, key=lambda x: x[0])
99
107
  return bs[0][1]
100
108
 
101
- def connect(self, target_id: int = 0):
109
+ def connect(self, target_id: int = 0) -> None:
102
110
  self.cmd_id = 1
103
111
  r = None
104
112
  targets: List[Any] = []
@@ -137,7 +145,7 @@ class CRD:
137
145
 
138
146
  raise RuntimeError("Websocket keep disconnecting")
139
147
 
140
- def exec_js(self, js: str, context_id: Optional[int] = None):
148
+ def exec_js(self, js: str, context_id: Optional[int] = None) -> Union[str, bytes]:
141
149
  command: Dict[str, Any] = {
142
150
  "id": self.cmd_id,
143
151
  "method": "Runtime.evaluate",
@@ -155,11 +163,11 @@ class CRD:
155
163
  }
156
164
  return self.send_cmd(command)
157
165
 
158
- def screenshot(self, clip: Optional[Dict[str, int]] = None):
166
+ def screenshot(self, clip: Optional[Dict[str, int]] = None) -> Image.Image:
159
167
  command: Dict[str, Any] = {
160
168
  "id": self.cmd_id,
161
169
  "method": "Page.captureScreenshot",
162
- "params": {},
170
+ "params": {"captureBeyondViewport": True, "optimizeForSpeed": True},
163
171
  }
164
172
  if clip:
165
173
  command["params"]["clip"] = clip
@@ -174,11 +182,11 @@ class CRD:
174
182
  str, json.loads(r).get("result", {}).get("result", {}).get("value", "")
175
183
  )
176
184
 
177
- def navigate(self, url: str):
185
+ def navigate(self, url: str) -> None:
178
186
  command = {"id": self.cmd_id, "method": "Page.navigate", "params": {"url": url}}
179
187
  self.send_cmd(command)
180
188
 
181
- def open_html_str(self, html: str):
189
+ def open_html_str(self, html: str) -> None:
182
190
  command: Dict[str, Any] = {
183
191
  "id": self.cmd_id,
184
192
  "method": "Page.navigate",
@@ -198,24 +206,28 @@ class CRD:
198
206
  }
199
207
  self.send_cmd(command)
200
208
 
201
- def runtime_enable(self):
209
+ def runtime_enable(self) -> None:
202
210
  command = {
203
211
  "method": "Runtime.enable",
204
212
  }
205
213
  self.send_cmd(command)
206
214
 
207
- def runtime_disable(self):
215
+ def runtime_disable(self) -> None:
208
216
  command = {
209
217
  "method": "Runtime.disable",
210
218
  }
211
219
  self.send_cmd(command)
212
220
 
213
- def reload(self):
221
+ def reload(self) -> None:
214
222
  command = {
215
223
  "method": "Page.reload",
216
224
  }
217
225
  self.send_cmd(command)
218
226
 
219
- def close(self):
227
+ def close(self) -> None:
228
+ command = {
229
+ "method": "Browser.close",
230
+ }
231
+ self.send_cmd(command)
220
232
  self.ws.close()
221
- self.chrome_proc.kill()
233
+ os.kill(self.chrome_proc.pid, signal.SIGTERM)
@@ -20,7 +20,7 @@ from sticker_convert.definitions import SVG_DEFAULT_HEIGHT, SVG_DEFAULT_WIDTH, S
20
20
  warnings.filterwarnings("ignore", category=XMLParsedAsHTMLWarning)
21
21
 
22
22
 
23
- def lcm(a: int, b: int):
23
+ def lcm(a: int, b: int) -> int:
24
24
  return abs(a * b) // gcd(a, b)
25
25
 
26
26
 
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env python3
2
+ from typing import Any, Dict, Protocol
3
+
4
+
5
+ class SingletonProtocol(Protocol):
6
+ def close(self) -> Any: ...
7
+
8
+
9
+ class Singletons:
10
+ def __init__(self) -> None:
11
+ self.objs: Dict[str, SingletonProtocol] = {}
12
+
13
+ def close(self) -> None:
14
+ for obj in self.objs.values():
15
+ obj.close()
16
+
17
+
18
+ singletons = Singletons()
@@ -25,6 +25,9 @@ class UrlDetect:
25
25
  if domain in ("e.kakao.com", "emoticon.kakao.com"):
26
26
  return "kakao"
27
27
 
28
+ if domain == "www.band.us":
29
+ return "band"
30
+
28
31
  if domain == "stickers.viber.com":
29
32
  return "viber"
30
33
 
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env python3
2
2
 
3
- __version__ = "2.12.4"
3
+ __version__ = "2.13.0"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sticker-convert
3
- Version: 2.12.4
3
+ Version: 2.13.0
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>
@@ -366,7 +366,7 @@ License-File: LICENSE
366
366
  Requires-Dist: aiolimiter~=1.2.1
367
367
  Requires-Dist: anyio~=4.9.0
368
368
  Requires-Dist: apngasm_python~=1.3.2
369
- Requires-Dist: av~=13.1.0
369
+ Requires-Dist: av>=13.1.0
370
370
  Requires-Dist: beautifulsoup4~=4.13.3
371
371
  Requires-Dist: cryptg~=0.5.0.post0
372
372
  Requires-Dist: rookiepy~=0.5.6
@@ -375,8 +375,8 @@ Requires-Dist: imagequant~=1.1.4
375
375
  Requires-Dist: memory-tempfile~=2.2.3
376
376
  Requires-Dist: mergedeep~=1.3.4
377
377
  Requires-Dist: numpy>=1.22.4
378
- Requires-Dist: Pillow~=11.1.0
379
- Requires-Dist: pybrowsers~=0.7.0
378
+ Requires-Dist: Pillow~=11.2.1
379
+ Requires-Dist: pybrowsers~=0.8.0
380
380
  Requires-Dist: pyoxipng~=9.1.0
381
381
  Requires-Dist: python-telegram-bot~=22.0
382
382
  Requires-Dist: psutil~=7.0.0
@@ -397,7 +397,7 @@ Dynamic: license-file
397
397
 
398
398
  - A python script for creating, downloading, converting+compressing and uploading stickers from multiple instant messaging applications.
399
399
  - With GUI and CLI that runs on Windows, MacOS and Linux
400
- - Currently supports Signal, Telegram, WhatsApp (Create .wastickers), Line (Download only), Kakao (Download only), Viber, Discord (Download only), iMessage (Create Xcode sticker pack project)
400
+ - Currently supports Signal, Telegram, WhatsApp (Create .wastickers), Line (Download only), Kakao (Download only), Naver Band (Download only), Viber, Discord (Download only), iMessage (Create Xcode sticker pack project)
401
401
  - Supports static and animated stickers, with transparency support
402
402
 
403
403
  ## Downloads
@@ -438,6 +438,7 @@ Dynamic: license-file
438
438
  | [WhatsApp](docs/guide_whatsapp.md) | ⭕ (By Android or WhatsApp Web) | ⭕ (Create `.wastickers`, import by Sticker Maker) |
439
439
  | [Line](docs/guide_line.md) | ✅ | 🚫 (Need to submit for manual approval) |
440
440
  | [Kakao](docs/guide_kakao.md) | ✅ (Need 'auth_token' for animated) | 🚫 (Need to submit for manual approval) |
441
+ | [Band](docs/guide_band.md) | ✅ | 🚫 (Need to submit for manual approval) |
441
442
  | [Viber](docs/guide_viber.md) | ✅ | ✅ (Require `viber_auth`) |
442
443
  | [Discord](docs/guide_discord.md) | ✅ (Require `token`) | 🚫 |
443
444
  | [iMessage](docs/guide_imessage.md) | 🚫 | ⭕ (Create Xcode stickerpack project for sideload) |
@@ -464,6 +465,9 @@ Dynamic: license-file
464
465
  - Kakao
465
466
  - Download: Supported (e.g. `https://e.kakao.com/t/xxxxx` OR `https://emoticon.kakao.com/items/xxxxx` OR `4404400`). It is rather complicated, learn more from [docs/guide_kakao.md](docs/guide_kakao.md)
466
467
  - Upload: Not supported. You need to manually submit sticker pack for approval before you can use in app.
468
+ - Band
469
+ - Download: Supported (e.g. `https://www.band.us/sticker/xxxx` OR 2535). Learn how to get share link from [docs/guide_band.md](docs/guide_band.md)
470
+ - Upload: Not supported. You need to manually submit sticker pack for approval before you can use in app.
467
471
  - Viber
468
472
  - Download: Supported (e.g. `https://stickers.viber.com/pages/example` OR `https://stickers.viber.com/pages/custom-sticker-packs/example`)
469
473
  - Upload: Supported. Viber authentication data required for uploading Viber stickers, which could be fetched from Viber Desktop application automatically.
@@ -490,30 +494,27 @@ Dynamic: license-file
490
494
  To run in CLI mode, pass on any arguments
491
495
 
492
496
  ```
493
- usage: sticker-convert.py [-h] [--version] [--no-confirm] [--no-progress] [--custom-presets CUSTOM_PRESETS]
494
- [--input-dir INPUT_DIR]
495
- [--download-auto DOWNLOAD_AUTO | --download-signal DOWNLOAD_SIGNAL | --download-telegram DOWNLOAD_TELEGRAM | --download-telegram-telethon DOWNLOAD_TELEGRAM_TELETHON | --download-line DOWNLOAD_LINE | --download-kakao DOWNLOAD_KAKAO | --download-viber DOWNLOAD_VIBER | --download-discord DOWNLOAD_DISCORD | --download-discord-emoji DOWNLOAD_DISCORD_EMOJI]
497
+ usage: sticker-convert.py [-h] [--version] [--no-confirm] [--no-progress] [--custom-presets CUSTOM_PRESETS] [--input-dir INPUT_DIR]
498
+ [--download-auto DOWNLOAD_AUTO | --download-signal DOWNLOAD_SIGNAL | --download-telegram DOWNLOAD_TELEGRAM | --download-telegram-telethon DOWNLOAD_TELEGRAM_TELETHON | --download-line DOWNLOAD_LINE | --download-kakao DOWNLOAD_KAKAO | --download-band DOWNLOAD_BAND | --download-viber DOWNLOAD_VIBER | --download-discord DOWNLOAD_DISCORD | --download-discord-emoji DOWNLOAD_DISCORD_EMOJI]
496
499
  [--output-dir OUTPUT_DIR] [--author AUTHOR] [--title TITLE]
497
500
  [--export-signal | --export-telegram | --export-telegram-emoji | --export-telegram-telethon | --export-telegram-emoji-telethon | --export-viber | --export-whatsapp | --export-imessage]
498
501
  [--no-compress]
499
502
  [--preset {auto,signal,telegram,telegram_emoji,whatsapp,line,kakao,viber,discord,discord_emoji,imessage_small,imessage_medium,imessage_large,custom}]
500
- [--steps STEPS] [--processes PROCESSES] [--fps-min FPS_MIN] [--fps-max FPS_MAX]
501
- [--fps-power FPS_POWER] [--res-min RES_MIN] [--res-max RES_MAX] [--res-w-min RES_W_MIN]
502
- [--res-w-max RES_W_MAX] [--res-h-min RES_H_MIN] [--res-h-max RES_H_MAX] [--res-power RES_POWER]
503
- [--quality-min QUALITY_MIN] [--quality-max QUALITY_MAX] [--quality-power QUALITY_POWER]
504
- [--color-min COLOR_MIN] [--color-max COLOR_MAX] [--color-power COLOR_POWER]
503
+ [--steps STEPS] [--processes PROCESSES] [--fps-min FPS_MIN] [--fps-max FPS_MAX] [--fps-power FPS_POWER]
504
+ [--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]
505
+ [--res-h-max RES_H_MAX] [--res-power RES_POWER] [--quality-min QUALITY_MIN] [--quality-max QUALITY_MAX]
506
+ [--quality-power QUALITY_POWER] [--color-min COLOR_MIN] [--color-max COLOR_MAX] [--color-power COLOR_POWER]
505
507
  [--duration-min DURATION_MIN] [--duration-max DURATION_MAX] [--padding-percent PADDING_PERCENT]
506
- [--bg-color BG_COLOR] [--vid-size-max VID_SIZE_MAX] [--img-size-max IMG_SIZE_MAX]
507
- [--vid-format VID_FORMAT] [--img-format IMG_FORMAT] [--fake-vid] [--scale-filter SCALE_FILTER]
508
- [--quantize-method QUANTIZE_METHOD] [--cache-dir CACHE_DIR] [--default-emoji DEFAULT_EMOJI]
509
- [--signal-uuid SIGNAL_UUID] [--signal-password SIGNAL_PASSWORD] [--signal-get-auth]
510
- [--telegram-token TELEGRAM_TOKEN] [--telegram-userid TELEGRAM_USERID] [--telethon-setup]
511
- [--kakao-auth-token KAKAO_AUTH_TOKEN] [--kakao-get-auth] [--kakao-get-auth-desktop]
512
- [--kakao-bin-path KAKAO_BIN_PATH] [--kakao-username KAKAO_USERNAME]
508
+ [--bg-color BG_COLOR] [--vid-size-max VID_SIZE_MAX] [--img-size-max IMG_SIZE_MAX] [--vid-format VID_FORMAT]
509
+ [--img-format IMG_FORMAT] [--fake-vid] [--scale-filter SCALE_FILTER] [--quantize-method QUANTIZE_METHOD]
510
+ [--cache-dir CACHE_DIR] [--chromium-path CHROMIUM_PATH] [--default-emoji DEFAULT_EMOJI] [--signal-uuid SIGNAL_UUID]
511
+ [--signal-password SIGNAL_PASSWORD] [--signal-get-auth] [--telegram-token TELEGRAM_TOKEN]
512
+ [--telegram-userid TELEGRAM_USERID] [--telethon-setup] [--kakao-auth-token KAKAO_AUTH_TOKEN] [--kakao-get-auth]
513
+ [--kakao-get-auth-desktop] [--kakao-bin-path KAKAO_BIN_PATH] [--kakao-username KAKAO_USERNAME]
513
514
  [--kakao-password KAKAO_PASSWORD] [--kakao-country-code KAKAO_COUNTRY_CODE]
514
- [--kakao-phone-number KAKAO_PHONE_NUMBER] [--line-get-auth] [--line-cookies LINE_COOKIES]
515
- [--viber-auth VIBER_AUTH] [--viber-get-auth VIBER_GET_AUTH] [--viber-bin-path VIBER_BIN_PATH]
516
- [--discord-get-auth] [--discord-token DISCORD_TOKEN] [--save-cred]
515
+ [--kakao-phone-number KAKAO_PHONE_NUMBER] [--line-get-auth] [--line-cookies LINE_COOKIES] [--viber-auth VIBER_AUTH]
516
+ [--viber-get-auth VIBER_GET_AUTH] [--viber-bin-path VIBER_BIN_PATH] [--discord-get-auth]
517
+ [--discord-token DISCORD_TOKEN] [--save-cred]
517
518
 
518
519
  CLI for stickers-convert
519
520
 
@@ -552,6 +553,9 @@ Input options:
552
553
  Download kakao stickers from a URL / ID as input
553
554
  (Example: https://e.kakao.com/t/xxxxx
554
555
  OR https://emoticon.kakao.com/items/xxxxx OR 4404400)
556
+ --download-band DOWNLOAD_BAND
557
+ Download Naver Band stickers from a URL / ID as input
558
+ (Example: https://www.band.us/sticker/xxxx OR 2535)
555
559
  --download-viber DOWNLOAD_VIBER
556
560
  Download viber stickers from a URL as input
557
561
  (Example: https://stickers.viber.com/pages/example
@@ -659,6 +663,10 @@ Compression options:
659
663
  --cache-dir CACHE_DIR
660
664
  Set custom cache directory.
661
665
  Useful for debugging, or speed up conversion if cache_dir is on RAM disk.
666
+ --chromium-path CHROMIUM_PATH
667
+ Set Chromium(-based)/Chrome browser path.
668
+ Required for converting from SVG files.
669
+ Leave blank to auto detect
662
670
  --default-emoji DEFAULT_EMOJI
663
671
  Set the default emoji for uploading Signal and Telegram sticker packs.
664
672
 
@@ -885,5 +893,5 @@ See [docs/TODO.md](docs/TODO.md)
885
893
  - Banner generated from [GitHub Socialify](https://socialify.git.ci/)
886
894
 
887
895
  ## DISCLAIMER
888
- - The author of this repo is NOT affiliated with Signal, Telegram, WhatsApp, Line, Kakao, Viber, Discord, iMessage or Sticker Maker.
896
+ - The author of this repo is NOT affiliated with Signal, Telegram, WhatsApp, Line, Kakao, Naver Band, Viber, Discord, iMessage or Sticker Maker.
889
897
  - The author of this repo is NOT repsonsible for any legal consequences and loss incurred from using this repo.
@@ -1,16 +1,17 @@
1
1
  sticker_convert/__init__.py,sha256=iQnv6UOOA69c3soAn7ZOnAIubTIQSUxtq1Uhh8xRWvU,102
2
2
  sticker_convert/__main__.py,sha256=elDCMvU27letiYs8jPUpxaCq5puURnvcDuqGsAAb6_w,592
3
- sticker_convert/cli.py,sha256=Mj_cN4CnvOBTie6vJmN-e6EostNSiRts5GR38mvgm-Q,22433
4
- sticker_convert/converter.py,sha256=b3lJX2eTJ8OMFgAjQzbv2E8lbCclgo3yJ1dtBXmur28,39593
3
+ sticker_convert/cli.py,sha256=2mTp9h9I3sIBpEftfZvPr0vfjaqdvuHD5yFngLi5MwY,22473
4
+ sticker_convert/converter.py,sha256=BWg42NaRRDxXxo74L5Rh0l2BDkpe2Bh948Trypeg2vA,39758
5
5
  sticker_convert/definitions.py,sha256=BqROmOvqIqw8ANaqZXIxJAXGD0HgjAvCfFouQ4SaWHc,2254
6
- sticker_convert/gui.py,sha256=Lvuu9J1MPdokjlHpLctqsRTOnWv9jXvy2IjJQt0FRAk,34177
7
- sticker_convert/job.py,sha256=gEd6yF8WPUR1_7q9SVhnwdD5usrDxwowNnR5q9uS8Yc,28011
6
+ sticker_convert/gui.py,sha256=bd8rMgFaXrn41y6aOHNlD6gPBDleDmiHMsGMZNfz1jk,34239
7
+ sticker_convert/job.py,sha256=FJiaJEcfMr8GnNfPC3SDcpTs7ytoiAZk6cxUbzsw9IE,28257
8
8
  sticker_convert/job_option.py,sha256=yI_uKWJEAul2XTC6pucz9PfW0iNwwOr0aVC-PAHkMA4,8109
9
- sticker_convert/version.py,sha256=v342n9uw6gNve6meN4iu5vMOMDrABk5g9HB3zQjA5N8,47
9
+ sticker_convert/version.py,sha256=bJKod-cGHYLxNjnXLfxixQN8STyD8kVf2ApImRquwfM,47
10
10
  sticker_convert/downloaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
+ sticker_convert/downloaders/download_band.py,sha256=JPjwwdxbMXPBM9TXF76wT9mtoDCLssYnrm1iS2C6uVM,3629
11
12
  sticker_convert/downloaders/download_base.py,sha256=MI5pCT_tkfoaFlrD1oNynDj1Rv1CK0APuNVElTEAEis,5110
12
13
  sticker_convert/downloaders/download_discord.py,sha256=6AFpLAYL2hRvVcsqUtzDUC31U66U02ZcnKXDnZRi2jk,3496
13
- sticker_convert/downloaders/download_kakao.py,sha256=-k9uTo_vn5CUjb0XPCKPmtYfftwhUntpyO2kZpeu9Mc,12472
14
+ sticker_convert/downloaders/download_kakao.py,sha256=lRmpEcYjHizIRM0uFBDvjMqNEpur0VmOTKAmiir9eB0,15181
14
15
  sticker_convert/downloaders/download_line.py,sha256=c-hTzEarGQP0b-pnPl29NuSKcaZWUeRo_94YpJzz72M,17911
15
16
  sticker_convert/downloaders/download_signal.py,sha256=3wv-BLd4qggly4AdtwV8f3vUpCVZ-8GnoPLoWngY3Pk,3728
16
17
  sticker_convert/downloaders/download_telegram.py,sha256=iGmOcVjU2Ai19t1lyDY2JhQIc--O5XMyNCGXZAA4DVY,2028
@@ -29,11 +30,11 @@ sticker_convert/gui_components/frames/right_clicker.py,sha256=dGIvSzEChrkguR80pz
29
30
  sticker_convert/gui_components/windows/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
31
  sticker_convert/gui_components/windows/advanced_compression_window.py,sha256=djJNyPodBmNhW0vHvdg6xAd7LYkVm9UINMHrRXVmr_k,32718
31
32
  sticker_convert/gui_components/windows/base_window.py,sha256=xBE1peGMPvWsdrFej0CJUVhmQ57GJGvz-cX03nIIhkE,1108
32
- sticker_convert/gui_components/windows/discord_get_auth_window.py,sha256=pUSarkXXmSr01VW9h4LgpJy7F53gw7X6ZNqunoFG-ys,2762
33
+ sticker_convert/gui_components/windows/discord_get_auth_window.py,sha256=a9ptBqtpZslQJ87-ZPotcT6gigouIHWAFijfkWv2rZQ,2786
33
34
  sticker_convert/gui_components/windows/kakao_get_auth_window.py,sha256=1nawn_D4wkziW_lROjUJlmVtITAuGt_4uruGMcEr7Oo,11128
34
35
  sticker_convert/gui_components/windows/line_get_auth_window.py,sha256=S4ES_lk2-GDvPokZtYALnUc5zW1VbS4WulNqO9K1aSs,3375
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=oHL4ipivtGT35tN5wzDKhsYsihLmoLwSDgI75g2XcCs,5183
36
+ sticker_convert/gui_components/windows/signal_get_auth_window.py,sha256=d9vWMfrD0s-qI-TmB0796LRvDW64Jh2wmA1mZcRubUw,3126
37
+ sticker_convert/gui_components/windows/viber_get_auth_window.py,sha256=8EGNohkBZjmTJ_0Rt4XP0zVd1eLraqukNoE84E9d5CA,5191
37
38
  sticker_convert/ios-message-stickers-template/.gitignore,sha256=4uuTph_9eHfqXHUavLOmGOji6aIHOif2bUEU_hCBn4Y,9
38
39
  sticker_convert/ios-message-stickers-template/README.md,sha256=oN0FvJkCWWjSZ3PMrCvY3T1zCsdkZYFgGHAoFh0Kmt8,467
39
40
  sticker_convert/ios-message-stickers-template/.github/FUNDING.yml,sha256=3LlmdSAGDsBA2o_C1iBYTNLwkABnyZuN0zxgPPyd-f8,70
@@ -70,11 +71,11 @@ sticker_convert/resources/NotoColorEmoji.ttf,sha256=LurIVaCIA8bSCfjrdO1feYr0bhKL
70
71
  sticker_convert/resources/appicon.icns,sha256=FB2DVTOQcFfQNZ9RcyG3z9c9k7eOiI1qw0IJhXMRFg4,5404
71
72
  sticker_convert/resources/appicon.ico,sha256=-ldugcl2Yq2pBRTktnhGKWInpKyWzRjCiPvMr3XPTlc,38078
72
73
  sticker_convert/resources/appicon.png,sha256=6XBEQz7PnerqS43aRkwpWolFG4WvKMuQ-st1ly-_JPg,5265
73
- sticker_convert/resources/compression.json,sha256=hZY906wUmdAuflVhUowm9EW6h40BzuD4LBNe-Mpd9V8,14184
74
+ sticker_convert/resources/compression.json,sha256=wEgtjcDyLEYup53s-SCGu2Wc3UdReWeSj9POWn5PXkk,15184
74
75
  sticker_convert/resources/emoji.json,sha256=q9DRFdVJfm7feZW7ZM6Xa5P1QsMvrn0PbBVU9jKcJKI,422720
75
76
  sticker_convert/resources/help.json,sha256=IDJhDD5plY8_Ze5gnM6rMs6H1-urWo94sEHeGzO5QeU,7364
76
- sticker_convert/resources/input.json,sha256=BYHYDqMLZuQnA3MF0ViudGpkSuAG8OMS7L-7hxC3K3o,3858
77
- sticker_convert/resources/memdump_linux.sh,sha256=YbdX5C5RyCnoeDUE6JgTo8nQXKhrUw5-kFDx5bQp9tY,651
77
+ sticker_convert/resources/input.json,sha256=vLP8pVo4Mfh-yLRjy5j1x4SMR1dQC9xCRzQ6RWN_t2E,4213
78
+ sticker_convert/resources/memdump_linux.sh,sha256=SFKXiE0ztZyGvpFYPOrdQ0wmY3ndgJuqfiofC7BQon0,625
78
79
  sticker_convert/resources/memdump_windows.ps1,sha256=CfyNSSEW3HJOkTu-mKrP3qh5aprN-1VCBfj-R1fELA0,302
79
80
  sticker_convert/resources/output.json,sha256=SC_3vtEBJ79R7q0vy_p33eLsGFEyBsSOai0Hy7mLqG8,2208
80
81
  sticker_convert/uploaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -85,18 +86,19 @@ sticker_convert/uploaders/upload_telegram.py,sha256=WlUyLJlW83XZz6RhA76jHMXA6TNU
85
86
  sticker_convert/uploaders/upload_viber.py,sha256=_vOK0UgP7V7ZeFG6pR3sVf3A744Q6J19qzO-2hDvt5w,6583
86
87
  sticker_convert/uploaders/xcode_imessage.py,sha256=iTTT8gDYOTNkKqXeSWUBuWfxu7xeE418t2Z1YQFR5L0,11365
87
88
  sticker_convert/utils/callback.py,sha256=spYUGlklOs1yPZAxoqwOWgR1sdimpfM8a27if3TaVYk,6155
88
- sticker_convert/utils/chrome_remotedebug.py,sha256=uzUBlUtuO0cRcDxO7hnPWvbdt5NJBnCXvAnStK2zAVQ,6445
89
+ sticker_convert/utils/chrome_remotedebug.py,sha256=p8D85NDlLiS7Vj2wLLZX7TN6hENe2p5PxVDoeOr_mTE,6902
89
90
  sticker_convert/utils/emoji.py,sha256=AqB26JY-PkYzNwPLReSnqLiQKe-bR9UXnLclAbgubJ8,367
90
91
  sticker_convert/utils/process.py,sha256=EAQZ9WpiKmkvToIv8G1HNY4V7m0jXyyePTmeP2XOZzE,4688
91
- sticker_convert/utils/url_detect.py,sha256=vCbhQbcW1X_UtdfQlICGY8pMX34KQ6sCtDJZbp0NrSg,876
92
- sticker_convert/utils/auth/get_discord_auth.py,sha256=MeyLzB8hlMTv8l2-6HBW45hppwogSH2gyI1L-VAOEkM,4273
92
+ sticker_convert/utils/singletons.py,sha256=SiV374FxU68DpysGoj_ytU1ErINkeOBbP4s9QTcexeY,357
93
+ sticker_convert/utils/url_detect.py,sha256=_wmI28hUyngq8TVz1bw7YM90qPLd3bIynawVlbr_lcI,939
94
+ sticker_convert/utils/auth/get_discord_auth.py,sha256=6qh1BuN-GieSXqJu9WbthLsflrYIGaEgKHGrQoPbO1M,4281
93
95
  sticker_convert/utils/auth/get_kakao_auth.py,sha256=Wok5sp0GGBgTwwlfYB7lVq82ndBAOGTcqsWEaWAXFNE,10760
94
- sticker_convert/utils/auth/get_kakao_desktop_auth.py,sha256=yT-gvvrKfpMRIVfmc6mfaEWSh4RKMs0B3rOD-zSI5hs,8597
96
+ sticker_convert/utils/auth/get_kakao_desktop_auth.py,sha256=0qxy1MfLFFDhSaEzWYT3H1GGOUBWDrmRPoonCIt1nuE,8613
95
97
  sticker_convert/utils/auth/get_line_auth.py,sha256=8l8ha2vQmk3rHGvDE7PkcxQXbH3oe62LKbI3qVUtvqc,2196
96
- sticker_convert/utils/auth/get_signal_auth.py,sha256=oDTcIUcRM8_zfmR6UoBvzBhIscwLRe7n2zw4aw0j8_Q,4564
97
- sticker_convert/utils/auth/get_viber_auth.py,sha256=mUTrcxq5bTrzSXEVaeTPqVQIdZdwvIhrbMgBUb7dU30,8173
98
+ sticker_convert/utils/auth/get_signal_auth.py,sha256=I6od2aj8yl1eLV8S2TtNQEPM77DC7FpkRKex0pXY2II,4580
99
+ sticker_convert/utils/auth/get_viber_auth.py,sha256=redKrHbCCBWHhOqAQOBIOWQpLM3R7Kr86ArTh7OWI4g,8181
98
100
  sticker_convert/utils/auth/telegram_api.py,sha256=hX9fT0Pp8yMxcKSXLe9Mvy12mQ_rWj-KTyamABI8YWA,24232
99
- sticker_convert/utils/auth/telethon_setup.py,sha256=QW0RAP3KwnxK9ZHmCo_iGqc1NiskOzsGa1kcmPT9PsQ,2972
101
+ sticker_convert/utils/auth/telethon_setup.py,sha256=vBgRPBU_jXI8sHpYEofvO84F-dObY0TCfFzhHyw3OLI,2994
100
102
  sticker_convert/utils/files/cache_store.py,sha256=etfe614OAhAyrnM5fGeESKq6R88YLNqkqkxSzEmZ0V0,1047
101
103
  sticker_convert/utils/files/json_manager.py,sha256=Vr6pZJdLMkrJJWN99210aduVHb0ILyf0SSTaw4TZqgc,541
102
104
  sticker_convert/utils/files/json_resources_loader.py,sha256=flZFixUXRTrOAhvRQpuSQgmJ69yXL94sxukcowLT1JQ,1049
@@ -104,12 +106,12 @@ sticker_convert/utils/files/metadata_handler.py,sha256=TUseSpKsFLoqqFf7YFENzkwDY
104
106
  sticker_convert/utils/files/run_bin.py,sha256=C_KKGtMUTajJnKo4Ia9e6WuWCXSQRdGsVPG-r5GXT_I,1784
105
107
  sticker_convert/utils/files/sanitize_filename.py,sha256=HBklPGsHRJjFQUIC5rYTQsUrsuTtezZXIEA8CPhLP8A,2156
106
108
  sticker_convert/utils/media/apple_png_normalize.py,sha256=LbrQhc7LlYX4I9ek4XJsZE4l0MygBA1jB-PFiYLEkzk,3657
107
- sticker_convert/utils/media/codec_info.py,sha256=_F_iV3k2GYtb8vYZUSKrWl9E7XEW6LDywbnJ-DM6kbk,16476
109
+ sticker_convert/utils/media/codec_info.py,sha256=HwA6eVh7cLhOlUoR_K9d_wyBRJ_ocGtB3GAyne_iZAU,16483
108
110
  sticker_convert/utils/media/decrypt_kakao.py,sha256=4wq9ZDRnFkx1WmFZnyEogBofiLGsWQM_X69HlA36578,1947
109
111
  sticker_convert/utils/media/format_verify.py,sha256=oM32P186tWe9YxvBQRPr8D3FEmBN3b2rEe_2S_MwxyQ,6236
110
- sticker_convert-2.12.4.dist-info/licenses/LICENSE,sha256=gXf5dRMhNSbfLPYYTY_5hsZ1r7UU1OaKQEAQUhuIBkM,18092
111
- sticker_convert-2.12.4.dist-info/METADATA,sha256=2Z9TXBiRE_dhOaRYaiIKZ_fYnnKOvfuKZH484Rgc_J8,53517
112
- sticker_convert-2.12.4.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
113
- sticker_convert-2.12.4.dist-info/entry_points.txt,sha256=MNJ7XyC--ugxi5jS1nzjDLGnxCyLuaGdsVLnJhDHCqs,66
114
- sticker_convert-2.12.4.dist-info/top_level.txt,sha256=r9vfnB0l1ZnH5pTH5RvkobnK3Ow9m0RsncaOMAtiAtk,16
115
- sticker_convert-2.12.4.dist-info/RECORD,,
112
+ sticker_convert-2.13.0.dist-info/licenses/LICENSE,sha256=gXf5dRMhNSbfLPYYTY_5hsZ1r7UU1OaKQEAQUhuIBkM,18092
113
+ sticker_convert-2.13.0.dist-info/METADATA,sha256=P6ZK34jRKvYmFd_2zm-8KAdjewwSJnoSaDN2yy3SR0Q,54352
114
+ sticker_convert-2.13.0.dist-info/WHEEL,sha256=pxyMxgL8-pra_rKaQ4drOZAegBVuX-G_4nRHjjgWbmo,91
115
+ sticker_convert-2.13.0.dist-info/entry_points.txt,sha256=MNJ7XyC--ugxi5jS1nzjDLGnxCyLuaGdsVLnJhDHCqs,66
116
+ sticker_convert-2.13.0.dist-info/top_level.txt,sha256=r9vfnB0l1ZnH5pTH5RvkobnK3Ow9m0RsncaOMAtiAtk,16
117
+ sticker_convert-2.13.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (78.1.0)
2
+ Generator: setuptools (79.0.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5