sticker-convert 2.10.8__py3-none-any.whl → 2.11.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 +39 -1
- sticker_convert/converter.py +10 -6
- sticker_convert/downloaders/download_base.py +37 -17
- sticker_convert/downloaders/download_discord.py +6 -6
- sticker_convert/downloaders/download_kakao.py +31 -13
- sticker_convert/downloaders/download_line.py +6 -6
- sticker_convert/downloaders/download_signal.py +10 -8
- sticker_convert/downloaders/download_telegram.py +22 -96
- sticker_convert/downloaders/download_viber.py +8 -6
- sticker_convert/gui.py +12 -0
- sticker_convert/gui_components/frames/cred_frame.py +38 -13
- sticker_convert/job.py +84 -63
- sticker_convert/job_option.py +6 -0
- sticker_convert/resources/compression.json +2 -2
- sticker_convert/resources/help.json +3 -2
- sticker_convert/resources/input.json +10 -0
- sticker_convert/resources/output.json +16 -0
- sticker_convert/uploaders/compress_wastickers.py +8 -6
- sticker_convert/uploaders/upload_signal.py +10 -6
- sticker_convert/uploaders/upload_telegram.py +178 -231
- sticker_convert/uploaders/upload_viber.py +12 -8
- sticker_convert/uploaders/xcode_imessage.py +8 -6
- sticker_convert/utils/auth/telegram_api.py +668 -0
- sticker_convert/utils/auth/telethon_setup.py +79 -0
- sticker_convert/utils/url_detect.py +1 -1
- sticker_convert/version.py +1 -1
- {sticker_convert-2.10.8.dist-info → sticker_convert-2.11.0.dist-info}/METADATA +54 -36
- {sticker_convert-2.10.8.dist-info → sticker_convert-2.11.0.dist-info}/RECORD +32 -30
- {sticker_convert-2.10.8.dist-info → sticker_convert-2.11.0.dist-info}/LICENSE +0 -0
- {sticker_convert-2.10.8.dist-info → sticker_convert-2.11.0.dist-info}/WHEEL +0 -0
- {sticker_convert-2.10.8.dist-info → sticker_convert-2.11.0.dist-info}/entry_points.txt +0 -0
- {sticker_convert-2.10.8.dist-info → sticker_convert-2.11.0.dist-info}/top_level.txt +0 -0
sticker_convert/cli.py
CHANGED
@@ -20,6 +20,7 @@ from sticker_convert.utils.auth.get_kakao_desktop_auth import GetKakaoDesktopAut
|
|
20
20
|
from sticker_convert.utils.auth.get_line_auth import GetLineAuth
|
21
21
|
from sticker_convert.utils.auth.get_signal_auth import GetSignalAuth
|
22
22
|
from sticker_convert.utils.auth.get_viber_auth import GetViberAuth
|
23
|
+
from sticker_convert.utils.auth.telethon_setup import TelethonSetup
|
23
24
|
from sticker_convert.utils.callback import Callback
|
24
25
|
from sticker_convert.utils.files.json_manager import JsonManager
|
25
26
|
from sticker_convert.utils.url_detect import UrlDetect
|
@@ -168,10 +169,12 @@ class CLI:
|
|
168
169
|
parser_cred = parser.add_argument_group("Credentials options")
|
169
170
|
flags_cred_bool = (
|
170
171
|
"signal_get_auth",
|
172
|
+
"telethon_setup",
|
171
173
|
"kakao_get_auth",
|
172
174
|
"kakao_get_auth_desktop",
|
173
175
|
"line_get_auth",
|
174
176
|
"discord_get_auth",
|
177
|
+
"save_cred",
|
175
178
|
)
|
176
179
|
for k, v in self.help["cred"].items():
|
177
180
|
keyword_args = {}
|
@@ -226,6 +229,7 @@ class CLI:
|
|
226
229
|
"signal": args.download_signal,
|
227
230
|
"line": args.download_line,
|
228
231
|
"telegram": args.download_telegram,
|
232
|
+
"telegram_telethon": args.download_telegram_telethon,
|
229
233
|
"kakao": args.download_kakao,
|
230
234
|
"viber": args.download_viber,
|
231
235
|
"discord": args.download_discord,
|
@@ -266,6 +270,14 @@ class CLI:
|
|
266
270
|
export_option = "signal"
|
267
271
|
elif args.export_telegram:
|
268
272
|
export_option = "telegram"
|
273
|
+
elif args.export_telegram_emoji:
|
274
|
+
export_option = "telegram_emoji"
|
275
|
+
elif args.export_telegram_telethon:
|
276
|
+
export_option = "telegram_telethon"
|
277
|
+
elif args.export_telegram_emoji_telethon:
|
278
|
+
export_option = "telegram_emoji_telethon"
|
279
|
+
elif args.export_viber:
|
280
|
+
export_option = "viber"
|
269
281
|
elif args.export_imessage:
|
270
282
|
export_option = "imessage"
|
271
283
|
else:
|
@@ -291,6 +303,10 @@ class CLI:
|
|
291
303
|
args.export_whatsapp,
|
292
304
|
args.export_signal,
|
293
305
|
args.export_telegram,
|
306
|
+
args.export_telegram_emoji,
|
307
|
+
args.export_telegram_telethon,
|
308
|
+
args.export_telegram_emoji_telethon,
|
309
|
+
args.export_viber,
|
294
310
|
args.export_imessage,
|
295
311
|
)
|
296
312
|
)
|
@@ -302,8 +318,12 @@ class CLI:
|
|
302
318
|
preset = "whatsapp"
|
303
319
|
elif args.export_signal:
|
304
320
|
preset = "signal"
|
305
|
-
elif args.export_telegram:
|
321
|
+
elif args.export_telegram or args.export_telegram_telethon:
|
306
322
|
preset = "telegram"
|
323
|
+
elif args.export_telegram_emoji or args.export_telegram_emoji_telethon:
|
324
|
+
preset = "telegram_emoji"
|
325
|
+
elif args.export_viber:
|
326
|
+
preset = "viber"
|
307
327
|
elif args.export_imessage:
|
308
328
|
preset = "imessage_small"
|
309
329
|
elif args.preset == "auto":
|
@@ -316,6 +336,12 @@ class CLI:
|
|
316
336
|
self.cb.msg(
|
317
337
|
"Auto compression option set to no_compress (Reason: Export to local directory only)"
|
318
338
|
)
|
339
|
+
elif "telegram_emoji" in output_option:
|
340
|
+
preset = "telegram_emoji"
|
341
|
+
self.cb.msg(f"Auto compression option set to {preset}")
|
342
|
+
elif "telegram" in output_option:
|
343
|
+
preset = "telegram"
|
344
|
+
self.cb.msg(f"Auto compression option set to {preset}")
|
319
345
|
elif output_option == "imessage":
|
320
346
|
preset = "imessage_small"
|
321
347
|
self.cb.msg(f"Auto compression option set to {preset}")
|
@@ -445,6 +471,8 @@ class CLI:
|
|
445
471
|
telegram_userid=args.telegram_userid
|
446
472
|
if args.telegram_userid
|
447
473
|
else creds.get("telegram", {}).get("userid"),
|
474
|
+
telethon_api_id=creds.get("telethon", {}).get("api_id"),
|
475
|
+
telethon_api_hash=creds.get("telethon", {}).get("api_hash"),
|
448
476
|
kakao_auth_token=args.kakao_auth_token
|
449
477
|
if args.kakao_auth_token
|
450
478
|
else creds.get("kakao", {}).get("auth_token"),
|
@@ -511,6 +539,16 @@ class CLI:
|
|
511
539
|
|
512
540
|
self.cb.msg("Failed to get uuid and password")
|
513
541
|
|
542
|
+
if args.telethon_setup:
|
543
|
+
telethon_setup = TelethonSetup(opt_cred, self.cb.ask_str)
|
544
|
+
success, _, telethon_api_id, telethon_api_hash = telethon_setup.start()
|
545
|
+
|
546
|
+
if success:
|
547
|
+
opt_cred.telethon_api_id = telethon_api_id
|
548
|
+
opt_cred.telethon_api_hash = telethon_api_hash
|
549
|
+
|
550
|
+
self.cb.msg("Telethon setup successful")
|
551
|
+
|
514
552
|
if args.line_get_auth:
|
515
553
|
get_line_auth = GetLineAuth()
|
516
554
|
|
sticker_convert/converter.py
CHANGED
@@ -434,7 +434,7 @@ class StickerConvert:
|
|
434
434
|
# Pillow is not reliable for getting webp frame durations
|
435
435
|
durations: Optional[List[int]]
|
436
436
|
if im.format == "WEBP":
|
437
|
-
_, _, _, durations = CodecInfo._get_file_fps_frames_duration_webp(
|
437
|
+
_, _, _, durations = CodecInfo._get_file_fps_frames_duration_webp( # type: ignore
|
438
438
|
self.in_f
|
439
439
|
)
|
440
440
|
else:
|
@@ -702,9 +702,9 @@ class StickerConvert:
|
|
702
702
|
self._frames_export_apng()
|
703
703
|
else:
|
704
704
|
self._frames_export_png()
|
705
|
-
elif self.out_f.suffix
|
705
|
+
elif self.out_f.suffix in (".gif", ".webp"):
|
706
706
|
self._frames_export_pil_anim()
|
707
|
-
elif self.out_f.suffix in (".webm", ".mp4", ".mkv"
|
707
|
+
elif self.out_f.suffix in (".webm", ".mp4", ".mkv") or is_animated:
|
708
708
|
self._frames_export_pyav()
|
709
709
|
else:
|
710
710
|
self._frames_export_pil()
|
@@ -764,7 +764,7 @@ class StickerConvert:
|
|
764
764
|
format=self.out_f.suffix.replace(".", ""),
|
765
765
|
options=options_container,
|
766
766
|
) as output:
|
767
|
-
out_stream = output.add_stream(codec, rate=self.fps, options=options_stream)
|
767
|
+
out_stream = output.add_stream(codec, rate=self.fps, options=options_stream) # type: ignore
|
768
768
|
out_stream = cast(VideoStream, out_stream)
|
769
769
|
assert isinstance(self.res_w, int) and isinstance(self.res_h, int)
|
770
770
|
out_stream.width = self.res_w
|
@@ -811,8 +811,12 @@ class StickerConvert:
|
|
811
811
|
elif self.out_f.suffix == ".webp":
|
812
812
|
im_out = [Image.fromarray(i) for i in self.frames_processed] # type: ignore
|
813
813
|
extra_kwargs["format"] = "WebP"
|
814
|
-
extra_kwargs["
|
815
|
-
|
814
|
+
extra_kwargs["allow_mixed"] = True
|
815
|
+
if self.quality:
|
816
|
+
if self.quality < 20:
|
817
|
+
extra_kwargs["minimize_size"] = True
|
818
|
+
extra_kwargs["method"] = 4 + int(2 * (100 - self.quality) / 100)
|
819
|
+
extra_kwargs["alpha_quality"] = self.quality
|
816
820
|
else:
|
817
821
|
raise RuntimeError(f"Invalid format {self.out_f.suffix}")
|
818
822
|
|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
3
3
|
|
4
4
|
from functools import partial
|
5
5
|
from pathlib import Path
|
6
|
-
from typing import Any, List, Optional, Tuple
|
6
|
+
from typing import Any, Dict, List, Optional, Tuple
|
7
7
|
|
8
8
|
import anyio
|
9
9
|
import httpx
|
@@ -34,18 +34,26 @@ class DownloadBase:
|
|
34
34
|
retries: int = 3,
|
35
35
|
headers: Optional[dict[Any, Any]] = None,
|
36
36
|
**kwargs: Any,
|
37
|
-
) ->
|
37
|
+
) -> Dict[str, bool]:
|
38
|
+
results: Dict[str, bool] = {}
|
38
39
|
anyio.run(
|
39
40
|
partial(
|
40
|
-
self.download_multiple_files_async,
|
41
|
+
self.download_multiple_files_async,
|
42
|
+
targets,
|
43
|
+
retries,
|
44
|
+
headers,
|
45
|
+
results,
|
46
|
+
**kwargs,
|
41
47
|
)
|
42
48
|
)
|
49
|
+
return results
|
43
50
|
|
44
51
|
async def download_multiple_files_async(
|
45
52
|
self,
|
46
53
|
targets: List[Tuple[str, Path]],
|
47
54
|
retries: int = 3,
|
48
55
|
headers: Optional[dict[Any, Any]] = None,
|
56
|
+
results: Optional[dict[str, bool]] = None,
|
49
57
|
**kwargs: Any,
|
50
58
|
) -> None:
|
51
59
|
# targets format: [(url1, dest2), (url2, dest2), ...]
|
@@ -53,44 +61,56 @@ class DownloadBase:
|
|
53
61
|
("bar", None, {"set_progress_mode": "determinate", "steps": len(targets)})
|
54
62
|
)
|
55
63
|
|
64
|
+
semaphore = anyio.Semaphore(4)
|
65
|
+
|
56
66
|
async with httpx.AsyncClient() as client:
|
57
67
|
async with anyio.create_task_group() as tg:
|
58
68
|
for url, dest in targets:
|
59
69
|
tg.start_soon(
|
60
70
|
self.download_file_async,
|
71
|
+
semaphore,
|
61
72
|
client,
|
62
73
|
url,
|
63
74
|
dest,
|
64
75
|
retries,
|
65
76
|
headers,
|
77
|
+
results,
|
66
78
|
**kwargs,
|
67
79
|
)
|
68
80
|
|
69
81
|
async def download_file_async(
|
70
82
|
self,
|
83
|
+
semaphore: anyio.Semaphore,
|
71
84
|
client: httpx.AsyncClient,
|
72
85
|
url: str,
|
73
86
|
dest: Path,
|
74
87
|
retries: int = 3,
|
75
88
|
headers: Optional[dict[Any, Any]] = None,
|
89
|
+
results: Optional[dict[str, bool]] = None,
|
76
90
|
**kwargs: Any,
|
77
91
|
) -> None:
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
if response.is_success:
|
85
|
-
async with await anyio.open_file(dest, "wb+") as f:
|
86
|
-
await f.write(response.content)
|
87
|
-
self.cb.put(f"Downloaded {url}")
|
88
|
-
else:
|
89
|
-
self.cb.put(
|
90
|
-
f"Error {response.status_code}: {url} (tried {retry+1}/{retries} times)"
|
92
|
+
async with semaphore:
|
93
|
+
self.cb.put(f"Downloading {url}")
|
94
|
+
success = False
|
95
|
+
for retry in range(retries):
|
96
|
+
response = await client.get(
|
97
|
+
url, follow_redirects=True, headers=headers, **kwargs
|
91
98
|
)
|
99
|
+
success = response.is_success
|
100
|
+
|
101
|
+
if success:
|
102
|
+
async with await anyio.open_file(dest, "wb+") as f:
|
103
|
+
await f.write(response.content)
|
104
|
+
self.cb.put(f"Downloaded {url}")
|
105
|
+
else:
|
106
|
+
self.cb.put(
|
107
|
+
f"Error {response.status_code}: {url} (tried {retry+1}/{retries} times)"
|
108
|
+
)
|
109
|
+
|
110
|
+
if results is not None:
|
111
|
+
results[url] = success
|
92
112
|
|
93
|
-
|
113
|
+
self.cb.put("update_bar")
|
94
114
|
|
95
115
|
def download_file(
|
96
116
|
self,
|
@@ -21,10 +21,10 @@ class DownloadDiscord(DownloadBase):
|
|
21
21
|
# def __init__(self, *args: Any, **kwargs: Any) -> None:
|
22
22
|
# super().__init__(*args, **kwargs)
|
23
23
|
|
24
|
-
def download_stickers_discord(self) ->
|
24
|
+
def download_stickers_discord(self) -> Tuple[int, int]:
|
25
25
|
if self.opt_cred is None or self.opt_cred.discord_token == "":
|
26
26
|
self.cb.put("Error: Downloading from Discord requires token")
|
27
|
-
return
|
27
|
+
return 0, 0
|
28
28
|
|
29
29
|
gid: Optional[str] = None
|
30
30
|
if self.url.isnumeric():
|
@@ -36,7 +36,7 @@ class DownloadDiscord(DownloadBase):
|
|
36
36
|
|
37
37
|
if gid is None or gid.isnumeric() is False:
|
38
38
|
self.cb.put("Error: Invalid url")
|
39
|
-
return
|
39
|
+
return 0, 0
|
40
40
|
|
41
41
|
headers = {
|
42
42
|
"Authorization": self.opt_cred.discord_token,
|
@@ -68,7 +68,7 @@ class DownloadDiscord(DownloadBase):
|
|
68
68
|
f_path = Path(self.out_dir, f_name)
|
69
69
|
targets.append((sticker_url, f_path))
|
70
70
|
|
71
|
-
self.download_multiple_files(targets)
|
71
|
+
results = self.download_multiple_files(targets)
|
72
72
|
|
73
73
|
server_name = r_json["name"]
|
74
74
|
MetadataHandler.set_metadata(
|
@@ -78,7 +78,7 @@ class DownloadDiscord(DownloadBase):
|
|
78
78
|
emoji_dict=emoji_dict if self.input_option == "discord" else None,
|
79
79
|
)
|
80
80
|
|
81
|
-
return
|
81
|
+
return sum(results.values()), len(targets)
|
82
82
|
|
83
83
|
@staticmethod
|
84
84
|
def start(
|
@@ -86,6 +86,6 @@ class DownloadDiscord(DownloadBase):
|
|
86
86
|
opt_cred: Optional[CredOption],
|
87
87
|
cb: CallbackProtocol,
|
88
88
|
cb_return: CallbackReturn,
|
89
|
-
) ->
|
89
|
+
) -> Tuple[int, int]:
|
90
90
|
downloader = DownloadDiscord(opt_input, opt_cred, cb, cb_return)
|
91
91
|
return downloader.download_stickers_discord()
|
@@ -34,6 +34,11 @@ class daumtools {
|
|
34
34
|
return dataDict['urlScheme'];
|
35
35
|
}
|
36
36
|
}
|
37
|
+
class document {
|
38
|
+
static querySelectorAll(selectors) {
|
39
|
+
return [];
|
40
|
+
}
|
41
|
+
}
|
37
42
|
"""
|
38
43
|
|
39
44
|
|
@@ -133,9 +138,21 @@ class DownloadKakao(DownloadBase):
|
|
133
138
|
kakao_url = cast(str, ctx.eval(js))
|
134
139
|
item_code = urlparse(kakao_url).path.split("/")[2]
|
135
140
|
|
141
|
+
# Share link redirect to preview link if use desktop headers
|
142
|
+
# This allows us to find pack author
|
143
|
+
headers_desktop = {"User-Agent": "Chrome"}
|
144
|
+
|
145
|
+
response = requests.get(url, headers=headers_desktop, allow_redirects=True)
|
146
|
+
response.url
|
147
|
+
|
148
|
+
pack_title_url = urlparse(response.url).path.split("/")[-1]
|
149
|
+
pack_info_unauthed = MetadataKakao.get_pack_info_unauthed(pack_title_url)
|
150
|
+
if pack_info_unauthed:
|
151
|
+
self.author = pack_info_unauthed["result"]["artist"]
|
152
|
+
|
136
153
|
return pack_title, item_code
|
137
154
|
|
138
|
-
def download_stickers_kakao(self) ->
|
155
|
+
def download_stickers_kakao(self) -> Tuple[int, int]:
|
139
156
|
self.auth_token = None
|
140
157
|
if self.opt_cred:
|
141
158
|
self.auth_token = self.opt_cred.kakao_auth_token
|
@@ -146,7 +163,7 @@ class DownloadKakao(DownloadBase):
|
|
146
163
|
if item_code:
|
147
164
|
return self.download_animated(item_code)
|
148
165
|
self.cb.put("Download failed: Cannot download metadata for sticker pack")
|
149
|
-
return
|
166
|
+
return 0, 0
|
150
167
|
|
151
168
|
if self.url.isnumeric() or self.url.startswith("kakaotalk://store/emoticon/"):
|
152
169
|
item_code = self.url.replace("kakaotalk://store/emoticon/", "")
|
@@ -177,7 +194,7 @@ class DownloadKakao(DownloadBase):
|
|
177
194
|
self.cb.put(
|
178
195
|
"Download failed: Cannot download metadata for sticker pack"
|
179
196
|
)
|
180
|
-
return
|
197
|
+
return 0, 0
|
181
198
|
|
182
199
|
self.author = self.pack_info_unauthed["result"]["artist"]
|
183
200
|
title_ko = self.pack_info_unauthed["result"]["title"]
|
@@ -197,14 +214,15 @@ class DownloadKakao(DownloadBase):
|
|
197
214
|
response = False
|
198
215
|
|
199
216
|
if response is False:
|
200
|
-
return
|
217
|
+
return 0, 0
|
201
218
|
|
202
219
|
return self.download_static(thumbnail_urls)
|
203
220
|
|
204
221
|
self.cb.put("Download failed: Unrecognized URL")
|
205
|
-
return
|
222
|
+
return 0, 0
|
206
223
|
|
207
|
-
def download_static(self, thumbnail_urls: str) ->
|
224
|
+
def download_static(self, thumbnail_urls: str) -> Tuple[int, int]:
|
225
|
+
headers = {"User-Agent": "Android"}
|
208
226
|
MetadataHandler.set_metadata(
|
209
227
|
self.out_dir, title=self.pack_title, author=self.author
|
210
228
|
)
|
@@ -215,11 +233,11 @@ class DownloadKakao(DownloadBase):
|
|
215
233
|
dest = Path(self.out_dir, str(num).zfill(3) + ".png")
|
216
234
|
targets.append((url, dest))
|
217
235
|
|
218
|
-
self.download_multiple_files(targets)
|
236
|
+
results = self.download_multiple_files(targets, headers=headers)
|
219
237
|
|
220
|
-
return
|
238
|
+
return sum(results.values()), len(targets)
|
221
239
|
|
222
|
-
def download_animated(self, item_code: str) ->
|
240
|
+
def download_animated(self, item_code: str) -> Tuple[int, int]:
|
223
241
|
MetadataHandler.set_metadata(
|
224
242
|
self.out_dir, title=self.pack_title, author=self.author
|
225
243
|
)
|
@@ -272,7 +290,7 @@ class DownloadKakao(DownloadBase):
|
|
272
290
|
break
|
273
291
|
if play_ext == "":
|
274
292
|
self.cb.put(f"Failed to determine extension of {item_code}")
|
275
|
-
return
|
293
|
+
return 0, 0
|
276
294
|
else:
|
277
295
|
play_path_format = f"dw/{item_code}.{play_type}_0##{play_ext}"
|
278
296
|
else:
|
@@ -308,7 +326,7 @@ class DownloadKakao(DownloadBase):
|
|
308
326
|
sound_dl_path = Path(self.out_dir, str(num).zfill(3) + sound_ext)
|
309
327
|
targets.append((sound_url, sound_dl_path))
|
310
328
|
|
311
|
-
self.download_multiple_files(targets, headers=headers)
|
329
|
+
results = self.download_multiple_files(targets, headers=headers)
|
312
330
|
|
313
331
|
for target in targets:
|
314
332
|
f_path = target[1]
|
@@ -326,7 +344,7 @@ class DownloadKakao(DownloadBase):
|
|
326
344
|
|
327
345
|
self.cb.put(f"Finished getting {item_code}")
|
328
346
|
|
329
|
-
return
|
347
|
+
return sum(results.values()), len(targets)
|
330
348
|
|
331
349
|
@staticmethod
|
332
350
|
def start(
|
@@ -334,6 +352,6 @@ class DownloadKakao(DownloadBase):
|
|
334
352
|
opt_cred: Optional[CredOption],
|
335
353
|
cb: CallbackProtocol,
|
336
354
|
cb_return: CallbackReturn,
|
337
|
-
) ->
|
355
|
+
) -> Tuple[int, int]:
|
338
356
|
downloader = DownloadKakao(opt_input, opt_cred, cb, cb_return)
|
339
357
|
return downloader.download_stickers_kakao()
|
@@ -400,13 +400,13 @@ class DownloadLine(DownloadBase):
|
|
400
400
|
|
401
401
|
self.cb.put(f"Combined {i.name.replace('-text.png', '.png')}")
|
402
402
|
|
403
|
-
def download_stickers_line(self) ->
|
403
|
+
def download_stickers_line(self) -> Tuple[int, int]:
|
404
404
|
url_data = MetadataLine.analyze_url(self.url)
|
405
405
|
if url_data:
|
406
406
|
self.pack_id, self.region, self.is_emoji = url_data
|
407
407
|
else:
|
408
408
|
self.cb.put("Download failed: Unsupported URL format")
|
409
|
-
return
|
409
|
+
return 0, 0
|
410
410
|
|
411
411
|
if self.is_emoji:
|
412
412
|
metadata = MetadataLine.get_metadata_sticon(self.pack_id, self.region)
|
@@ -423,7 +423,7 @@ class DownloadLine(DownloadBase):
|
|
423
423
|
) = metadata
|
424
424
|
else:
|
425
425
|
self.cb.put("Download failed: Failed to get metadata")
|
426
|
-
return
|
426
|
+
return 0, 0
|
427
427
|
|
428
428
|
MetadataHandler.set_metadata(self.out_dir, title=self.title, author=self.author)
|
429
429
|
|
@@ -434,7 +434,7 @@ class DownloadLine(DownloadBase):
|
|
434
434
|
self.cb.put(f"Downloaded {pack_url}")
|
435
435
|
else:
|
436
436
|
self.cb.put(f"Cannot download {pack_url}")
|
437
|
-
return
|
437
|
+
return 0, 0
|
438
438
|
|
439
439
|
if self.is_emoji:
|
440
440
|
self.decompress_emoticon(zip_file)
|
@@ -458,7 +458,7 @@ class DownloadLine(DownloadBase):
|
|
458
458
|
self.download_multiple_files(custom_sticker_text_urls, headers=self.headers)
|
459
459
|
self.combine_custom_text()
|
460
460
|
|
461
|
-
return
|
461
|
+
return len(self.pack_files), len(self.pack_files)
|
462
462
|
|
463
463
|
@staticmethod
|
464
464
|
def start(
|
@@ -466,6 +466,6 @@ class DownloadLine(DownloadBase):
|
|
466
466
|
opt_cred: Optional[CredOption],
|
467
467
|
cb: CallbackProtocol,
|
468
468
|
cb_return: CallbackReturn,
|
469
|
-
) ->
|
469
|
+
) -> Tuple[int, int]:
|
470
470
|
downloader = DownloadLine(opt_input, opt_cred, cb, cb_return)
|
471
471
|
return downloader.download_stickers_line()
|
@@ -1,6 +1,6 @@
|
|
1
1
|
#!/usr/bin/env python3
|
2
2
|
from pathlib import Path
|
3
|
-
from typing import Dict, Optional
|
3
|
+
from typing import Dict, Optional, Tuple
|
4
4
|
|
5
5
|
import anyio
|
6
6
|
from signalstickers_client.errors import SignalException
|
@@ -62,23 +62,25 @@ class DownloadSignal(DownloadBase):
|
|
62
62
|
self.out_dir, title=pack.title, author=pack.author, emoji_dict=emoji_dict
|
63
63
|
)
|
64
64
|
|
65
|
-
def download_stickers_signal(self) ->
|
66
|
-
if "signal.art" not in self.url
|
65
|
+
def download_stickers_signal(self) -> Tuple[int, int]:
|
66
|
+
if "signal.art" not in self.url or not self.url.startswith(
|
67
|
+
"sgnl://addstickers/"
|
68
|
+
):
|
67
69
|
self.cb.put("Download failed: Unrecognized URL format")
|
68
|
-
return
|
70
|
+
return 0, 0
|
69
71
|
|
70
|
-
pack_id = self.url.split("
|
72
|
+
pack_id = self.url.split("pack_id=")[1].split("&pack_key=")[0]
|
71
73
|
pack_key = self.url.split("&pack_key=")[1]
|
72
74
|
|
73
75
|
try:
|
74
76
|
pack = anyio.run(DownloadSignal.get_pack, pack_id, pack_key)
|
75
77
|
except SignalException as e:
|
76
78
|
self.cb.put(f"Failed to download pack due to {repr(e)}")
|
77
|
-
return
|
79
|
+
return 0, 0
|
78
80
|
|
79
81
|
self.save_stickers(pack)
|
80
82
|
|
81
|
-
return
|
83
|
+
return len(pack.stickers), len(pack.stickers)
|
82
84
|
|
83
85
|
@staticmethod
|
84
86
|
def start(
|
@@ -86,6 +88,6 @@ class DownloadSignal(DownloadBase):
|
|
86
88
|
opt_cred: Optional[CredOption],
|
87
89
|
cb: CallbackProtocol,
|
88
90
|
cb_return: CallbackReturn,
|
89
|
-
) ->
|
91
|
+
) -> Tuple[int, int]:
|
90
92
|
downloader = DownloadSignal(opt_input, opt_cred, cb, cb_return)
|
91
93
|
return downloader.download_stickers_signal()
|
@@ -1,15 +1,13 @@
|
|
1
1
|
#!/usr/bin/env python3
|
2
2
|
from pathlib import Path
|
3
|
-
from typing import
|
3
|
+
from typing import Optional, Tuple
|
4
4
|
from urllib.parse import urlparse
|
5
5
|
|
6
6
|
import anyio
|
7
|
-
from telegram import PhotoSize, Sticker, StickerSet
|
8
|
-
from telegram.error import TelegramError
|
9
|
-
from telegram.ext import AIORateLimiter, ApplicationBuilder
|
10
7
|
|
11
8
|
from sticker_convert.downloaders.download_base import DownloadBase
|
12
9
|
from sticker_convert.job_option import CredOption, InputOption
|
10
|
+
from sticker_convert.utils.auth.telegram_api import BotAPI, TelegramAPI, TelethonAPI
|
13
11
|
from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
|
14
12
|
from sticker_convert.utils.files.metadata_handler import MetadataHandler
|
15
13
|
|
@@ -18,105 +16,33 @@ class DownloadTelegram(DownloadBase):
|
|
18
16
|
# def __init__(self, *args: Any, **kwargs: Any) -> None:
|
19
17
|
# super().__init__(*args, **kwargs)
|
20
18
|
|
21
|
-
def download_stickers_telegram(self) ->
|
22
|
-
self.token = ""
|
23
|
-
|
24
|
-
if self.opt_cred:
|
25
|
-
self.token = self.opt_cred.telegram_token.strip()
|
26
|
-
if not self.token:
|
27
|
-
self.cb.put("Download failed: Token required for downloading from telegram")
|
28
|
-
return False
|
29
|
-
|
19
|
+
def download_stickers_telegram(self) -> Tuple[int, int]:
|
30
20
|
if not ("telegram.me" in self.url or "t.me" in self.url):
|
31
21
|
self.cb.put("Download failed: Unrecognized URL format")
|
32
|
-
return
|
33
|
-
|
34
|
-
self.title = Path(urlparse(self.url).path).name
|
35
|
-
|
36
|
-
self.emoji_dict: Dict[str, str] = {}
|
22
|
+
return 0, 0
|
37
23
|
|
38
24
|
return anyio.run(self.save_stickers)
|
39
25
|
|
40
|
-
async def save_stickers(self) ->
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
.connect_timeout(timeout)
|
47
|
-
.pool_timeout(timeout)
|
48
|
-
.read_timeout(timeout)
|
49
|
-
.write_timeout(timeout)
|
50
|
-
.connection_pool_size(20)
|
51
|
-
.build()
|
52
|
-
)
|
53
|
-
|
54
|
-
async with application:
|
55
|
-
bot = application.bot
|
56
|
-
try:
|
57
|
-
sticker_set: StickerSet = await bot.get_sticker_set(
|
58
|
-
self.title,
|
59
|
-
read_timeout=timeout,
|
60
|
-
write_timeout=timeout,
|
61
|
-
connect_timeout=timeout,
|
62
|
-
pool_timeout=timeout,
|
63
|
-
)
|
64
|
-
except TelegramError as e:
|
65
|
-
self.cb.put(
|
66
|
-
f"Failed to download telegram sticker set {self.title} due to: {e}"
|
67
|
-
)
|
68
|
-
return False
|
69
|
-
|
70
|
-
self.cb.put(
|
71
|
-
(
|
72
|
-
"bar",
|
73
|
-
None,
|
74
|
-
{
|
75
|
-
"set_progress_mode": "determinate",
|
76
|
-
"steps": len(sticker_set.stickers),
|
77
|
-
},
|
78
|
-
)
|
79
|
-
)
|
80
|
-
|
81
|
-
async def download_sticker(
|
82
|
-
sticker: Union[PhotoSize, Sticker], f_id: str
|
83
|
-
) -> None:
|
84
|
-
sticker_file = await sticker.get_file(
|
85
|
-
read_timeout=timeout,
|
86
|
-
write_timeout=timeout,
|
87
|
-
connect_timeout=timeout,
|
88
|
-
pool_timeout=timeout,
|
89
|
-
)
|
90
|
-
fpath = sticker_file.file_path
|
91
|
-
assert fpath is not None
|
92
|
-
ext = Path(fpath).suffix
|
93
|
-
f_name = f_id + ext
|
94
|
-
f_path = Path(self.out_dir, f_name)
|
95
|
-
await sticker_file.download_to_drive(
|
96
|
-
custom_path=f_path,
|
97
|
-
read_timeout=timeout,
|
98
|
-
write_timeout=timeout,
|
99
|
-
connect_timeout=timeout,
|
100
|
-
pool_timeout=timeout,
|
101
|
-
)
|
102
|
-
if isinstance(sticker, Sticker) and sticker.emoji is not None:
|
103
|
-
self.emoji_dict[f_id] = sticker.emoji
|
104
|
-
self.cb.put(f"Downloaded {f_name}")
|
105
|
-
if f_id != "cover":
|
106
|
-
self.cb.put("update_bar")
|
26
|
+
async def save_stickers(self) -> Tuple[int, int]:
|
27
|
+
tg_api: TelegramAPI
|
28
|
+
if self.input_option.endswith("telethon"):
|
29
|
+
tg_api = TelethonAPI()
|
30
|
+
else:
|
31
|
+
tg_api = BotAPI()
|
107
32
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
tg.start_soon(download_sticker, sticker, f_id)
|
33
|
+
if self.opt_cred is None:
|
34
|
+
self.cb.put("Download failed: No credentials")
|
35
|
+
return 0, 0
|
112
36
|
|
113
|
-
|
114
|
-
|
37
|
+
success = await tg_api.setup(self.opt_cred, False, self.cb, self.cb_return)
|
38
|
+
if success is False:
|
39
|
+
self.cb.put("Download failed: Invalid credentials")
|
40
|
+
return 0, 0
|
115
41
|
|
116
|
-
|
117
|
-
|
118
|
-
)
|
119
|
-
return
|
42
|
+
title = Path(urlparse(self.url).path).name
|
43
|
+
results, emoji_dict = await tg_api.pack_dl(title, self.out_dir)
|
44
|
+
MetadataHandler.set_metadata(self.out_dir, title=title, emoji_dict=emoji_dict)
|
45
|
+
return sum(results.values()), len(results)
|
120
46
|
|
121
47
|
@staticmethod
|
122
48
|
def start(
|
@@ -124,6 +50,6 @@ class DownloadTelegram(DownloadBase):
|
|
124
50
|
opt_cred: Optional[CredOption],
|
125
51
|
cb: CallbackProtocol,
|
126
52
|
cb_return: CallbackReturn,
|
127
|
-
) ->
|
53
|
+
) -> Tuple[int, int]:
|
128
54
|
downloader = DownloadTelegram(opt_input, opt_cred, cb, cb_return)
|
129
55
|
return downloader.download_stickers_telegram()
|