sticker-convert 2.10.9__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.
@@ -0,0 +1,668 @@
1
+ #!/usr/bin/env python3
2
+ import re
3
+ import time
4
+ from collections import defaultdict
5
+ from pathlib import Path
6
+ from typing import Any, Dict, List, Optional, Protocol, Tuple, Union, cast
7
+
8
+ import anyio
9
+ from telegram import InputSticker, PhotoSize, Sticker
10
+ from telegram import StickerSet as TGStickerSet
11
+ from telegram.error import BadRequest, TelegramError
12
+ from telegram.ext import AIORateLimiter, ApplicationBuilder
13
+ from telethon.errors.rpcerrorlist import StickersetInvalidError # type: ignore
14
+ from telethon.functions import messages # type: ignore
15
+ from telethon.tl.types.messages import StickerSet as TLStickerSet # type: ignore
16
+ from telethon.types import DocumentAttributeFilename, InputStickerSetShortName, InputStickerSetThumb, Message, TypeDocument # type: ignore
17
+
18
+ from sticker_convert.job_option import CredOption
19
+ from sticker_convert.utils.auth.telethon_setup import TelethonSetup
20
+ from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
21
+
22
+ # sticker_path: Path, sticker_bytes: bytes, emoji_list: List[str], sticker_format: str
23
+ TelegramSticker = Tuple[Path, bytes, List[str], str]
24
+
25
+
26
+ class TelegramAPI(Protocol):
27
+ async def setup(
28
+ self,
29
+ opt_cred: CredOption,
30
+ is_upload: bool,
31
+ cb: CallbackProtocol,
32
+ cb_return: CallbackReturn,
33
+ ) -> bool: ...
34
+ async def exit(self) -> None: ...
35
+ async def set_upload_pack_type(self, is_emoji: bool) -> None: ...
36
+ async def set_upload_pack_short_name(self, pack_title: str) -> str: ...
37
+ async def check_pack_exist(self) -> bool: ...
38
+ async def pack_del(self) -> bool: ...
39
+ async def pack_new(
40
+ self, stickers_list: List[TelegramSticker], sticker_type: str
41
+ ) -> Tuple[int, int]: ...
42
+ async def pack_add(
43
+ self, stickers_list: List[TelegramSticker], sticker_type: str
44
+ ) -> Tuple[int, int]: ...
45
+ async def pack_thumbnail(self, thumbnail: TelegramSticker) -> bool: ...
46
+ async def get_pack_url(self) -> str: ...
47
+ async def pack_dl(
48
+ self, pack_short_name: str, out_dir: Path
49
+ ) -> Tuple[Dict[str, bool], Dict[str, str]]: ...
50
+
51
+
52
+ class BotAPI(TelegramAPI):
53
+ async def setup(
54
+ self,
55
+ opt_cred: CredOption,
56
+ is_upload: bool,
57
+ cb: CallbackProtocol,
58
+ cb_return: CallbackReturn,
59
+ ) -> bool:
60
+ self.timeout = 30
61
+ self.cb = cb
62
+
63
+ if is_upload and not (opt_cred.telegram_token and opt_cred.telegram_userid):
64
+ self.cb.put("Token and userid required for uploading to telegram")
65
+ return False
66
+ elif is_upload is False and not opt_cred.telegram_token:
67
+ self.cb.put("Token required for downloading from telegram")
68
+ return False
69
+
70
+ if opt_cred.telegram_userid.isnumeric():
71
+ self.telegram_userid = int(opt_cred.telegram_userid)
72
+ else:
73
+ self.cb.put("Invalid userid, should contain numbers only")
74
+ return False
75
+
76
+ self.application = ( # type: ignore
77
+ ApplicationBuilder()
78
+ .token(opt_cred.telegram_token)
79
+ .rate_limiter(AIORateLimiter(max_retries=3))
80
+ .connect_timeout(self.timeout)
81
+ .pool_timeout(self.timeout)
82
+ .read_timeout(self.timeout)
83
+ .write_timeout(self.timeout)
84
+ .build()
85
+ )
86
+ await self.application.initialize()
87
+
88
+ return True
89
+
90
+ async def exit(self) -> None:
91
+ await self.application.shutdown()
92
+
93
+ async def set_upload_pack_short_name(self, pack_title: str) -> str:
94
+ self.pack_title = pack_title
95
+ bot_name = self.application.bot.name
96
+ self.pack_short_name = (
97
+ pack_title.replace(" ", "_") + "_by_" + bot_name.replace("@", "")
98
+ )
99
+ self.pack_short_name = re.sub(
100
+ "[^0-9a-zA-Z]+", "_", self.pack_short_name
101
+ ) # name used in url, only alphanum and underscore only
102
+ return self.pack_short_name
103
+
104
+ async def set_upload_pack_type(self, is_emoji: bool) -> None:
105
+ self.is_emoji = is_emoji
106
+
107
+ async def check_pack_exist(self) -> bool:
108
+ sticker_set: Any = None
109
+ try:
110
+ sticker_set = await self.application.bot.get_sticker_set(
111
+ self.pack_short_name,
112
+ read_timeout=30,
113
+ write_timeout=30,
114
+ connect_timeout=30,
115
+ pool_timeout=30,
116
+ )
117
+ except TelegramError:
118
+ pass
119
+
120
+ if sticker_set is not None:
121
+ return True
122
+ return False
123
+
124
+ async def pack_del(self) -> bool:
125
+ try:
126
+ await self.application.bot.delete_sticker_set(self.pack_short_name)
127
+ except BadRequest as e:
128
+ msg = f"Cannot delete sticker set {self.pack_short_name} due to {e}"
129
+ if str(e) == "Stickerpack_not_found":
130
+ msg += "\nHint: You might had deleted and recreated pack too quickly. Wait about 3 minutes and try again."
131
+ self.cb.put(msg)
132
+ return False
133
+ except TelegramError as e:
134
+ self.cb.put(f"Cannot delete sticker set {self.pack_short_name} due to {e}")
135
+ return False
136
+ return True
137
+
138
+ async def pack_new(
139
+ self, stickers_list: List[TelegramSticker], sticker_type: str
140
+ ) -> Tuple[int, int]:
141
+ init_input_stickers: List[InputSticker] = []
142
+ for i in stickers_list[:50]:
143
+ init_input_stickers.append(
144
+ InputSticker(
145
+ sticker=i[1],
146
+ emoji_list=i[2],
147
+ format=i[3],
148
+ )
149
+ )
150
+
151
+ try:
152
+ self.cb.put(
153
+ f"Creating pack and bulk uploading {len(init_input_stickers)} stickers of {self.pack_short_name}"
154
+ )
155
+ await self.application.bot.create_new_sticker_set(
156
+ self.telegram_userid,
157
+ self.pack_short_name,
158
+ self.pack_title,
159
+ init_input_stickers,
160
+ sticker_type,
161
+ )
162
+ self.cb.put(
163
+ f"Created pack and bulk uploaded {len(init_input_stickers)} stickers of {self.pack_short_name}"
164
+ )
165
+ _, success_add = await self.pack_add(stickers_list[50:], sticker_type)
166
+ return len(stickers_list), len(init_input_stickers) + success_add
167
+ except TelegramError as e:
168
+ self.cb.put(
169
+ f"Cannot create pack and bulk upload {len(init_input_stickers)} stickers of {self.pack_short_name} due to {e}"
170
+ )
171
+ return len(stickers_list), 0
172
+
173
+ async def pack_add(
174
+ self, stickers_list: List[TelegramSticker], sticker_type: str
175
+ ) -> Tuple[int, int]:
176
+ stickers_ok = 0
177
+ self.cb.put(
178
+ (
179
+ "bar",
180
+ None,
181
+ {
182
+ "set_progress_mode": "determinate",
183
+ "steps": len(stickers_list),
184
+ },
185
+ )
186
+ )
187
+ for i in stickers_list:
188
+ input_sticker = InputSticker(
189
+ sticker=i[1],
190
+ emoji_list=i[2],
191
+ format=i[3],
192
+ )
193
+ try:
194
+ # We could use tg.start_soon() here
195
+ # But this would disrupt the order of stickers
196
+ await self.application.bot.add_sticker_to_set(
197
+ self.telegram_userid,
198
+ self.pack_short_name,
199
+ input_sticker,
200
+ )
201
+ self.cb.put(f"Uploaded sticker {i[0]} of {self.pack_short_name}")
202
+ stickers_ok += 1
203
+ except BadRequest as e:
204
+ self.cb.put(
205
+ f"Cannot upload sticker {i[0]} of {self.pack_short_name} due to {e}"
206
+ )
207
+ if str(e) == "Stickerpack_not_found":
208
+ self.cb.put(
209
+ "Hint: You might had deleted and recreated pack too quickly. Wait about 3 minutes and try again."
210
+ )
211
+ except TelegramError as e:
212
+ self.cb.put(
213
+ f"Cannot upload sticker {i[0]} of {self.pack_short_name} due to {e}"
214
+ )
215
+ self.cb.put("update_bar")
216
+
217
+ self.cb.put(("bar", None, {"set_progress_mode": "indeterminate"}))
218
+ return len(stickers_list), stickers_ok
219
+
220
+ async def pack_thumbnail(self, thumbnail: TelegramSticker) -> bool:
221
+ try:
222
+ self.cb.put(f"Uploading cover (thumbnail) of pack {self.pack_short_name}")
223
+ await self.application.bot.set_sticker_set_thumbnail(
224
+ self.pack_short_name,
225
+ self.telegram_userid,
226
+ thumbnail[3],
227
+ thumbnail[1],
228
+ )
229
+ self.cb.put(f"Uploaded cover (thumbnail) of pack {self.pack_short_name}")
230
+ return True
231
+ except TelegramError as e:
232
+ self.cb.put(
233
+ f"Cannot upload cover (thumbnail) of pack {self.pack_short_name} due to {e}"
234
+ )
235
+ return False
236
+
237
+ async def get_pack_url(self) -> str:
238
+ if self.is_emoji:
239
+ return f"https://t.me/addemoji/{self.pack_short_name}"
240
+ else:
241
+ return f"https://t.me/addstickers/{self.pack_short_name}"
242
+
243
+ async def _download_sticker(
244
+ self,
245
+ sticker: Union[PhotoSize, Sticker],
246
+ f_id: str,
247
+ out_dir: Path,
248
+ results: Dict[str, bool],
249
+ emoji_dict: Dict[str, str],
250
+ ) -> None:
251
+ try:
252
+ sticker_file = await sticker.get_file(
253
+ read_timeout=self.timeout,
254
+ write_timeout=self.timeout,
255
+ connect_timeout=self.timeout,
256
+ pool_timeout=self.timeout,
257
+ )
258
+ except TelegramError as e:
259
+ self.cb.put(f"Failed to download {f_id}: {str(e)}")
260
+ results[f_id] = False
261
+ return
262
+ fpath = sticker_file.file_path
263
+ assert fpath is not None
264
+ ext = Path(fpath).suffix
265
+ f_name = f_id + ext
266
+ f_path = Path(out_dir, f_name)
267
+ await sticker_file.download_to_drive(
268
+ custom_path=f_path,
269
+ read_timeout=self.timeout,
270
+ write_timeout=self.timeout,
271
+ connect_timeout=self.timeout,
272
+ pool_timeout=self.timeout,
273
+ )
274
+ if isinstance(sticker, Sticker) and sticker.emoji is not None:
275
+ emoji_dict[f_id] = sticker.emoji
276
+ self.cb.put(f"Downloaded {f_name}")
277
+ results[f_id] = True
278
+ if f_id != "cover":
279
+ self.cb.put("update_bar")
280
+
281
+ async def pack_dl(
282
+ self, pack_short_name: str, out_dir: Path
283
+ ) -> Tuple[Dict[str, bool], Dict[str, str]]:
284
+ results: Dict[str, bool] = {}
285
+ emoji_dict: Dict[str, str] = {}
286
+
287
+ try:
288
+ sticker_set: TGStickerSet = await self.application.bot.get_sticker_set(
289
+ pack_short_name,
290
+ read_timeout=self.timeout,
291
+ write_timeout=self.timeout,
292
+ connect_timeout=self.timeout,
293
+ pool_timeout=self.timeout,
294
+ )
295
+ except TelegramError as e:
296
+ self.cb.put(
297
+ f"Failed to download telegram sticker set {pack_short_name} due to: {e}"
298
+ )
299
+ return results, emoji_dict
300
+
301
+ self.cb.put(
302
+ (
303
+ "bar",
304
+ None,
305
+ {
306
+ "set_progress_mode": "determinate",
307
+ "steps": len(sticker_set.stickers),
308
+ },
309
+ )
310
+ )
311
+
312
+ async with anyio.create_task_group() as tg:
313
+ for num, sticker in enumerate(sticker_set.stickers):
314
+ f_id = str(num).zfill(3)
315
+ tg.start_soon(
316
+ self._download_sticker, sticker, f_id, out_dir, results, emoji_dict
317
+ )
318
+
319
+ if sticker_set.thumbnail is not None:
320
+ results_thumb: Dict[str, bool] = {}
321
+ tg.start_soon(
322
+ self._download_sticker,
323
+ sticker_set.thumbnail,
324
+ "cover",
325
+ out_dir,
326
+ results_thumb,
327
+ emoji_dict,
328
+ )
329
+
330
+ return results, emoji_dict
331
+
332
+
333
+ class TelethonAPI(TelegramAPI):
334
+ async def setup(
335
+ self,
336
+ opt_cred: CredOption,
337
+ is_upload: bool,
338
+ cb: CallbackProtocol,
339
+ cb_return: CallbackReturn,
340
+ ) -> bool:
341
+ self.opt_cred = opt_cred
342
+ self.cb = cb
343
+ self.cb_return = cb_return
344
+
345
+ success, self.client, _, _ = await TelethonSetup(
346
+ self.opt_cred, self.cb_ask_str
347
+ ).start_async()
348
+
349
+ return success
350
+
351
+ async def exit(self) -> None:
352
+ self.client.disconnect()
353
+
354
+ def cb_ask_str(
355
+ self, msg: Optional[str] = None, initialvalue: Optional[str] = None
356
+ ) -> str:
357
+ self.cb.put(("ask_str", (msg,), None))
358
+ response = self.cb_return.get_response()
359
+
360
+ assert isinstance(response, str)
361
+ return response
362
+
363
+ async def set_upload_pack_short_name(self, pack_title: str) -> str:
364
+ self.pack_title = pack_title
365
+ self.pack_short_name = re.sub(
366
+ "[^0-9a-zA-Z]+", "_", pack_title
367
+ ) # name used in url, only alphanum and underscore only
368
+ return self.pack_short_name
369
+
370
+ async def set_upload_pack_type(self, is_emoji: bool) -> None:
371
+ self.is_emoji = is_emoji
372
+
373
+ async def check_pack_exist(self) -> bool:
374
+ try:
375
+ await self.client(
376
+ messages.GetStickerSetRequest(
377
+ InputStickerSetShortName(self.pack_short_name), 0
378
+ )
379
+ )
380
+ except StickersetInvalidError:
381
+ return False
382
+
383
+ return True
384
+
385
+ async def _send_and_recv(self, msg: Union[str, Path]) -> str:
386
+ if isinstance(msg, str):
387
+ sent_message = await self.client.send_message("Stickers", msg)
388
+ else:
389
+ sent_message = cast(Message, await self.client.send_file("Stickers", msg)) # type: ignore
390
+
391
+ for _ in range(5):
392
+ last_message = cast(
393
+ List[Message],
394
+ await self.client.get_messages("Stickers", 1), # type: ignore
395
+ )[0]
396
+ if sent_message.id != last_message.id:
397
+ return last_message.message
398
+ time.sleep(1)
399
+
400
+ return "timeout"
401
+
402
+ async def pack_del(self) -> bool:
403
+ msg_fail = "Cannot delete pack of {} due to {}"
404
+ if self.is_emoji:
405
+ repl = await self._send_and_recv("/delemoji")
406
+ else:
407
+ repl = await self._send_and_recv("/delpack")
408
+ if repl != "Choose the sticker set you want to delete.":
409
+ self.cb.put(msg_fail.format(self.pack_short_name, repl))
410
+ return False
411
+ repl = await self._send_and_recv(self.pack_short_name)
412
+ if "Yes, I am totally sure." not in repl:
413
+ self.cb.put(msg_fail.format(self.pack_short_name, repl))
414
+ return False
415
+ repl = await self._send_and_recv("Yes, I am totally sure.")
416
+ if "Done!" not in repl:
417
+ self.cb.put(msg_fail.format(self.pack_short_name, repl))
418
+ return False
419
+
420
+ return True
421
+
422
+ async def pack_new(
423
+ self, stickers_list: List[TelegramSticker], sticker_type: str
424
+ ) -> Tuple[int, int]:
425
+ stickers_ok = 0
426
+ if self.is_emoji:
427
+ repl = await self._send_and_recv("/newemojipack")
428
+ elif stickers_list[0][3] == "static":
429
+ repl = await self._send_and_recv("/newsticker")
430
+ elif stickers_list[0][3] == "video":
431
+ repl = await self._send_and_recv("/newvideo")
432
+ elif stickers_list[0][3] == "animated":
433
+ repl = await self._send_and_recv("/newanimated")
434
+ else:
435
+ self.cb.put(
436
+ f"Cannot upload any sticker to {self.pack_short_name} due to invalid sticker format {stickers_list[0][3]}"
437
+ )
438
+ return len(stickers_list), 0
439
+ if "Yay!" not in repl:
440
+ self.cb.put(f"Cannot upload any sticker due to {repl}")
441
+ return len(stickers_list), 0
442
+
443
+ if self.is_emoji:
444
+ repl = await self._send_and_recv(
445
+ f"{stickers_list[0][3].capitalize()} emoji"
446
+ )
447
+ if "Yay!" not in repl:
448
+ self.cb.put(f"Cannot upload any sticker due to {repl}")
449
+ return len(stickers_list), 0
450
+
451
+ repl = await self._send_and_recv(self.pack_title)
452
+ if "Alright!" not in repl:
453
+ self.cb.put(f"Cannot upload any sticker due to {repl}")
454
+ return len(stickers_list), 0
455
+ self.cb.put(
456
+ (
457
+ "bar",
458
+ None,
459
+ {
460
+ "set_progress_mode": "determinate",
461
+ "steps": len(stickers_list),
462
+ },
463
+ )
464
+ )
465
+ for i in stickers_list:
466
+ repl = await self._send_and_recv(i[0])
467
+ if "Thanks!" not in repl:
468
+ self.cb.put(
469
+ f"Cannot upload sticker {i[0]} of {self.pack_short_name} due to {repl}"
470
+ )
471
+ self.cb.put("update_bar")
472
+ continue
473
+ repl = await self._send_and_recv("".join(i[2]))
474
+ if "Congratulations." not in repl:
475
+ self.cb.put(
476
+ f"Cannot upload sticker {i[0]} of {self.pack_short_name} due to {repl}"
477
+ )
478
+ self.cb.put("update_bar")
479
+ continue
480
+ stickers_ok += 1
481
+ self.cb.put("update_bar")
482
+ repl = await self._send_and_recv("/publish")
483
+ if "icon" not in repl:
484
+ self.cb.put(f"Cannot upload pack {self.pack_short_name} due to {repl}")
485
+ return len(stickers_list), 0
486
+ repl = await self._send_and_recv("/skip")
487
+ if "Please provide a short name" not in repl:
488
+ self.cb.put(f"Cannot upload pack {self.pack_short_name} due to {repl}")
489
+ return len(stickers_list), 0
490
+ repl = await self._send_and_recv(self.pack_short_name)
491
+ if "Kaboom!" not in repl:
492
+ self.cb.put(f"Cannot upload pack {self.pack_short_name} due to {repl}")
493
+ return len(stickers_list), 0
494
+
495
+ self.cb.put(("bar", None, {"set_progress_mode": "indeterminate"}))
496
+
497
+ return len(stickers_list), stickers_ok
498
+
499
+ async def pack_add(
500
+ self, stickers_list: List[TelegramSticker], sticker_type: str
501
+ ) -> Tuple[int, int]:
502
+ stickers_ok = 0
503
+ if self.is_emoji:
504
+ repl = await self._send_and_recv("/addemoji")
505
+ else:
506
+ repl = await self._send_and_recv("/addsticker")
507
+ if "Choose" not in repl:
508
+ self.cb.put(
509
+ f"Cannot upload any sticker to {self.pack_short_name} due to {repl}"
510
+ )
511
+ return len(stickers_list), 0
512
+ repl = await self._send_and_recv(self.pack_short_name)
513
+ if "Alright!" not in repl:
514
+ self.cb.put(
515
+ f"Cannot upload any sticker to {self.pack_short_name} due to {repl}"
516
+ )
517
+ return len(stickers_list), 0
518
+
519
+ self.cb.put(
520
+ (
521
+ "bar",
522
+ None,
523
+ {
524
+ "set_progress_mode": "determinate",
525
+ "steps": len(stickers_list),
526
+ },
527
+ )
528
+ )
529
+ for i in stickers_list:
530
+ repl = await self._send_and_recv(i[0])
531
+ if "Thanks!" not in repl:
532
+ self.cb.put(
533
+ f"Cannot upload sticker {i[0]} of {self.pack_short_name} due to {repl}"
534
+ )
535
+ self.cb.put("update_bar")
536
+ continue
537
+ repl = await self._send_and_recv("".join(i[2]))
538
+ if "There we go." not in repl:
539
+ self.cb.put(
540
+ f"Cannot upload sticker {i[0]} of {self.pack_short_name} due to {repl}"
541
+ )
542
+ self.cb.put("update_bar")
543
+ continue
544
+ self.cb.put("update_bar")
545
+ stickers_ok += 1
546
+
547
+ self.cb.put(("bar", None, {"set_progress_mode": "indeterminate"}))
548
+
549
+ repl = await self._send_and_recv("/done")
550
+ if "OK" not in repl:
551
+ self.cb.put(
552
+ f"Cannot upload any sticker to {self.pack_short_name} due to {repl}"
553
+ )
554
+ return len(stickers_list), 0
555
+
556
+ return len(stickers_list), stickers_ok
557
+
558
+ async def pack_thumbnail(self, thumbnail: TelegramSticker) -> bool:
559
+ repl = await self._send_and_recv("/setpackicon")
560
+ if "OK" not in repl:
561
+ self.cb.put(
562
+ f"Cannot set pack icon for {self.pack_short_name} due to {repl}"
563
+ )
564
+ return False
565
+ repl = await self._send_and_recv(thumbnail[0])
566
+ if "Enjoy!" not in repl:
567
+ self.cb.put(
568
+ f"Cannot set pack icon for {self.pack_short_name} due to {repl}"
569
+ )
570
+ return False
571
+ return True
572
+
573
+ async def get_pack_url(self) -> str:
574
+ if self.is_emoji:
575
+ return f"https://t.me/addemoji/{self.pack_short_name}"
576
+ else:
577
+ return f"https://t.me/addstickers/{self.pack_short_name}"
578
+
579
+ async def _download_sticker(
580
+ self,
581
+ sticker: TypeDocument,
582
+ f_id: str,
583
+ out_dir: Path,
584
+ id_to_emoji: Dict[int, str],
585
+ emoji_dict: Dict[str, str],
586
+ results: Dict[str, bool],
587
+ ) -> None:
588
+ fpath_attr = [
589
+ attr
590
+ for attr in sticker.attributes # type: ignore
591
+ if isinstance(attr, DocumentAttributeFilename)
592
+ ]
593
+ assert len(fpath_attr) > 0
594
+ fpath = fpath_attr[0].file_name
595
+ ext = Path(fpath).suffix
596
+ f_name = f_id + ext
597
+ f_path = Path(out_dir, f_name)
598
+
599
+ try:
600
+ await self.client.download_media(sticker, file=f_path) # type: ignore
601
+ except Exception as e:
602
+ self.cb.put(f"Failed to download {f_id}: {str(e)}")
603
+ results[f_id] = False
604
+ return
605
+
606
+ emoji_dict[f_id] = id_to_emoji[sticker.id]
607
+ self.cb.put(f"Downloaded {f_name}")
608
+ results[f_id] = True
609
+ self.cb.put("update_bar")
610
+
611
+ async def pack_dl(
612
+ self, pack_short_name: str, out_dir: Path
613
+ ) -> Tuple[Dict[str, bool], Dict[str, str]]:
614
+ results: Dict[str, bool] = {}
615
+ emoji_dict: Dict[str, str] = {}
616
+ id_to_emoji: Dict[int, str] = defaultdict(str)
617
+
618
+ sticker_set = cast(
619
+ TLStickerSet,
620
+ await self.client(
621
+ messages.GetStickerSetRequest(
622
+ InputStickerSetShortName(pack_short_name), 0
623
+ )
624
+ ),
625
+ )
626
+
627
+ self.cb.put(
628
+ (
629
+ "bar",
630
+ None,
631
+ {
632
+ "set_progress_mode": "determinate",
633
+ "steps": len(sticker_set.documents),
634
+ },
635
+ )
636
+ )
637
+
638
+ for pack in sticker_set.packs:
639
+ for document_id in pack.documents:
640
+ id_to_emoji[document_id] += pack.emoticon
641
+
642
+ ext = ""
643
+ async with anyio.create_task_group() as tg:
644
+ for num, sticker in enumerate(sticker_set.documents):
645
+ f_id = str(num).zfill(3)
646
+ tg.start_soon(
647
+ self._download_sticker,
648
+ sticker,
649
+ f_id,
650
+ out_dir,
651
+ id_to_emoji,
652
+ emoji_dict,
653
+ results,
654
+ )
655
+
656
+ if sticker_set.set.thumb_version and ext:
657
+ try:
658
+ await self.client.download_file( # type: ignore
659
+ InputStickerSetThumb(
660
+ InputStickerSetShortName(pack_short_name),
661
+ thumb_version=sticker_set.set.thumb_version,
662
+ ),
663
+ f"cover{ext}",
664
+ )
665
+ except Exception as e:
666
+ self.cb.put(f"Failed to download cover{ext}: {str(e)}")
667
+
668
+ return results, emoji_dict