sticker-convert 2.10.9__py3-none-any.whl → 2.11.0__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,20 +1,19 @@
1
1
  #!/usr/bin/env python3
2
2
  import copy
3
- import re
4
3
  from pathlib import Path
5
4
  from typing import Any, Dict, List, Optional, Tuple, Union, cast
6
5
 
7
6
  import anyio
8
- from telegram import InputSticker, Sticker
9
- from telegram.error import BadRequest, TelegramError
10
- from telegram.ext import AIORateLimiter, ApplicationBuilder
7
+ from telegram import Sticker
11
8
 
12
9
  from sticker_convert.converter import StickerConvert
13
10
  from sticker_convert.job_option import CompOption, CredOption, OutputOption
14
11
  from sticker_convert.uploaders.upload_base import UploadBase
12
+ from sticker_convert.utils.auth.telegram_api import BotAPI, TelegramAPI, TelegramSticker, TelethonAPI
15
13
  from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
16
14
  from sticker_convert.utils.emoji import extract_emojis
17
15
  from sticker_convert.utils.files.metadata_handler import MetadataHandler
16
+ from sticker_convert.utils.media.codec_info import CodecInfo
18
17
  from sticker_convert.utils.media.format_verify import FormatVerify
19
18
 
20
19
 
@@ -70,256 +69,190 @@ class UploadTelegram(UploadBase):
70
69
 
71
70
  async def upload_pack(
72
71
  self, pack_title: str, stickers: List[Path], emoji_dict: Dict[str, str]
73
- ) -> Optional[str]:
74
- token = self.opt_cred.telegram_token.strip()
75
- assert token
76
- timeout = 10 * len(stickers)
77
-
78
- application = ( # type: ignore
79
- ApplicationBuilder()
80
- .token(self.opt_cred.telegram_token.strip())
81
- .rate_limiter(AIORateLimiter(max_retries=3))
82
- .connect_timeout(timeout)
83
- .pool_timeout(timeout)
84
- .read_timeout(timeout)
85
- .write_timeout(timeout)
86
- .connection_pool_size(len(stickers))
87
- .build()
88
- )
89
-
90
- async with application:
91
- bot = application.bot
92
- pack_short_name = (
93
- pack_title.replace(" ", "_") + "_by_" + bot.name.replace("@", "")
94
- )
95
- pack_short_name = re.sub(
96
- "[^0-9a-zA-Z]+", "_", pack_short_name
97
- ) # name used in url, only alphanum and underscore only
98
-
99
- sticker_set: Any = None
100
- try:
101
- sticker_set = await bot.get_sticker_set(
102
- pack_short_name,
103
- read_timeout=30,
104
- write_timeout=30,
105
- connect_timeout=30,
106
- pool_timeout=30,
72
+ ) -> Tuple[Optional[str], int, int]:
73
+ tg_api: TelegramAPI
74
+ if self.opt_output.option.endswith("telethon"):
75
+ tg_api = TelethonAPI()
76
+ else:
77
+ tg_api = BotAPI()
78
+
79
+ is_emoji = False
80
+ if "emoji" in self.opt_output.option:
81
+ is_emoji = True
82
+
83
+ success = await tg_api.setup(self.opt_cred, True, self.cb, self.cb_return)
84
+ if success is False:
85
+ self.cb.put("Download failed: Invalid credentials")
86
+ return None, len(stickers), 0
87
+
88
+ pack_short_name = await tg_api.set_upload_pack_short_name(pack_title)
89
+ await tg_api.set_upload_pack_type(is_emoji)
90
+ pack_exist = await tg_api.check_pack_exist()
91
+ if pack_exist:
92
+ question = f"Warning: Pack {pack_short_name} already exists.\n"
93
+ question += "Delete all stickers in pack?\n"
94
+ question += "Note: After recreating set, please wait for about 3 minutes for the set to reappear."
95
+
96
+ self.cb.put(
97
+ (
98
+ "ask_bool",
99
+ (question,),
100
+ None,
107
101
  )
108
- except TelegramError:
109
- pass
102
+ )
103
+ if self.cb_return:
104
+ response = self.cb_return.get_response()
105
+ else:
106
+ response = False
107
+
108
+ if response is True:
109
+ self.cb.put(f"Deleting all stickers from pack {pack_short_name}")
110
+ await tg_api.pack_del()
111
+ pack_exist = False
112
+ else:
113
+ self.cb.put(f"Not deleting existing pack {pack_short_name}")
114
+
115
+ if self.opt_output.option == "telegram_emoji":
116
+ sticker_type = Sticker.CUSTOM_EMOJI
117
+ else:
118
+ sticker_type = Sticker.REGULAR
110
119
 
