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.
- sticker_convert/cli.py +3 -0
- sticker_convert/converter.py +61 -58
- sticker_convert/downloaders/download_band.py +110 -0
- sticker_convert/downloaders/download_kakao.py +84 -22
- sticker_convert/downloaders/download_line.py +8 -4
- sticker_convert/gui.py +6 -3
- sticker_convert/gui_components/windows/advanced_compression_window.py +1 -1
- sticker_convert/gui_components/windows/discord_get_auth_window.py +3 -3
- sticker_convert/gui_components/windows/kakao_get_auth_window.py +25 -4
- sticker_convert/gui_components/windows/signal_get_auth_window.py +3 -3
- sticker_convert/gui_components/windows/viber_get_auth_window.py +16 -1
- sticker_convert/job.py +6 -0
- sticker_convert/resources/compression.json +47 -0
- sticker_convert/resources/help.json +1 -1
- sticker_convert/resources/input.json +10 -0
- sticker_convert/resources/memdump_linux.sh +0 -1
- sticker_convert/utils/auth/get_discord_auth.py +2 -2
- sticker_convert/utils/auth/get_kakao_desktop_auth.py +38 -43
- sticker_convert/utils/auth/get_signal_auth.py +2 -2
- sticker_convert/utils/auth/get_viber_auth.py +3 -5
- sticker_convert/utils/auth/telegram_api.py +3 -1
- sticker_convert/utils/auth/telethon_setup.py +21 -8
- sticker_convert/utils/chrome_remotedebug.py +27 -29
- sticker_convert/utils/chromiums/linux.py +52 -0
- sticker_convert/utils/chromiums/osx.py +68 -0
- sticker_convert/utils/chromiums/windows.py +45 -0
- sticker_convert/utils/media/codec_info.py +1 -1
- sticker_convert/utils/process.py +152 -108
- sticker_convert/utils/singletons.py +18 -0
- sticker_convert/utils/url_detect.py +3 -0
- sticker_convert/version.py +1 -1
- {sticker_convert-2.12.4.dist-info → sticker_convert-2.13.1.0.dist-info}/METADATA +37 -29
- {sticker_convert-2.12.4.dist-info → sticker_convert-2.13.1.0.dist-info}/RECORD +37 -32
- {sticker_convert-2.12.4.dist-info → sticker_convert-2.13.1.0.dist-info}/WHEEL +1 -1
- {sticker_convert-2.12.4.dist-info → sticker_convert-2.13.1.0.dist-info}/entry_points.txt +0 -0
- {sticker_convert-2.12.4.dist-info → sticker_convert-2.13.1.0.dist-info}/licenses/LICENSE +0 -0
- {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()
|
sticker_convert/converter.py
CHANGED
@@ -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
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
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
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
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 =
|
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
|
-
|
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
|
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":
|
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
|
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
|
-
|
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
|
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
|
-
|
123
|
-
|
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.
|
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
|
-
|
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
|
-
|
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
|
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.
|
89
|
-
|
90
|
-
|
91
|
-
self.
|
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()
|