sticker-convert 2.10.8__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.
- 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
@@ -44,7 +44,7 @@ class DownloadViber(DownloadBase):
|
|
44
44
|
|
45
45
|
return title, zip_url
|
46
46
|
|
47
|
-
def decompress(self, zip_file: bytes) ->
|
47
|
+
def decompress(self, zip_file: bytes) -> int:
|
48
48
|
with zipfile.ZipFile(BytesIO(zip_file)) as zf:
|
49
49
|
self.cb.put("Unzipping...")
|
50
50
|
|
@@ -69,19 +69,21 @@ class DownloadViber(DownloadBase):
|
|
69
69
|
|
70
70
|
self.cb.put("update_bar")
|
71
71
|
|
72
|
-
|
72
|
+
return len(zf_files)
|
73
|
+
|
74
|
+
def download_stickers_viber(self) -> Tuple[int, int]:
|
73
75
|
pack_info = self.get_pack_info(self.url)
|
74
76
|
if pack_info is None:
|
75
77
|
self.cb.put("Download failed: Cannot get pack info")
|
76
|
-
return
|
78
|
+
return 0, 0
|
77
79
|
title, zip_url = pack_info
|
78
80
|
|
79
81
|
zip_file = self.download_file(zip_url)
|
80
|
-
self.decompress(zip_file)
|
82
|
+
count = self.decompress(zip_file)
|
81
83
|
|
82
84
|
MetadataHandler.set_metadata(self.out_dir, title=title)
|
83
85
|
|
84
|
-
return
|
86
|
+
return count, count
|
85
87
|
|
86
88
|
@staticmethod
|
87
89
|
def start(
|
@@ -89,6 +91,6 @@ class DownloadViber(DownloadBase):
|
|
89
91
|
opt_cred: Optional[CredOption],
|
90
92
|
cb: CallbackProtocol,
|
91
93
|
cb_return: CallbackReturn,
|
92
|
-
) ->
|
94
|
+
) -> Tuple[int, int]:
|
93
95
|
downloader = DownloadViber(opt_input, opt_cred, cb, cb_return)
|
94
96
|
return downloader.download_stickers_viber()
|
sticker_convert/gui.py
CHANGED
@@ -154,6 +154,8 @@ class GUI(Window):
|
|
154
154
|
self.signal_password_var = StringVar(self)
|
155
155
|
self.telegram_token_var = StringVar(self)
|
156
156
|
self.telegram_userid_var = StringVar(self)
|
157
|
+
self.telethon_api_id_var = IntVar(self)
|
158
|
+
self.telethon_api_hash_var = StringVar(self)
|
157
159
|
self.kakao_auth_token_var = StringVar(self)
|
158
160
|
self.kakao_username_var = StringVar(self)
|
159
161
|
self.kakao_password_var = StringVar(self)
|
@@ -406,6 +408,10 @@ class GUI(Window):
|
|
406
408
|
self.signal_password_var.set(self.creds.get("signal", {}).get("password", ""))
|
407
409
|
self.telegram_token_var.set(self.creds.get("telegram", {}).get("token", ""))
|
408
410
|
self.telegram_userid_var.set(self.creds.get("telegram", {}).get("userid", ""))
|
411
|
+
self.telethon_api_id_var.set(self.creds.get("telethon", {}).get("api_id", 0))
|
412
|
+
self.telethon_api_hash_var.set(
|
413
|
+
self.creds.get("telethon", {}).get("api_hash", "")
|
414
|
+
)
|
409
415
|
self.kakao_auth_token_var.set(self.creds.get("kakao", {}).get("auth_token", ""))
|
410
416
|
self.kakao_username_var.set(self.creds.get("kakao", {}).get("username", ""))
|
411
417
|
self.kakao_password_var.set(self.creds.get("kakao", {}).get("password", ""))
|
@@ -451,6 +457,10 @@ class GUI(Window):
|
|
451
457
|
selection = self.comp_preset_var.get()
|
452
458
|
if selection == "auto":
|
453
459
|
output_option = self.get_output_name()
|
460
|
+
if "telegram_emoji" in output_option:
|
461
|
+
return "telegram_emoji"
|
462
|
+
if "telegram" in output_option:
|
463
|
+
return "telegram"
|
454
464
|
if output_option == "imessage":
|
455
465
|
return "imessage_small"
|
456
466
|
if output_option == "local":
|
@@ -572,6 +582,8 @@ class GUI(Window):
|
|
572
582
|
signal_password=self.signal_password_var.get(),
|
573
583
|
telegram_token=self.telegram_token_var.get(),
|
574
584
|
telegram_userid=self.telegram_userid_var.get(),
|
585
|
+
telethon_api_id=self.telethon_api_id_var.get(),
|
586
|
+
telethon_api_hash=self.telethon_api_hash_var.get(),
|
575
587
|
kakao_auth_token=self.kakao_auth_token_var.get(),
|
576
588
|
kakao_username=self.kakao_username_var.get(),
|
577
589
|
kakao_password=self.kakao_password_var.get(),
|
@@ -10,6 +10,7 @@ from sticker_convert.gui_components.windows.kakao_get_auth_window import KakaoGe
|
|
10
10
|
from sticker_convert.gui_components.windows.line_get_auth_window import LineGetAuthWindow
|
11
11
|
from sticker_convert.gui_components.windows.signal_get_auth_window import SignalGetAuthWindow
|
12
12
|
from sticker_convert.gui_components.windows.viber_get_auth_window import ViberGetAuthWindow
|
13
|
+
from sticker_convert.utils.auth.telethon_setup import TelethonSetup
|
13
14
|
|
14
15
|
if TYPE_CHECKING:
|
15
16
|
from sticker_convert.gui import GUI # type: ignore
|
@@ -77,6 +78,16 @@ class CredFrame(LabelFrame):
|
|
77
78
|
)
|
78
79
|
self.telegram_userid_entry.bind("<Button-3><ButtonRelease-3>", RightClicker)
|
79
80
|
|
81
|
+
self.telethon_auth_lbl = Label(
|
82
|
+
self, text="Telethon authorization", justify="left", anchor="w"
|
83
|
+
)
|
84
|
+
self.telethon_auth_btn = Button(
|
85
|
+
self,
|
86
|
+
text="Generate",
|
87
|
+
command=self.cb_telethon_get_auth,
|
88
|
+
bootstyle="secondary", # type: ignore
|
89
|
+
)
|
90
|
+
|
80
91
|
self.kakao_auth_token_lbl = Label(
|
81
92
|
self, text="Kakao auth_token", justify="left", anchor="w"
|
82
93
|
)
|
@@ -157,19 +168,21 @@ class CredFrame(LabelFrame):
|
|
157
168
|
self.telegram_userid_entry.grid(
|
158
169
|
column=1, row=4, columnspan=2, sticky="w", padx=3, pady=3
|
159
170
|
)
|
160
|
-
self.
|
161
|
-
self.
|
162
|
-
self.
|
163
|
-
self.
|
164
|
-
self.
|
165
|
-
self.
|
166
|
-
self.
|
167
|
-
self.
|
168
|
-
self.
|
169
|
-
self.
|
170
|
-
self.
|
171
|
-
self.
|
172
|
-
self.
|
171
|
+
self.telethon_auth_lbl.grid(column=0, row=5, sticky="w", padx=3, pady=3)
|
172
|
+
self.telethon_auth_btn.grid(column=2, row=5, sticky="e", padx=3, pady=3)
|
173
|
+
self.kakao_auth_token_lbl.grid(column=0, row=6, sticky="w", padx=3, pady=3)
|
174
|
+
self.kakao_auth_token_entry.grid(column=1, row=6, sticky="w", padx=3, pady=3)
|
175
|
+
self.kakao_get_auth_btn.grid(column=2, row=6, sticky="e", padx=3, pady=3)
|
176
|
+
self.line_cookies_lbl.grid(column=0, row=7, sticky="w", padx=3, pady=3)
|
177
|
+
self.line_cookies_entry.grid(column=1, row=7, sticky="w", padx=3, pady=3)
|
178
|
+
self.line_get_auth_btn.grid(column=2, row=7, sticky="e", padx=3, pady=3)
|
179
|
+
self.viber_auth_lbl.grid(column=0, row=8, sticky="w", padx=3, pady=3)
|
180
|
+
self.viber_auth_entry.grid(column=1, row=8, sticky="w", padx=3, pady=3)
|
181
|
+
self.viber_get_auth_btn.grid(column=2, row=8, sticky="e", padx=3, pady=3)
|
182
|
+
self.discord_token_lbl.grid(column=0, row=9, sticky="w", padx=3, pady=3)
|
183
|
+
self.discord_token_entry.grid(column=1, row=9, sticky="w", padx=3, pady=3)
|
184
|
+
self.discord_get_auth_btn.grid(column=2, row=9, sticky="e", padx=3, pady=3)
|
185
|
+
self.help_btn.grid(column=2, row=10, sticky="e", padx=3, pady=3)
|
173
186
|
|
174
187
|
def cb_cred_help(self, *_: Any) -> None:
|
175
188
|
faq_site = "https://github.com/laggykiller/sticker-convert#faq"
|
@@ -177,6 +190,18 @@ class CredFrame(LabelFrame):
|
|
177
190
|
if not success:
|
178
191
|
self.gui.cb_ask_str("You can get help from:", initialvalue=faq_site)
|
179
192
|
|
193
|
+
def cb_telethon_get_auth(self, *_: Any) -> None:
|
194
|
+
success, _client, api_id, api_hash = TelethonSetup(
|
195
|
+
self.gui.get_opt_cred(), self.gui.cb_ask_str
|
196
|
+
).start()
|
197
|
+
if success:
|
198
|
+
self.gui.telethon_api_id_var.set(api_id)
|
199
|
+
self.gui.telethon_api_hash_var.set(api_hash)
|
200
|
+
self.gui.save_creds()
|
201
|
+
self.gui.cb_msg_block("Telethon setup successful")
|
202
|
+
else:
|
203
|
+
self.gui.cb_msg_block("Telethon setup failed")
|
204
|
+
|
180
205
|
def cb_kakao_get_auth(self, *_: Any) -> None:
|
181
206
|
KakaoGetAuthWindow(self.gui)
|
182
207
|
|
sticker_convert/job.py
CHANGED
@@ -216,7 +216,6 @@ class Job:
|
|
216
216
|
self.cb_ask_bool = cb_ask_bool
|
217
217
|
self.cb_ask_str = cb_ask_str
|
218
218
|
|
219
|
-
self.compress_fails: List[str] = []
|
220
219
|
self.out_urls: List[str] = []
|
221
220
|
|
222
221
|
self.executor = Executor(
|
@@ -236,19 +235,21 @@ class Job:
|
|
236
235
|
|
237
236
|
self.executor.cb("msg", kwargs={"cls": True})
|
238
237
|
|
239
|
-
tasks = (
|
238
|
+
tasks: Tuple[Callable[..., Tuple[bool, Optional[str]]], ...] = (
|
240
239
|
self.verify_input,
|
241
240
|
self.cleanup,
|
242
241
|
self.download,
|
243
242
|
self.compress,
|
244
243
|
self.export,
|
245
|
-
self.report,
|
246
244
|
)
|
247
245
|
|
248
246
|
code = 0
|
247
|
+
summaries: List[str] = []
|
249
248
|
for task in tasks:
|
250
249
|
self.executor.cb("bar", kwargs={"set_progress_mode": "indeterminate"})
|
251
|
-
success = task()
|
250
|
+
success, summary = task()
|
251
|
+
if summary is not None:
|
252
|
+
summaries.append(summary)
|
252
253
|
|
253
254
|
if self.executor.is_cancel_job.value == 1: # type: ignore
|
254
255
|
code = 2
|
@@ -258,6 +259,22 @@ class Job:
|
|
258
259
|
self.executor.cb("An error occured during this run.")
|
259
260
|
break
|
260
261
|
|
262
|
+
msg = "##########\n"
|
263
|
+
msg += "Summary:\n"
|
264
|
+
msg += "##########\n"
|
265
|
+
|
266
|
+
msg += "\n"
|
267
|
+
msg += "\n".join(summaries)
|
268
|
+
msg += "\n"
|
269
|
+
|
270
|
+
if self.out_urls:
|
271
|
+
msg += "Export results:\n"
|
272
|
+
msg += "\n".join(self.out_urls)
|
273
|
+
else:
|
274
|
+
msg += "Export result: None"
|
275
|
+
|
276
|
+
self.executor.cb(msg)
|
277
|
+
|
261
278
|
self.executor.cleanup()
|
262
279
|
|
263
280
|
return code
|
@@ -265,7 +282,7 @@ class Job:
|
|
265
282
|
def cancel(self, *_: Any, **_kwargs: Any) -> None:
|
266
283
|
self.executor.kill_workers()
|
267
284
|
|
268
|
-
def verify_input(self) -> bool:
|
285
|
+
def verify_input(self) -> Tuple[bool, None]:
|
269
286
|
info_msg = ""
|
270
287
|
error_msg = ""
|
271
288
|
|
@@ -352,7 +369,7 @@ class Job:
|
|
352
369
|
|
353
370
|
if error_msg != "":
|
354
371
|
self.executor.cb(error_msg)
|
355
|
-
return False
|
372
|
+
return False, None
|
356
373
|
|
357
374
|
# Check if preset not equal to export option
|
358
375
|
# Only warn if the compression option is available in export preset
|
@@ -362,7 +379,10 @@ class Job:
|
|
362
379
|
not self.opt_comp.no_compress
|
363
380
|
and self.opt_output.option != "local"
|
364
381
|
and self.opt_comp.preset != "custom"
|
365
|
-
and
|
382
|
+
and (
|
383
|
+
self.opt_output.option not in self.opt_comp.preset
|
384
|
+
and self.opt_comp.preset not in self.opt_output.option
|
385
|
+
)
|
366
386
|
):
|
367
387
|
msg = "Compression preset does not match export option\n"
|
368
388
|
msg += "You may continue, but the files will need to be compressed again before export\n"
|
@@ -372,7 +392,7 @@ class Job:
|
|
372
392
|
response = self.executor.cb_return.get_response()
|
373
393
|
|
374
394
|
if response is False:
|
375
|
-
return False
|
395
|
+
return False, None
|
376
396
|
|
377
397
|
for param, value in (
|
378
398
|
("fps_power", self.opt_comp.fps_power),
|
@@ -431,7 +451,7 @@ class Job:
|
|
431
451
|
response = self.executor.cb_return.get_response()
|
432
452
|
|
433
453
|
if response is False:
|
434
|
-
return False
|
454
|
+
return False, None
|
435
455
|
|
436
456
|
# Warn about in/output directories that might contain other files
|
437
457
|
# Directory is safe if the name is stickers_input/stickers_output, or
|
@@ -468,13 +488,13 @@ class Job:
|
|
468
488
|
response = self.executor.cb_return.get_response()
|
469
489
|
|
470
490
|
if response is False:
|
471
|
-
return False
|
491
|
+
return False, None
|
472
492
|
|
473
493
|
break
|
474
494
|
|
475
|
-
return True
|
495
|
+
return True, None
|
476
496
|
|
477
|
-
def cleanup(self) -> bool:
|
497
|
+
def cleanup(self) -> Tuple[bool, None]:
|
478
498
|
# If input is 'From local directory', then we should keep files in input/output directory as it maybe edited by user
|
479
499
|
# If input is not 'From local directory', then we should move files in input/output directory as new files will be downloaded
|
480
500
|
# Output directory should be cleanup unless no_compress is true (meaning files in output directory might be edited by user)
|
@@ -523,10 +543,10 @@ class Job:
|
|
523
543
|
new_path = Path(archive_dir, old_path.name)
|
524
544
|
old_path.rename(new_path)
|
525
545
|
|
526
|
-
return True
|
546
|
+
return True, None
|
527
547
|
|
528
|
-
def download(self) -> bool:
|
529
|
-
downloaders: List[Callable[...,
|
548
|
+
def download(self) -> Tuple[bool, str]:
|
549
|
+
downloaders: List[Callable[..., Tuple[int, int]]] = []
|
530
550
|
|
531
551
|
if self.opt_input.option == "signal":
|
532
552
|
downloaders.append(DownloadSignal.start)
|
@@ -534,7 +554,7 @@ class Job:
|
|
534
554
|
if self.opt_input.option == "line":
|
535
555
|
downloaders.append(DownloadLine.start)
|
536
556
|
|
537
|
-
if self.opt_input.option
|
557
|
+
if self.opt_input.option.startswith("telegram"):
|
538
558
|
downloaders.append(DownloadTelegram.start)
|
539
559
|
|
540
560
|
if self.opt_input.option == "kakao":
|
@@ -549,8 +569,8 @@ class Job:
|
|
549
569
|
if len(downloaders) > 0:
|
550
570
|
self.executor.cb("Downloading...")
|
551
571
|
else:
|
552
|
-
self.executor.cb("
|
553
|
-
return True
|
572
|
+
self.executor.cb("Skipped download (No files to download)")
|
573
|
+
return True, "Download: Skipped (No files to download)"
|
554
574
|
|
555
575
|
self.executor.start_workers(processes=1)
|
556
576
|
|
@@ -563,15 +583,24 @@ class Job:
|
|
563
583
|
self.executor.join_workers()
|
564
584
|
|
565
585
|
# Return False if any of the job returns failure
|
586
|
+
stickers_ok = 0
|
587
|
+
stickers_total = 0
|
588
|
+
success = True
|
566
589
|
for result in self.executor.results_list:
|
567
|
-
|
568
|
-
|
590
|
+
stickers_ok += result[0]
|
591
|
+
stickers_total += result[1]
|
592
|
+
success = (
|
593
|
+
success if stickers_ok == stickers_total and stickers_ok > 0 else False
|
594
|
+
)
|
569
595
|
|
570
|
-
return
|
596
|
+
return (
|
597
|
+
success,
|
598
|
+
f"Download: {stickers_ok}/{stickers_total} stickers success",
|
599
|
+
)
|
571
600
|
|
572
|
-
def compress(self) -> bool:
|
601
|
+
def compress(self) -> Tuple[bool, str]:
|
573
602
|
if self.opt_comp.no_compress is True:
|
574
|
-
self.executor.cb("no_compress is set to True
|
603
|
+
self.executor.cb("Skipped compression (no_compress is set to True)")
|
575
604
|
in_dir_files = [
|
576
605
|
i
|
577
606
|
for i in sorted(self.opt_input.dir.iterdir())
|
@@ -598,7 +627,7 @@ class Job:
|
|
598
627
|
src_f = Path(self.opt_input.dir, i.name)
|
599
628
|
dst_f = Path(self.opt_output.dir, i.name)
|
600
629
|
shutil.copy(src_f, dst_f)
|
601
|
-
return True
|
630
|
+
return True, "Compress: Skipped (no_compress is set to True)"
|
602
631
|
msg = "Compressing..."
|
603
632
|
|
604
633
|
input_dir = Path(self.opt_input.dir)
|
@@ -620,8 +649,8 @@ class Job:
|
|
620
649
|
|
621
650
|
in_fs_count = len(in_fs)
|
622
651
|
if in_fs_count == 0:
|
623
|
-
self.executor.cb("No files to compress")
|
624
|
-
return True
|
652
|
+
self.executor.cb("Skipped compression (No files to compress)")
|
653
|
+
return True, "Compress: Skipped (No files to compress)"
|
625
654
|
|
626
655
|
self.executor.cb(msg)
|
627
656
|
self.executor.cb(
|
@@ -640,21 +669,35 @@ class Job:
|
|
640
669
|
|
641
670
|
self.executor.join_workers()
|
642
671
|
|
643
|
-
|
672
|
+
success = True
|
673
|
+
stickers_ok = 0
|
674
|
+
stickers_total = 0
|
675
|
+
fails: List[str] = []
|
644
676
|
for result in self.executor.results_list:
|
677
|
+
stickers_total += 1
|
645
678
|
if result[0] is False:
|
646
|
-
|
679
|
+
success = False
|
680
|
+
fails.append(str(result[1]))
|
681
|
+
else:
|
682
|
+
stickers_ok += 1
|
647
683
|
|
648
|
-
|
684
|
+
msg_append = ""
|
685
|
+
if success is False:
|
686
|
+
msg_append = " (Failed: " + ", ".join(fails) + ")"
|
649
687
|
|
650
|
-
|
688
|
+
return (
|
689
|
+
success,
|
690
|
+
f"Compress: {stickers_ok}/{stickers_total} stickers success" + msg_append,
|
691
|
+
)
|
692
|
+
|
693
|
+
def export(self) -> Tuple[bool, str]:
|
651
694
|
if self.opt_output.option == "local":
|
652
|
-
self.executor.cb("Saving to local directory only
|
653
|
-
return True
|
695
|
+
self.executor.cb("Skipped export (Saving to local directory only)")
|
696
|
+
return True, "Export: Skipped (Saving to local directory only)"
|
654
697
|
|
655
698
|
self.executor.cb("Exporting...")
|
656
699
|
|
657
|
-
exporters: List[Callable[..., List[str]]] = []
|
700
|
+
exporters: List[Callable[..., Tuple[int, int, List[str]]]] = []
|
658
701
|
|
659
702
|
if self.opt_output.option == "whatsapp":
|
660
703
|
exporters.append(CompressWastickers.start)
|
@@ -662,10 +705,7 @@ class Job:
|
|
662
705
|
if self.opt_output.option == "signal":
|
663
706
|
exporters.append(UploadSignal.start)
|
664
707
|
|
665
|
-
if self.opt_output.option
|
666
|
-
exporters.append(UploadTelegram.start)
|
667
|
-
|
668
|
-
if self.opt_output.option == "telegram_emoji":
|
708
|
+
if self.opt_output.option.startswith("telegram"):
|
669
709
|
exporters.append(UploadTelegram.start)
|
670
710
|
|
671
711
|
if self.opt_output.option == "imessage":
|
@@ -684,8 +724,12 @@ class Job:
|
|
684
724
|
|
685
725
|
self.executor.join_workers()
|
686
726
|
|
727
|
+
stickers_ok = 0
|
728
|
+
stickers_total = 0
|
687
729
|
for result in self.executor.results_list:
|
688
|
-
|
730
|
+
stickers_ok += result[0]
|
731
|
+
stickers_total += result[1]
|
732
|
+
self.out_urls.extend(result[2])
|
689
733
|
|
690
734
|
if self.out_urls:
|
691
735
|
with open(
|
@@ -694,29 +738,6 @@ class Job:
|
|
694
738
|
f.write("\n".join(self.out_urls))
|
695
739
|
else:
|
696
740
|
self.executor.cb("An error occured while exporting stickers")
|
697
|
-
return False
|
698
|
-
|
699
|
-
return True
|
700
|
-
|
701
|
-
def report(self) -> bool:
|
702
|
-
msg = "##########\n"
|
703
|
-
msg += "Summary:\n"
|
704
|
-
msg += "##########\n"
|
705
|
-
msg += "\n"
|
706
|
-
|
707
|
-
if self.compress_fails:
|
708
|
-
msg += f'Warning: Could not compress the following {len(self.compress_fails)} file{"s" if len(self.compress_fails) > 1 else ""}:\n'
|
709
|
-
msg += "\n".join(self.compress_fails)
|
710
|
-
msg += "\n"
|
711
|
-
msg += "\nConsider adjusting compression parameters"
|
712
|
-
msg += "\n"
|
713
|
-
|
714
|
-
if self.out_urls:
|
715
|
-
msg += "Export results:\n"
|
716
|
-
msg += "\n".join(self.out_urls)
|
717
|
-
else:
|
718
|
-
msg += "Export result: None"
|
719
|
-
|
720
|
-
self.executor.cb(msg)
|
741
|
+
return False, f"Export: {stickers_ok}/{stickers_total} stickers success"
|
721
742
|
|
722
|
-
return True
|
743
|
+
return True, f"Export: {stickers_ok}/{stickers_total} stickers success"
|
sticker_convert/job_option.py
CHANGED
@@ -214,6 +214,8 @@ class CredOption(BaseOption):
|
|
214
214
|
signal_password: str = ""
|
215
215
|
telegram_token: str = ""
|
216
216
|
telegram_userid: str = ""
|
217
|
+
telethon_api_id: int = 0
|
218
|
+
telethon_api_hash: str = ""
|
217
219
|
kakao_auth_token: str = ""
|
218
220
|
kakao_username: str = ""
|
219
221
|
kakao_password: str = ""
|
@@ -227,6 +229,10 @@ class CredOption(BaseOption):
|
|
227
229
|
return {
|
228
230
|
"signal": {"uuid": self.signal_uuid, "password": self.signal_password},
|
229
231
|
"telegram": {"token": self.telegram_token, "userid": self.telegram_userid},
|
232
|
+
"telethon": {
|
233
|
+
"api_id": self.telethon_api_id,
|
234
|
+
"api_hash": self.telethon_api_hash,
|
235
|
+
},
|
230
236
|
"kakao": {
|
231
237
|
"auth_token": self.kakao_auth_token,
|
232
238
|
"username": self.kakao_username,
|
@@ -59,7 +59,8 @@
|
|
59
59
|
"signal_password": "Set Signal password. Required for uploading Signal stickers.",
|
60
60
|
"signal_get_auth": "Generate Signal uuid and password.",
|
61
61
|
"telegram_token": "Set Telegram token. Required for uploading and downloading Telegram stickers.",
|
62
|
-
"telegram_userid": "Set
|
62
|
+
"telegram_userid": "Set Telegram user_id (From real account, not bot account). Required for uploading Telegram stickers.",
|
63
|
+
"telethon_setup": "Setup Telethon",
|
63
64
|
"kakao_auth_token": "Set Kakao auth_token. Required for downloading animated stickers from https://e.kakao.com/t/xxxxx",
|
64
65
|
"kakao_get_auth": "Generate Kakao auth_token by simulating login. Kakao username, password, country code and phone number are also required.",
|
65
66
|
"kakao_get_auth_desktop": "Get Kakao auth_token from Kakao Desktop application.\n(Only working on Windows.)",
|
@@ -75,6 +76,6 @@
|
|
75
76
|
"viber_bin_path": "Specify location of Viber Desktop application.\nUseful for portable installation.",
|
76
77
|
"discord_get_auth": "Get Discord token.",
|
77
78
|
"discord_token": "Set Discord token. Required for downloading Discord stickers and emojis.",
|
78
|
-
"save_cred": "Save
|
79
|
+
"save_cred": "Save credentials."
|
79
80
|
}
|
80
81
|
}
|
@@ -29,6 +29,16 @@
|
|
29
29
|
"author": false
|
30
30
|
}
|
31
31
|
},
|
32
|
+
"telegram_telethon": {
|
33
|
+
"full_name": "Download from Telegram with Telethon",
|
34
|
+
"help": "Download telegram stickers from a URL as input with Telethon",
|
35
|
+
"example": "Example: https://telegram.me/addstickers/xxxxx\n OR https://telegram.me/addemoji/xxxxx",
|
36
|
+
"address_lbls": "URL address",
|
37
|
+
"metadata_provides": {
|
38
|
+
"title": true,
|
39
|
+
"author": false
|
40
|
+
}
|
41
|
+
},
|
32
42
|
"line": {
|
33
43
|
"full_name": "Download from Line",
|
34
44
|
"help": "Download line stickers from a URL / ID as input",
|
@@ -23,6 +23,22 @@
|
|
23
23
|
"author": false
|
24
24
|
}
|
25
25
|
},
|
26
|
+
"telegram_telethon": {
|
27
|
+
"full_name": "Upload to Telegram with Telethon",
|
28
|
+
"help": "Upload to Telegram with Telethon *Not recommended, but allow link not end with _by_xxxbot*",
|
29
|
+
"metadata_requirements": {
|
30
|
+
"title": true,
|
31
|
+
"author": false
|
32
|
+
}
|
33
|
+
},
|
34
|
+
"telegram_emoji_telethon": {
|
35
|
+
"full_name": "Upload to Telegram with Telethon (Custom emoji)",
|
36
|
+
"help": "Upload to Telegram with Telethon (Custom emoji) *Not recommended, but allow link not end with _by_xxxbot*",
|
37
|
+
"metadata_requirements": {
|
38
|
+
"title": true,
|
39
|
+
"author": false
|
40
|
+
}
|
41
|
+
},
|
26
42
|
"viber": {
|
27
43
|
"full_name": "Upload to Viber",
|
28
44
|
"help": "Upload to Viber",
|
@@ -3,7 +3,7 @@ import copy
|
|
3
3
|
import shutil
|
4
4
|
import zipfile
|
5
5
|
from pathlib import Path
|
6
|
-
from typing import Any, List
|
6
|
+
from typing import Any, List, Tuple
|
7
7
|
|
8
8
|
from sticker_convert.converter import StickerConvert
|
9
9
|
from sticker_convert.job_option import CompOption, CredOption, OutputOption
|
@@ -47,7 +47,7 @@ class CompressWastickers(UploadBase):
|
|
47
47
|
self.opt_comp_merged = copy.deepcopy(self.opt_comp)
|
48
48
|
self.opt_comp_merged.merge(self.base_spec)
|
49
49
|
|
50
|
-
def compress_wastickers(self) -> List[str]:
|
50
|
+
def compress_wastickers(self) -> Tuple[int, int, List[str]]:
|
51
51
|
urls: List[str] = []
|
52
52
|
title, author, _ = MetadataHandler.get_metadata(
|
53
53
|
self.opt_output.dir,
|
@@ -56,10 +56,10 @@ class CompressWastickers(UploadBase):
|
|
56
56
|
)
|
57
57
|
if not title:
|
58
58
|
self.cb.put("Title is required for compressing .wastickers")
|
59
|
-
return urls
|
59
|
+
return 0, 0, urls
|
60
60
|
if not author:
|
61
61
|
self.cb.put("Author is required for compressing .wastickers")
|
62
|
-
return urls
|
62
|
+
return 0, 0, urls
|
63
63
|
packs = MetadataHandler.split_sticker_packs(
|
64
64
|
self.opt_output.dir,
|
65
65
|
title=title,
|
@@ -67,7 +67,9 @@ class CompressWastickers(UploadBase):
|
|
67
67
|
separate_image_anim=not self.opt_comp.fake_vid,
|
68
68
|
)
|
69
69
|
|
70
|
+
stickers_total = 0
|
70
71
|
for pack_title, stickers in packs.items():
|
72
|
+
stickers_total += len(stickers)
|
71
73
|
# Originally the Sticker Maker application name the files with int(time.time())
|
72
74
|
with CacheStore.get_cache_store(path=self.opt_comp.cache_dir) as tempdir:
|
73
75
|
for num, src in enumerate(stickers):
|
@@ -106,7 +108,7 @@ class CompressWastickers(UploadBase):
|
|
106
108
|
self.cb.put((out_f))
|
107
109
|
urls.append(out_f)
|
108
110
|
|
109
|
-
return urls
|
111
|
+
return stickers_total, stickers_total, urls
|
110
112
|
|
111
113
|
def add_metadata(self, pack_dir: Path, title: str, author: str) -> None:
|
112
114
|
opt_comp_merged = copy.deepcopy(self.opt_comp)
|
@@ -150,6 +152,6 @@ class CompressWastickers(UploadBase):
|
|
150
152
|
opt_cred: CredOption,
|
151
153
|
cb: CallbackProtocol,
|
152
154
|
cb_return: CallbackReturn,
|
153
|
-
) -> List[str]:
|
155
|
+
) -> Tuple[int, int, List[str]]:
|
154
156
|
exporter = CompressWastickers(opt_output, opt_comp, opt_cred, cb, cb_return)
|
155
157
|
return exporter.compress_wastickers()
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env python3
|
2
2
|
import copy
|
3
3
|
from pathlib import Path
|
4
|
-
from typing import Any, Dict, List
|
4
|
+
from typing import Any, Dict, List, Tuple
|
5
5
|
|
6
6
|
import anyio
|
7
7
|
from signalstickers_client.errors import SignalException
|
@@ -91,15 +91,15 @@ class UploadSignal(UploadBase):
|
|
91
91
|
|
92
92
|
pack._addsticker(sticker) # type: ignore
|
93
93
|
|
94
|
-
def upload_stickers_signal(self) -> List[str]:
|
94
|
+
def upload_stickers_signal(self) -> Tuple[int, int, List[str]]:
|
95
95
|
urls: List[str] = []
|
96
96
|
|
97
97
|
if not self.opt_cred.signal_uuid:
|
98
98
|
self.cb.put("uuid required for uploading to Signal")
|
99
|
-
return urls
|
99
|
+
return 0, 0, urls
|
100
100
|
if not self.opt_cred.signal_password:
|
101
101
|
self.cb.put("password required for uploading to Signal")
|
102
|
-
return urls
|
102
|
+
return 0, 0, urls
|
103
103
|
|
104
104
|
title, author, emoji_dict = MetadataHandler.get_metadata(
|
105
105
|
self.opt_output.dir,
|
@@ -138,7 +138,10 @@ class UploadSignal(UploadBase):
|
|
138
138
|
file_per_pack=200,
|
139
139
|
separate_image_anim=False,
|
140
140
|
)
|
141
|
+
stickers_total = 0
|
142
|
+
stickers_ok = 0
|
141
143
|
for pack_title, stickers in packs.items():
|
144
|
+
stickers_total += len(stickers)
|
142
145
|
pack = LocalStickerPack()
|
143
146
|
pack.title = pack_title
|
144
147
|
pack.author = author
|
@@ -155,11 +158,12 @@ class UploadSignal(UploadBase):
|
|
155
158
|
)
|
156
159
|
self.cb.put((result))
|
157
160
|
urls.append(result)
|
161
|
+
stickers_ok += len(stickers)
|
158
162
|
|
159
163
|
except SignalException as e:
|
160
164
|
self.cb.put(f"Failed to upload pack {pack_title} due to {repr(e)}")
|
161
165
|
|
162
|
-
return urls
|
166
|
+
return stickers_ok, stickers_total, urls
|
163
167
|
|
164
168
|
@staticmethod
|
165
169
|
def start(
|
@@ -168,6 +172,6 @@ class UploadSignal(UploadBase):
|
|
168
172
|
opt_cred: CredOption,
|
169
173
|
cb: CallbackProtocol,
|
170
174
|
cb_return: CallbackReturn,
|
171
|
-
) -> List[str]:
|
175
|
+
) -> Tuple[int, int, List[str]]:
|
172
176
|
exporter = UploadSignal(opt_output, opt_comp, opt_cred, cb, cb_return)
|
173
177
|
return exporter.upload_stickers_signal()
|