111
- if sticker_set is not None:
112
- question = f"Warning: Pack {pack_short_name} already exists.\n"
113
- question += "Delete all stickers in pack?\n"
114
- question += "Note: After recreating set, please wait for about 3 minutes for the set to reappear."
120
+ stickers_list: List[TelegramSticker] = []
121
+ sticker_format = None
122
+ for src in stickers:
123
+ self.cb.put(f"Verifying {src} for uploading to telegram")
115
124
 
125
+ emoji = extract_emojis(emoji_dict.get(Path(src).stem, ""))
126
+ if emoji == "":
116
127
  self.cb.put(
117
- (
118
- "ask_bool",
119
- (question,),
120
- None,
121
- )
128
+ f"Warning: Cannot find emoji for file {Path(src).name}, using default emoji..."
122
129
  )
123
- if self.cb_return:
124
- response = self.cb_return.get_response()
125
- else:
126
- response = False
127
-
128
- if response is True:
129
- self.cb.put(f"Deleting all stickers from pack {pack_short_name}")
130
- try:
131
- await bot.delete_sticker_set(pack_short_name)
132
- except BadRequest as e:
133
- self.cb.put(
134
- f"Cannot delete sticker set {pack_short_name} due to {e}"
135
- )
136
- if str(e) == "Stickerpack_not_found":
137
- self.cb.put(
138
- "Hint: You might had deleted and recreated pack too quickly. Wait about 3 minutes and try again."
139
- )
140
- return None
141
- except TelegramError as e:
142
- self.cb.put(
143
- f"Cannot delete sticker set {pack_short_name} due to {e}"
144
- )
145
- return None
146
- sticker_set = None
147
- else:
148
- self.cb.put(f"Not deleting existing pack {pack_short_name}")
130
+ emoji_list = [self.opt_comp.default_emoji]
131
+
132
+ if len(emoji) > 20:
133
+ self.cb.put(
134
+ f"Warning: {len(emoji)} emoji for file {Path(src).name}, exceeding limit of 20, keep first 20 only..."
135
+ )
136
+ emoji_list = [*emoji][:20]
137
+
138
+ ext = Path(src).suffix
139
+ if ext == ".tgs":
140
+ spec_choice = self.tgs_spec
141
+ sticker_format = "animated"
142
+ elif ext == ".webm":
143
+ spec_choice = self.webm_spec
144
+ sticker_format = "video"
145
+ else:
146
+ ext = ".png"
147
+ spec_choice = self.png_spec
148
+ sticker_format = "static"
149
149
 
150
150
  if self.opt_output.option == "telegram_emoji":
151
- sticker_type = Sticker.CUSTOM_EMOJI
151
+ spec_choice.set_res(100)
152
+
153
+ file_info = CodecInfo(src)
154
+ check_file_result = (
155
+ FormatVerify.check_file_fps(
156
+ src, fps=spec_choice.get_fps(), file_info=file_info
157
+ )
158
+ and FormatVerify.check_file_duration(
159
+ src, duration=spec_choice.get_duration(), file_info=file_info
160
+ )
161
+ and FormatVerify.check_file_size(
162
+ src, size=spec_choice.get_size_max(), file_info=file_info
163
+ )
164
+ and FormatVerify.check_format(
165
+ src, fmt=spec_choice.get_format(), file_info=file_info
166
+ )
167
+ )
168
+ if sticker_format == "video":
169
+ # For video stickers (Only)
170
+ # Allow file with one of the dimension = 512 but another <512
171
+ # https://core.telegram.org/stickers#video-requirements
172
+ check_file_result = check_file_result and (
173
+ file_info.res[0] == 512 or file_info.res[1] == 512
174
+ )
175
+ check_file_result = check_file_result and (
176
+ file_info.res[0] <= 512 and file_info.res[1] <= 512
177
+ )
152
178
  else:
153
- sticker_type = Sticker.REGULAR
154
-
155
- init_input_stickers: List[InputSticker] = []
156
- extra_input_stickers: List[Tuple[InputSticker, Path]] = []
157
- sticker_format = None
158
- for src in stickers:
159
- self.cb.put(f"Verifying {src} for uploading to telegram")
160
-
161
- emoji = extract_emojis(emoji_dict.get(Path(src).stem, ""))
162
- if emoji == "":
163
- self.cb.put(
164
- f"Warning: Cannot find emoji for file {Path(src).name}, using default emoji..."
165
- )
166
- emoji_list = [self.opt_comp.default_emoji]
167
-
168
- if len(emoji) > 20:
169
- self.cb.put(
170
- f"Warning: {len(emoji)} emoji for file {Path(src).name}, exceeding limit of 20, keep first 20 only..."
171
- )
172
- emoji_list = [*emoji][:20]
173
-
174
- ext = Path(src).suffix
175
- if ext == ".tgs":
176
- spec_choice = self.tgs_spec
177
- sticker_format = "animated"
178
- elif ext == ".webm":
179
- spec_choice = self.webm_spec
180
- sticker_format = "video"
181
- else:
182
- ext = ".png"
183
- spec_choice = self.png_spec
184
- sticker_format = "static"
185
-
186
- if self.opt_output.option == "telegram_emoji":
187
- spec_choice.set_res(100)
188
-
189
- if FormatVerify.check_file(src, spec=spec_choice):
190
- with open(src, "rb") as f:
191
- sticker_bytes = f.read()
192
- else:
193
- _, _, convert_result, _ = StickerConvert.convert(
194
- Path(src),
195
- Path(f"bytes{ext}"),
196
- self.opt_comp_merged,
197
- self.cb,
198
- self.cb_return,
199
- )
200
- sticker_bytes = cast(bytes, convert_result)
179
+ check_file_result = (
180
+ check_file_result
181
+ and file_info.res[0] == 512
182
+ and file_info.res[1] == 512
183
+ )
184
+ # It is important to check if webp and png are static only
185
+ check_file_result = check_file_result and FormatVerify.check_animated(
186
+ src, animated=spec_choice.animated, file_info=file_info
187
+ )
201
188
 
202
- input_sticker = InputSticker(
203
- sticker=sticker_bytes,
204
- emoji_list=emoji_list,
205
- format=sticker_format,
189
+ if check_file_result:
190
+ with open(src, "rb") as f:
191
+ sticker_bytes = f.read()
192
+ else:
193
+ _, _, convert_result, _ = StickerConvert.convert(
194
+ Path(src),
195
+ Path(f"bytes{ext}"),
196
+ self.opt_comp_merged,
197
+ self.cb,
198
+ self.cb_return,
206
199
  )
200
+ sticker_bytes = cast(bytes, convert_result)
207
201
 
208
- if sticker_set is None and len(init_input_stickers) < 50:
209
- init_input_stickers.append(input_sticker)
210
- else:
211
- extra_input_stickers.append((input_sticker, src))
202
+ stickers_list.append((src, sticker_bytes, emoji_list, sticker_format))
212
203
 
213
- if len(init_input_stickers) > 0:
214
- self.cb.put(
215
- f"Creating pack and bulk uploading {len(init_input_stickers)} stickers of {pack_short_name}"
216
- )
217
- try:
218
- await bot.create_new_sticker_set(
219
- user_id=self.telegram_userid,
220
- name=pack_short_name,
221
- title=pack_title,
222
- stickers=init_input_stickers,
223
- sticker_type=sticker_type,
224
- )
225
- sticker_set = True
226
- self.cb.put(
227
- f"Created pack and bulk uploaded {len(init_input_stickers)} stickers of {pack_short_name}"
228
- )
229
- except TelegramError as e:
230
- self.cb.put(
231
- f"Cannot create pack and bulk upload {len(init_input_stickers)} stickers of {pack_short_name} due to {e}"
232
- )
233
- return None
234
-
235
- for input_sticker, src in extra_input_stickers:
236
- try:
237
- # We could use tg.start_soon() here
238
- # But this would disrupt the order of stickers
239
- await bot.add_sticker_to_set(
240
- user_id=self.telegram_userid,
241
- name=pack_short_name,
242
- sticker=input_sticker,
243
- )
244
- self.cb.put(f"Uploaded sticker {src} of {pack_short_name}")
245
- except BadRequest as e:
246
- self.cb.put(
247
- f"Cannot upload sticker {src} of {pack_short_name} due to {e}"
248
- )
249
- if str(e) == "Stickerpack_not_found":
250
- self.cb.put(
251
- "Hint: You might had deleted and recreated pack too quickly. Wait about 3 minutes and try again."
252
- )
253
- except TelegramError as e:
254
- self.cb.put(
255
- f"Cannot upload sticker {src} of {pack_short_name} due to {e}"
256
- )
257
-
258
- cover_path = MetadataHandler.get_cover(self.opt_output.dir)
259
- if cover_path:
260
- thumbnail_bytes: Union[None, bytes, Path] = None
261
- cover_ext = Path(cover_path).suffix
262
-
263
- if cover_ext == ".tgs":
264
- thumbnail_format = "animated"
265
- cover_spec_choice = self.tgs_cover_spec
266
- elif cover_ext == ".webm":
267
- thumbnail_format = "video"
268
- cover_spec_choice = self.webm_cover_spec
269
- else:
270
- cover_ext = ".png"
271
- thumbnail_format = "static"
272
- cover_spec_choice = self.png_cover_spec
273
-
274
- if FormatVerify.check_file(cover_path, spec=cover_spec_choice):
275
- with open(cover_path, "rb") as f:
276
- thumbnail_bytes = f.read()
277
- else:
278
- _, _, thumbnail_bytes, _ = StickerConvert.convert(
204
+ if pack_exist is False:
205
+ stickers_total, stickers_ok = await tg_api.pack_new(
206
+ stickers_list, sticker_type
207
+ )
208
+ pack_exist = True
209
+ else:
210
+ stickers_total, stickers_ok = await tg_api.pack_add(
211
+ stickers_list, sticker_type
212
+ )
213
+
214
+ cover_path = MetadataHandler.get_cover(self.opt_output.dir)
215
+ if cover_path:
216
+ thumbnail_bytes: Union[None, bytes, Path] = None
217
+ cover_ext = Path(cover_path).suffix
218
+
219
+ if cover_ext == ".tgs":
220
+ thumbnail_format = "animated"
221
+ cover_spec_choice = self.tgs_cover_spec
222
+ elif cover_ext == ".webm":
223
+ thumbnail_format = "video"
224
+ cover_spec_choice = self.webm_cover_spec
225
+ else:
226
+ cover_ext = ".png"
227
+ thumbnail_format = "static"
228
+ cover_spec_choice = self.png_cover_spec
229
+
230
+ if FormatVerify.check_file(cover_path, spec=cover_spec_choice):
231
+ with open(cover_path, "rb") as f:
232
+ thumbnail_bytes = f.read()
233
+ else:
234
+ _, _, thumbnail_bytes, _ = cast(
235
+ Tuple[Any, Any, bytes, Any],
236
+ StickerConvert.convert(
279
237
  cover_path,
280
238
  Path(f"bytes{cover_ext}"),
281
239
  self.opt_comp_cover_merged,
282
240
  self.cb,
283
241
  self.cb_return,
284
- )
285
-
286
- try:
287
- self.cb.put(
288
- f"Uploading cover (thumbnail) of pack {pack_short_name}"
289
- )
290
- await bot.set_sticker_set_thumbnail(
291
- name=pack_short_name,
292
- user_id=self.telegram_userid,
293
- thumbnail=thumbnail_bytes,
294
- format=thumbnail_format,
295
- )
296
- self.cb.put(f"Uploaded cover (thumbnail) of pack {pack_short_name}")
297
- except TelegramError as e:
298
- self.cb.put(
299
- f"Cannot upload cover (thumbnail) of pack {pack_short_name} due to {e}"
300
- )
301
-
302
- self.cb.put(f"Finish uploading {pack_short_name}")
242
+ ),
243
+ )
303
244
 
304
- if self.opt_output.option == "telegram_emoji":
305
- result = f"https://t.me/addemoji/{pack_short_name}"
306
- else:
307
- result = f"https://t.me/addstickers/{pack_short_name}"
308
- return result
245
+ await tg_api.pack_thumbnail(
246
+ (cover_path, thumbnail_bytes, [], thumbnail_format)
247
+ )
248
+
249
+ self.cb.put(f"Finish uploading {pack_short_name}")
250
+ await tg_api.exit()
251
+ return await tg_api.get_pack_url(), stickers_total, stickers_ok
309
252
 
310
253
  def upload_stickers_telegram(self) -> Tuple[int, int, List[str]]:
311
254
  urls: List[str] = []
312
255
 
313
- if not (self.opt_cred.telegram_token and self.opt_cred.telegram_userid):
314
- self.cb.put("Token and userid required for uploading to telegram")
315
- return 0, 0, urls
316
-
317
- if self.opt_cred.telegram_userid.isnumeric():
318
- self.telegram_userid = int(self.opt_cred.telegram_userid)
319
- else:
320
- self.cb.put("Invalid userid, should contain numbers only")
321
- return 0, 0, urls
322
-
323
256
  title, _, emoji_dict = MetadataHandler.get_metadata(
324
257
  self.opt_output.dir,
325
258
  title=self.opt_output.title,
@@ -367,11 +300,14 @@ class UploadTelegram(UploadBase):
367
300
  for pack_title, stickers in packs.items():
368
301
  stickers_total += len(stickers)
369
302
  self.cb.put(f"Uploading pack {pack_title}")
370
- result = anyio.run(self.upload_pack, pack_title, stickers, emoji_dict)
303
+ result, stickers_total_pack, stickers_ok_pack = anyio.run(
304
+ self.upload_pack, pack_title, stickers, emoji_dict
305
+ )
371
306
  if result:
372
307
  self.cb.put((result))
373
308
  urls.append(result)
374
- stickers_ok += len(stickers)
309
+ stickers_total += stickers_total_pack
310
+ stickers_ok += stickers_ok_pack
375
311
 
376
312
  return stickers_ok, stickers_total, urls
377
313