sticker-convert 2.8.0__py3-none-any.whl → 2.8.1__py3-none-any.whl

Sign up to get free protection for your applications and to get access to all the features.
@@ -4,7 +4,6 @@ from fractions import Fraction
4
4
  from io import BytesIO
5
5
  from math import ceil, floor
6
6
  from pathlib import Path
7
- from queue import Queue
8
7
  from typing import TYPE_CHECKING, Any, Dict, List, Literal, Optional, Tuple, Union, cast
9
8
 
10
9
  import numpy as np
@@ -12,7 +11,7 @@ from PIL import Image
12
11
  from PIL import __version__ as PillowVersion
13
12
 
14
13
  from sticker_convert.job_option import CompOption
15
- from sticker_convert.utils.callback import Callback, CallbackReturn, CbQueueItemType
14
+ from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
16
15
  from sticker_convert.utils.files.cache_store import CacheStore
17
16
  from sticker_convert.utils.media.codec_info import CodecInfo, rounding
18
17
  from sticker_convert.utils.media.format_verify import FormatVerify
@@ -120,7 +119,7 @@ class StickerConvert:
120
119
  in_f: Union[Path, Tuple[Path, bytes]],
121
120
  out_f: Path,
122
121
  opt_comp: CompOption,
123
- cb: "Union[Queue[CbQueueItemType], Callback]",
122
+ cb: CallbackProtocol,
124
123
  # cb_return: CallbackReturn
125
124
  ) -> None:
126
125
  self.in_f: Union[bytes, Path]
@@ -186,7 +185,7 @@ class StickerConvert:
186
185
  in_f: Union[Path, Tuple[Path, bytes]],
187
186
  out_f: Path,
188
187
  opt_comp: CompOption,
189
- cb: "Union[Queue[CbQueueItemType], Callback]",
188
+ cb: CallbackProtocol,
190
189
  _cb_return: CallbackReturn,
191
190
  ) -> Tuple[bool, Path, Union[None, bytes, Path], int]:
192
191
  sticker = StickerConvert(in_f, out_f, opt_comp, cb)
@@ -2,13 +2,12 @@
2
2
  from __future__ import annotations
3
3
 
4
4
  from pathlib import Path
5
- from queue import Queue
6
- from typing import Any, List, Optional, Tuple, Union
5
+ from typing import Any, List, Optional, Tuple
7
6
 
8
7
  import requests
9
8
 
10
9
  from sticker_convert.job_option import CredOption
11
- from sticker_convert.utils.callback import Callback, CallbackReturn, CbQueueItemType
10
+ from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
12
11
 
13
12
 
14
13
  class DownloadBase:
@@ -17,10 +16,7 @@ class DownloadBase:
17
16
  url: str,
18
17
  out_dir: Path,
19
18
  opt_cred: Optional[CredOption],
20
- cb: Union[
21
- Queue[CbQueueItemType],
22
- Callback,
23
- ],
19
+ cb: CallbackProtocol,
24
20
  cb_return: CallbackReturn,
25
21
  ) -> None:
26
22
  self.url = url
@@ -5,8 +5,7 @@ import json
5
5
  import zipfile
6
6
  from io import BytesIO
7
7
  from pathlib import Path
8
- from queue import Queue
9
- from typing import Any, List, Optional, Tuple, Union
8
+ from typing import Any, List, Optional, Tuple
10
9
  from urllib.parse import urlparse
11
10
 
12
11
  import requests
@@ -15,7 +14,7 @@ from bs4.element import Tag
15
14
 
16
15
  from sticker_convert.downloaders.download_base import DownloadBase
17
16
  from sticker_convert.job_option import CredOption
18
- from sticker_convert.utils.callback import Callback, CallbackReturn, CbQueueItemType
17
+ from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
19
18
  from sticker_convert.utils.files.metadata_handler import MetadataHandler
20
19
  from sticker_convert.utils.media.decrypt_kakao import DecryptKakao
21
20
 
@@ -249,7 +248,7 @@ class DownloadKakao(DownloadBase):
249
248
  url: str,
250
249
  out_dir: Path,
251
250
  opt_cred: Optional[CredOption],
252
- cb: "Union[Queue[CbQueueItemType], Callback]",
251
+ cb: CallbackProtocol,
253
252
  cb_return: CallbackReturn,
254
253
  ) -> bool:
255
254
  downloader = DownloadKakao(url, out_dir, opt_cred, cb, cb_return)
@@ -7,8 +7,7 @@ import string
7
7
  import zipfile
8
8
  from io import BytesIO
9
9
  from pathlib import Path
10
- from queue import Queue
11
- from typing import Any, Dict, List, Optional, Tuple, Union
10
+ from typing import Any, Dict, List, Optional, Tuple
12
11
  from urllib import parse
13
12
 
14
13
  import requests
@@ -18,7 +17,7 @@ from PIL import Image
18
17
  from sticker_convert.downloaders.download_base import DownloadBase
19
18
  from sticker_convert.job_option import CredOption
20
19
  from sticker_convert.utils.auth.get_line_auth import GetLineAuth
21
- from sticker_convert.utils.callback import Callback, CallbackReturn, CbQueueItemType
20
+ from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
22
21
  from sticker_convert.utils.files.metadata_handler import MetadataHandler
23
22
  from sticker_convert.utils.media.apple_png_normalize import ApplePngNormalize
24
23
 
@@ -466,7 +465,7 @@ class DownloadLine(DownloadBase):
466
465
  url: str,
467
466
  out_dir: Path,
468
467
  opt_cred: Optional[CredOption],
469
- cb: "Union[Queue[CbQueueItemType], Callback]",
468
+ cb: CallbackProtocol,
470
469
  cb_return: CallbackReturn,
471
470
  ) -> bool:
472
471
  downloader = DownloadLine(url, out_dir, opt_cred, cb, cb_return)
@@ -1,7 +1,6 @@
1
1
  #!/usr/bin/env python3
2
2
  from pathlib import Path
3
- from queue import Queue
4
- from typing import Dict, Optional, Union
3
+ from typing import Dict, Optional
5
4
 
6
5
  import anyio
7
6
  from signalstickers_client import StickersClient # type: ignore
@@ -10,7 +9,7 @@ from signalstickers_client.models import StickerPack # type: ignore
10
9
 
11
10
  from sticker_convert.downloaders.download_base import DownloadBase
12
11
  from sticker_convert.job_option import CredOption
13
- from sticker_convert.utils.callback import Callback, CallbackReturn, CbQueueItemType
12
+ from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
14
13
  from sticker_convert.utils.files.metadata_handler import MetadataHandler
15
14
  from sticker_convert.utils.media.codec_info import CodecInfo
16
15
 
@@ -86,7 +85,7 @@ class DownloadSignal(DownloadBase):
86
85
  url: str,
87
86
  out_dir: Path,
88
87
  opt_cred: Optional[CredOption],
89
- cb: "Union[Queue[CbQueueItemType], Callback]",
88
+ cb: CallbackProtocol,
90
89
  cb_return: CallbackReturn,
91
90
  ) -> bool:
92
91
  downloader = DownloadSignal(url, out_dir, opt_cred, cb, cb_return)
@@ -1,6 +1,5 @@
1
1
  #!/usr/bin/env python3
2
2
  from pathlib import Path
3
- from queue import Queue
4
3
  from typing import Dict, Optional, Union
5
4
  from urllib.parse import urlparse
6
5
 
@@ -11,7 +10,7 @@ from telegram.ext import AIORateLimiter, ApplicationBuilder
11
10
 
12
11
  from sticker_convert.downloaders.download_base import DownloadBase
13
12
  from sticker_convert.job_option import CredOption
14
- from sticker_convert.utils.callback import Callback, CallbackReturn, CbQueueItemType
13
+ from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
15
14
  from sticker_convert.utils.files.metadata_handler import MetadataHandler
16
15
 
17
16
 
@@ -124,7 +123,7 @@ class DownloadTelegram(DownloadBase):
124
123
  url: str,
125
124
  out_dir: Path,
126
125
  opt_cred: Optional[CredOption],
127
- cb: "Union[Queue[CbQueueItemType], Callback]",
126
+ cb: CallbackProtocol,
128
127
  cb_return: CallbackReturn,
129
128
  ) -> bool:
130
129
  downloader = DownloadTelegram(url, out_dir, opt_cred, cb, cb_return)
sticker_convert/job.py CHANGED
@@ -5,12 +5,10 @@ import os
5
5
  import shutil
6
6
  import traceback
7
7
  from datetime import datetime
8
- from multiprocessing import Process, Value
9
- from multiprocessing.managers import ListProxy, SyncManager
8
+ from multiprocessing import Manager, Process, Value
10
9
  from pathlib import Path
11
- from queue import Queue
12
10
  from threading import Thread
13
- from typing import TYPE_CHECKING, Any, Callable, Dict, Generator, List, Optional, Tuple
11
+ from typing import Any, Callable, Dict, List, Optional, Tuple
14
12
  from urllib.parse import urlparse
15
13
 
16
14
  from sticker_convert.converter import StickerConvert
@@ -23,18 +21,11 @@ from sticker_convert.uploaders.compress_wastickers import CompressWastickers
23
21
  from sticker_convert.uploaders.upload_signal import UploadSignal
24
22
  from sticker_convert.uploaders.upload_telegram import UploadTelegram
25
23
  from sticker_convert.uploaders.xcode_imessage import XcodeImessage
26
- from sticker_convert.utils.callback import CallbackReturn, CbQueueItemType
24
+ from sticker_convert.utils.callback import CallbackReturn, CbQueueType, ResultsListType, WorkQueueType
27
25
  from sticker_convert.utils.files.json_resources_loader import OUTPUT_JSON
28
26
  from sticker_convert.utils.files.metadata_handler import MetadataHandler
29
27
  from sticker_convert.utils.media.codec_info import CodecInfo
30
28
 
31
- WorkListItemType = Optional[Tuple[Callable[..., Any], Tuple[Any, ...]]]
32
- if TYPE_CHECKING:
33
- # mypy complains about this
34
- WorkListType = ListProxy[WorkListItemType] # type: ignore
35
- else:
36
- WorkListType = List[WorkListItemType]
37
-
38
29
 
39
30
  class Executor:
40
31
  def __init__(
@@ -51,33 +42,29 @@ class Executor:
51
42
  self.cb_ask_bool = cb_ask_bool
52
43
  self.cb_ask_str = cb_ask_str
53
44
 
54
- self.manager = SyncManager()
55
- self.manager.start()
56
- # Using list instead of queue for work_list as it can cause random deadlocks
57
- # Especially when using scale_filter=nearest
58
- self.work_list: WorkListType = self.manager.list()
59
- self.results_queue: Queue[Any] = self.manager.Queue()
60
- self.cb_queue: Queue[CbQueueItemType] = self.manager.Queue()
61
- self.cb_return = CallbackReturn()
45
+ self.manager = Manager()
46
+ self.work_queue: WorkQueueType = self.manager.Queue()
47
+ self.cb_queue: CbQueueType = self.manager.Queue()
48
+ self.results_list: ResultsListType = self.manager.list()
49
+ self.cb_return = CallbackReturn(self.manager)
62
50
  self.processes: List[Process] = []
63
51
 
64
52
  self.is_cancel_job = Value("i", 0)
65
53
 
66
- self.cb_thread_instance = Thread(
67
- target=self.cb_thread,
68
- args=(
69
- self.cb_queue,
70
- self.cb_return,
71
- ),
72
- )
73
- self.cb_thread_instance.start()
54
+ self.cb_thread_instance: Optional[Thread] = None
74
55
 
75
56
  def cb_thread(
76
57
  self,
77
- cb_queue: Queue[CbQueueItemType],
78
- cb_return: CallbackReturn,
58
+ cb_queue: CbQueueType,
59
+ processes: int,
79
60
  ) -> None:
61
+ processes_done = 0
80
62
  for i in iter(cb_queue.get, None):
63
+ if i == "__PROCESS_DONE__":
64
+ processes_done += 1
65
+ if processes_done == processes:
66
+ cb_queue.put(None)
67
+ continue
81
68
  if isinstance(i, tuple):
82
69
  action = i[0]
83
70
  if len(i) >= 2:
@@ -92,42 +79,44 @@ class Executor:
92
79
  action = i
93
80
  args = tuple()
94
81
  kwargs = {}
95
- if action == "msg":
96
- self.cb_msg(*args, **kwargs)
97
- elif action == "bar":
98
- self.cb_bar(*args, **kwargs)
99
- elif action == "update_bar":
100
- self.cb_bar(update_bar=1)
101
- elif action == "msg_block":
102
- cb_return.set_response(self.cb_msg_block(*args, **kwargs))
103
- elif action == "ask_bool":
104
- cb_return.set_response(self.cb_ask_bool(*args, **kwargs))
105
- elif action == "ask_str":
106
- cb_return.set_response(self.cb_ask_str(*args, **kwargs))
107
- else:
108
- self.cb_msg(action)
82
+ self.cb(action, args, kwargs)
83
+
84
+ def cb(
85
+ self,
86
+ action: Optional[str],
87
+ args: Optional[Tuple[str, ...]] = None,
88
+ kwargs: Optional[Dict[str, Any]] = None,
89
+ ) -> None:
90
+ if args is None:
91
+ args = tuple()
92
+ if kwargs is None:
93
+ kwargs = {}
94
+ if action == "msg":
95
+ self.cb_msg(*args, **kwargs)
96
+ elif action == "bar":
97
+ self.cb_bar(*args, **kwargs)
98
+ elif action == "update_bar":
99
+ self.cb_bar(update_bar=1)
100
+ elif action == "msg_block":
101
+ self.cb_return.set_response(self.cb_msg_block(*args, **kwargs))
102
+ elif action == "ask_bool":
103
+ self.cb_return.set_response(self.cb_ask_bool(*args, **kwargs))
104
+ elif action == "ask_str":
105
+ self.cb_return.set_response(self.cb_ask_str(*args, **kwargs))
106
+ else:
107
+ self.cb_msg(action)
109
108
 
110
109
  @staticmethod
111
110
  def worker(
112
- work_list: WorkListType,
113
- results_queue: Queue[Any],
114
- cb_queue: Queue[CbQueueItemType],
111
+ work_queue: WorkQueueType,
112
+ results_list: ResultsListType,
113
+ cb_queue: CbQueueType,
115
114
  cb_return: CallbackReturn,
116
115
  ) -> None:
117
- while True:
118
- try:
119
- work = work_list.pop(0)
120
- except IndexError:
121
- break
122
-
123
- if work is None:
124
- break
125
- else:
126
- work_func, work_args = work
127
-
116
+ for work_func, work_args in iter(work_queue.get, None):
128
117
  try:
129
118
  results = work_func(*work_args, cb_queue, cb_return)
130
- results_queue.put(results)
119
+ results_list.append(results)
131
120
  except Exception:
132
121
  arg_dump: List[Any] = []
133
122
  for i in work_args:
@@ -142,15 +131,25 @@ class Executor:
142
131
  e += "#####################"
143
132
  cb_queue.put(e)
144
133
 
145
- work_list.append(None)
134
+ work_queue.put(None)
135
+ cb_queue.put("__PROCESS_DONE__")
146
136
 
147
137
  def start_workers(self, processes: int = 1) -> None:
138
+ self.cb_thread_instance = Thread(
139
+ target=self.cb_thread,
140
+ args=(self.cb_queue, processes),
141
+ )
142
+ self.cb_thread_instance.start()
143
+
144
+ self.results_list[:] = []
145
+ while not self.work_queue.empty():
146
+ self.work_queue.get()
148
147
  for _ in range(processes):
149
148
  process = Process(
150
149
  target=Executor.worker,
151
150
  args=(
152
- self.work_list,
153
- self.results_queue,
151
+ self.work_queue,
152
+ self.results_list,
154
153
  self.cb_queue,
155
154
  self.cb_return,
156
155
  ),
@@ -163,18 +162,18 @@ class Executor:
163
162
  def add_work(
164
163
  self, work_func: Callable[..., Any], work_args: Tuple[Any, ...]
165
164
  ) -> None:
166
- self.work_list.append((work_func, work_args))
165
+ self.work_queue.put((work_func, work_args))
167
166
 
168
167
  def join_workers(self) -> None:
169
- self.work_list.append(None)
168
+ self.work_queue.put(None)
170
169
  try:
171
170
  for process in self.processes:
172
171
  process.join()
173
172
  except KeyboardInterrupt:
174
173
  pass
175
174
 
176
- self.results_queue.put(None)
177
- self.work_list[:] = []
175
+ if self.cb_thread_instance:
176
+ self.cb_thread_instance.join()
178
177
  self.processes.clear()
179
178
 
180
179
  def kill_workers(self, *_: Any, **__: Any) -> None:
@@ -187,21 +186,10 @@ class Executor:
187
186
 
188
187
  def cleanup(self, killed: bool = False) -> None:
189
188
  if killed:
190
- self.cb_queue.put("Job cancelled.")
191
- self.cb_queue.put(("bar", None, {"set_progress_mode": "clear"}))
192
- self.cb_queue.put(None)
193
- self.cb_thread_instance.join()
194
-
195
- def get_result(self) -> Generator[Any, None, None]:
196
- yield from iter(self.results_queue.get, None)
197
-
198
- def cb(
199
- self,
200
- action: Optional[str],
201
- args: Optional[Tuple[str, ...]] = None,
202
- kwargs: Optional[Dict[str, Any]] = None,
203
- ) -> None:
204
- self.cb_queue.put((action, args, kwargs))
189
+ self.cb_msg("Job cancelled.")
190
+ self.cb_bar("clear")
191
+ # self.cb_queue.put(None)
192
+ self.manager.shutdown()
205
193
 
206
194
 
207
195
  class Job:
@@ -547,17 +535,18 @@ class Job:
547
535
  self.executor.cb("Nothing to download")
548
536
  return True
549
537
 
538
+ self.executor.start_workers(processes=1)
539
+
550
540
  for downloader in downloaders:
551
541
  self.executor.add_work(
552
542
  work_func=downloader,
553
543
  work_args=(self.opt_input.url, self.opt_input.dir, self.opt_cred),
554
544
  )
555
545
 
556
- self.executor.start_workers(processes=1)
557
546
  self.executor.join_workers()
558
547
 
559
548
  # Return False if any of the job returns failure
560
- for result in self.executor.get_result():
549
+ for result in self.executor.results_list:
561
550
  if result is False:
562
551
  return False
563
552
 
@@ -619,6 +608,8 @@ class Job:
619
608
  "bar", kwargs={"set_progress_mode": "determinate", "steps": in_fs_count}
620
609
  )
621
610
 
611
+ self.executor.start_workers(processes=min(self.opt_comp.processes, in_fs_count))
612
+
622
613
  for i in in_fs:
623
614
  in_f = input_dir / i.name
624
615
  out_f = output_dir / Path(i).stem
@@ -627,11 +618,10 @@ class Job:
627
618
  work_func=StickerConvert.convert, work_args=(in_f, out_f, self.opt_comp)
628
619
  )
629
620
 
630
- self.executor.start_workers(processes=min(self.opt_comp.processes, in_fs_count))
631
621
  self.executor.join_workers()
632
622
 
633
623
  # Return False if any of the job returns failure
634
- for result in self.executor.get_result():
624
+ for result in self.executor.results_list:
635
625
  if result[0] is False:
636
626
  return False
637
627
 
@@ -661,16 +651,17 @@ class Job:
661
651
  if self.opt_output.option == "imessage":
662
652
  exporters.append(XcodeImessage.start)
663
653
 
654
+ self.executor.start_workers(processes=1)
655
+
664
656
  for exporter in exporters:
665
657
  self.executor.add_work(
666
658
  work_func=exporter,
667
659
  work_args=(self.opt_output, self.opt_comp, self.opt_cred),
668
660
  )
669
661
 
670
- self.executor.start_workers(processes=1)
671
662
  self.executor.join_workers()
672
663
 
673
- for result in self.executor.get_result():
664
+ for result in self.executor.results_list:
674
665
  self.out_urls.extend(result)
675
666
 
676
667
  if self.out_urls:
@@ -3,13 +3,12 @@ import copy
3
3
  import shutil
4
4
  import zipfile
5
5
  from pathlib import Path
6
- from queue import Queue
7
- from typing import Any, List, Union
6
+ from typing import Any, List
8
7
 
9
8
  from sticker_convert.converter import StickerConvert
10
9
  from sticker_convert.job_option import CompOption, CredOption, OutputOption
11
10
  from sticker_convert.uploaders.upload_base import UploadBase
12
- from sticker_convert.utils.callback import Callback, CallbackReturn, CbQueueItemType
11
+ from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
13
12
  from sticker_convert.utils.files.cache_store import CacheStore
14
13
  from sticker_convert.utils.files.metadata_handler import MetadataHandler
15
14
  from sticker_convert.utils.files.sanitize_filename import sanitize_filename
@@ -150,7 +149,7 @@ class CompressWastickers(UploadBase):
150
149
  opt_output: OutputOption,
151
150
  opt_comp: CompOption,
152
151
  opt_cred: CredOption,
153
- cb: "Union[Queue[CbQueueItemType], Callback]",
152
+ cb: CallbackProtocol,
154
153
  cb_return: CallbackReturn,
155
154
  ) -> List[str]:
156
155
  exporter = CompressWastickers(opt_output, opt_comp, opt_cred, cb, cb_return)
@@ -1,9 +1,7 @@
1
1
  #!/usr/bin/env python3
2
- from queue import Queue
3
- from typing import Union
4
2
 
5
3
  from sticker_convert.job_option import CompOption, CredOption, OutputOption
6
- from sticker_convert.utils.callback import Callback, CallbackReturn, CbQueueItemType
4
+ from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
7
5
 
8
6
 
9
7
  class UploadBase:
@@ -12,13 +10,9 @@ class UploadBase:
12
10
  opt_output: OutputOption,
13
11
  opt_comp: CompOption,
14
12
  opt_cred: CredOption,
15
- cb: "Union[Queue[CbQueueItemType], Callback]",
13
+ cb: CallbackProtocol,
16
14
  cb_return: CallbackReturn,
17
15
  ) -> None:
18
- if not cb:
19
- cb = Callback(silent=True)
20
- cb_return = CallbackReturn()
21
-
22
16
  self.opt_output = opt_output
23
17
  self.opt_comp = opt_comp
24
18
  self.opt_cred = opt_cred
@@ -1,8 +1,7 @@
1
1
  #!/usr/bin/env python3
2
2
  import copy
3
3
  from pathlib import Path
4
- from queue import Queue
5
- from typing import Any, Dict, List, Union
4
+ from typing import Any, Dict, List
6
5
 
7
6
  import anyio
8
7
  from signalstickers_client import StickersClient # type: ignore
@@ -12,7 +11,7 @@ from signalstickers_client.models import LocalStickerPack, Sticker # type: igno
12
11
  from sticker_convert.converter import StickerConvert
13
12
  from sticker_convert.job_option import CompOption, CredOption, OutputOption
14
13
  from sticker_convert.uploaders.upload_base import UploadBase
15
- from sticker_convert.utils.callback import Callback, CallbackReturn, CbQueueItemType
14
+ from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
16
15
  from sticker_convert.utils.files.metadata_handler import MetadataHandler
17
16
  from sticker_convert.utils.media.codec_info import CodecInfo
18
17
  from sticker_convert.utils.media.format_verify import FormatVerify
@@ -167,7 +166,7 @@ class UploadSignal(UploadBase):
167
166
  opt_output: OutputOption,
168
167
  opt_comp: CompOption,
169
168
  opt_cred: CredOption,
170
- cb: "Union[Queue[CbQueueItemType], Callback]",
169
+ cb: CallbackProtocol,
171
170
  cb_return: CallbackReturn,
172
171
  ) -> List[str]:
173
172
  exporter = UploadSignal(opt_output, opt_comp, opt_cred, cb, cb_return)
@@ -2,7 +2,6 @@
2
2
  import copy
3
3
  import re
4
4
  from pathlib import Path
5
- from queue import Queue
6
5
  from typing import Any, Dict, List, Optional, Tuple, Union, cast
7
6
 
8
7
  import anyio
@@ -13,7 +12,7 @@ from telegram.ext import AIORateLimiter, ApplicationBuilder
13
12
  from sticker_convert.converter import StickerConvert
14
13
  from sticker_convert.job_option import CompOption, CredOption, OutputOption
15
14
  from sticker_convert.uploaders.upload_base import UploadBase
16
- from sticker_convert.utils.callback import Callback, CallbackReturn, CbQueueItemType
15
+ from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
17
16
  from sticker_convert.utils.files.metadata_handler import MetadataHandler
18
17
  from sticker_convert.utils.media.format_verify import FormatVerify
19
18
 
@@ -350,7 +349,7 @@ class UploadTelegram(UploadBase):
350
349
  opt_output: OutputOption,
351
350
  opt_comp: CompOption,
352
351
  opt_cred: CredOption,
353
- cb: "Union[Queue[CbQueueItemType], Callback]",
352
+ cb: CallbackProtocol,
354
353
  cb_return: CallbackReturn,
355
354
  ) -> List[str]:
356
355
  exporter = UploadTelegram(
@@ -6,14 +6,13 @@ import plistlib
6
6
  import shutil
7
7
  import zipfile
8
8
  from pathlib import Path
9
- from queue import Queue
10
- from typing import Any, Dict, List, Union
9
+ from typing import Any, Dict, List
11
10
 
12
11
  from sticker_convert.converter import StickerConvert
13
12
  from sticker_convert.definitions import ROOT_DIR
14
13
  from sticker_convert.job_option import CompOption, CredOption, OutputOption
15
14
  from sticker_convert.uploaders.upload_base import UploadBase
16
- from sticker_convert.utils.callback import Callback, CallbackReturn, CbQueueItemType
15
+ from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
17
16
  from sticker_convert.utils.files.metadata_handler import XCODE_IMESSAGE_ICONSET, MetadataHandler
18
17
  from sticker_convert.utils.files.sanitize_filename import sanitize_filename
19
18
  from sticker_convert.utils.media.codec_info import CodecInfo
@@ -279,7 +278,7 @@ class XcodeImessage(UploadBase):
279
278
  opt_output: OutputOption,
280
279
  opt_comp: CompOption,
281
280
  opt_cred: CredOption,
282
- cb: "Union[Queue[CbQueueItemType], Callback]",
281
+ cb: CallbackProtocol,
283
282
  cb_return: CallbackReturn,
284
283
  ) -> List[str]:
285
284
  exporter = XcodeImessage(opt_output, opt_comp, opt_cred, cb, cb_return)
@@ -1,39 +1,57 @@
1
1
  #!/usr/bin/env python3
2
- from multiprocessing import Event, Queue
3
- from typing import Any, Callable, Dict, Optional, Tuple, Union
2
+ from multiprocessing import Event, Manager
3
+ from multiprocessing.managers import ListProxy, SyncManager
4
+ from queue import Queue
5
+ from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Protocol, Tuple, Union
4
6
 
5
7
  from tqdm import tqdm
6
8
 
7
9
  CbQueueTupleType = Tuple[
8
10
  Optional[str], Optional[Tuple[Any, ...]], Optional[Dict[str, Any]]
9
11
  ]
10
- CbQueueItemType = Union[
11
- CbQueueTupleType,
12
- str,
13
- None,
14
- ]
12
+ CbQueueItemType = Union[CbQueueTupleType, str, None]
13
+ WorkQueueItemType = Optional[Tuple[Callable[..., Any], Tuple[Any, ...]]]
14
+ ResponseItemType = Union[bool, str, None]
15
+
16
+ if TYPE_CHECKING:
17
+ # mypy complains about this
18
+ ResultsListType = ListProxy[Any] # type: ignore
19
+ ResponseListType = ListProxy[ResponseItemType] # type: ignore
20
+ CbQueueType = Queue[CbQueueItemType] # type: ignore
21
+ WorkQueueType = Queue[WorkQueueItemType] # type: ignore
22
+ else:
23
+ ResultsListType = List[Any]
24
+ ResponseListType = List[ResponseItemType]
25
+ CbQueueType = Queue
26
+ WorkQueueType = Queue
15
27
 
16
28
 
17
29
  class CallbackReturn:
18
- def __init__(self) -> None:
30
+ def __init__(self, manager: Optional[SyncManager] = None) -> None:
19
31
  self.response_event = Event()
20
- self.response_queue: Queue[Union[bool, str, None]] = Queue()
32
+ if manager is None:
33
+ manager = Manager()
34
+ self.response_queue: ResponseListType = manager.list()
21
35
 
22
- def set_response(self, response: Union[bool, str, None]) -> None:
23
- self.response_queue.put(response)
36
+ def set_response(self, response: ResponseItemType) -> None:
37
+ self.response_queue.append(response)
24
38
  self.response_event.set()
25
39
 
26
- def get_response(self) -> Union[bool, str, None]:
40
+ def get_response(self) -> ResponseItemType:
27
41
  self.response_event.wait()
28
42
 
29
- response = self.response_queue.get()
43
+ response = self.response_queue.pop()
30
44
 
31
45
  self.response_event.clear()
32
46
 
33
47
  return response
34
48
 
35
49
 
36
- class Callback:
50
+ class CallbackProtocol(Protocol):
51
+ def put(self, i: Union[CbQueueItemType, str]) -> Any: ...
52
+
53
+
54
+ class Callback(CallbackProtocol):
37
55
  def __init__(
38
56
  self,
39
57
  msg: Optional[Callable[..., None]] = None,
@@ -155,13 +173,7 @@ class Callback:
155
173
 
156
174
  return response
157
175
 
158
- def put(
159
- self,
160
- i: Union[
161
- CbQueueItemType,
162
- str,
163
- ],
164
- ) -> Union[str, bool, None]:
176
+ def put(self, i: Union[CbQueueItemType, str]) -> Union[str, bool, None]:
165
177
  if isinstance(i, tuple):
166
178
  action = i[0]
167
179
  if len(i) >= 2:
@@ -258,11 +258,7 @@ class CodecInfo:
258
258
  fps = frames_apparent / total_duration * 1000
259
259
  return fps, frames, total_duration
260
260
 
261
- return (
262
- 0.0,
263
- 1,
264
- 0,
265
- )
261
+ return 0.0, 1, 0
266
262
 
267
263
  @staticmethod
268
264
  def _get_file_fps_frames_duration_webp(
@@ -294,8 +290,8 @@ class CodecInfo:
294
290
  total_duration += frame_duration
295
291
  frames += 1
296
292
 
297
- if frames == 0:
298
- return 0.0, 0, 0
293
+ if frames <= 1:
294
+ return 0.0, 1, 0
299
295
 
300
296
  if len(durations) == 1:
301
297
  fps = frames / total_duration * 1000
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env python3
2
2
 
3
- __version__ = "2.8.0"
3
+ __version__ = "2.8.1"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sticker-convert
3
- Version: 2.8.0
3
+ Version: 2.8.1
4
4
  Summary: Convert (animated) stickers to/from WhatsApp, Telegram, Signal, Line, Kakao, iMessage. Written in Python.
5
5
  Author-email: laggykiller <chaudominic2@gmail.com>
6
6
  Maintainer-email: laggykiller <chaudominic2@gmail.com>
@@ -1,18 +1,18 @@
1
1
  sticker_convert/__init__.py,sha256=iQnv6UOOA69c3soAn7ZOnAIubTIQSUxtq1Uhh8xRWvU,102
2
2
  sticker_convert/__main__.py,sha256=6RJauR-SCSSTT3TU7FFB6B6PVwsCxO2xZXtmZ3jc2Is,463
3
3
  sticker_convert/cli.py,sha256=kyfhvMoHq42uLZsYYLrr6b30xsNE93GVZlbGYPFjC2I,18385
4
- sticker_convert/converter.py,sha256=Y0vVZhAxlTe_SDTbQq2_Z9vM8oY6VAJPToYji-S6J-E,35033
4
+ sticker_convert/converter.py,sha256=VRAvSBtsr9XTJHd2iOydZ3xpAb7OZ9tBedYNYMGfnjA,34950
5
5
  sticker_convert/definitions.py,sha256=ZhP2ALCEud-w9ZZD4c3TDG9eHGPZyaAL7zPUsJAbjtE,2073
6
6
  sticker_convert/gui.py,sha256=TqdgFbHBRYgcXWWrsfxLUJ8Zu9WeE11vYyZMX6nalik,30599
7
- sticker_convert/job.py,sha256=J4e7dZ48t5EhM3fG-xF1BEQ10WYljx3wWamKXAJjCa8,26000
7
+ sticker_convert/job.py,sha256=Qky9gMtaHg4BmgDn6I_K1gvmYNlfR-ydp9-H95X963M,25592
8
8
  sticker_convert/job_option.py,sha256=1YVhyTfu2cWz3qpAKbdIM11jbL0CJz0ksOYAeg8v6dc,7649
9
- sticker_convert/version.py,sha256=M_a1EApD3NUMpL5LvuHWnryb8nvQLMKOHwpDKPiWPX4,46
9
+ sticker_convert/version.py,sha256=C5EXaFbWRR6BU63HDiiI9CxdR6UJMMuL7gTZEPmmC0U,46
10
10
  sticker_convert/downloaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
- sticker_convert/downloaders/download_base.py,sha256=5R7c8kwahAflOOYrtSQPnBVQ4T-DsprPUMP7G9wcJX4,2824
12
- sticker_convert/downloaders/download_kakao.py,sha256=RYrebTxEjKjXAr9xw18r0dMW0dFjSqZxzi8dpaq56TY,8581
13
- sticker_convert/downloaders/download_line.py,sha256=iQwCWqZBnoKFuQqgTR2JPnxE1RJWMu9eRmg38wST-kM,17918
14
- sticker_convert/downloaders/download_signal.py,sha256=HMV5SV-WnfJkZ0lC65yY45xlE7_GK1b_ELOPwNTptG8,3225
15
- sticker_convert/downloaders/download_telegram.py,sha256=OZdg7WuJV5VurZVC6dZSnzCW-ahl_4E9L-zsZuwM2x0,4659
11
+ sticker_convert/downloaders/download_base.py,sha256=CcrgZiBOYJbYcDGCPDHp-ECGXSpfmGtQCzS7KRbBl1E,2726
12
+ sticker_convert/downloaders/download_kakao.py,sha256=UFp7EpMea62fIePY5DfhH4jThAwdeazfoC5iW1g4dAo,8516
13
+ sticker_convert/downloaders/download_line.py,sha256=9WzOWujTbZdAqBi52k21OUEfRmcV1loCaJiDmg6dklw,17853
14
+ sticker_convert/downloaders/download_signal.py,sha256=A-paX51kRvXIs6tY9aXv77_DJhBPcTfqZ8ib31yk5ks,3160
15
+ sticker_convert/downloaders/download_telegram.py,sha256=JETwy2gSOP2f5DjI636l4uW8Ix8_jzZ6aVzgTpavqC4,4601
16
16
  sticker_convert/gui_components/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
17
  sticker_convert/gui_components/gui_utils.py,sha256=okho2cA1Scem_m6rPiYifreFzpFrM21-yUkiAv64EUI,3431
18
18
  sticker_convert/gui_components/frames/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -72,12 +72,12 @@ sticker_convert/resources/help.json,sha256=TUZi_70uVmgImApBUtKieDGEMtu8syVjE0ah8
72
72
  sticker_convert/resources/input.json,sha256=sRz8qWaLh2KTjjlPIxz2UfynVn2Bn0olywbb8-qT_Hc,2251
73
73
  sticker_convert/resources/output.json,sha256=QYP2gqDvEaAm5I9bH4NReaB1XMLboevv69u-V8YdZUs,1373
74
74
  sticker_convert/uploaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
75
- sticker_convert/uploaders/compress_wastickers.py,sha256=vrrd2huRGEw0Dbd3EqS162MsQHuzFk5rhB6GnD9zhfU,6062
76
- sticker_convert/uploaders/upload_base.py,sha256=FDNZdMUcamLtnxy1XNMHk1N1MJapTlODLDhod5wqo7g,1386
77
- sticker_convert/uploaders/upload_signal.py,sha256=6H4GT10d_J9rEA0Ov1CTdNagxuRDjGYtuQYZADV05Lo,6606
78
- sticker_convert/uploaders/upload_telegram.py,sha256=JXgnIQcyoMjgAOfZ9TatMn4CeeOkk1Nytc7FdbN7DBA,14679
79
- sticker_convert/uploaders/xcode_imessage.py,sha256=mwnUTNclq4SFGX8JgFoM-bsvAtsYtrjg6gFPNdRgbWk,11319
80
- sticker_convert/utils/callback.py,sha256=JnwrgaSNdl-74Nd-fz6EH-r6ePLLb-4a5C1P0OAPjNQ,5279
75
+ sticker_convert/uploaders/compress_wastickers.py,sha256=xNua2pDPD-7Q2Fx9WLo1IlncVs3jVPMN-pxXTswjk8g,5997
76
+ sticker_convert/uploaders/upload_base.py,sha256=uQupPn6r4zrlAzpKzzX7CgvZb69ATyrwPKahWOQj0ds,1203
77
+ sticker_convert/uploaders/upload_signal.py,sha256=vFMvQ4TwDNliPuQ7ecXHzTT-qrTwPAORbSxZ7Nk9VM4,6541
78
+ sticker_convert/uploaders/upload_telegram.py,sha256=Q4dy6Esdatf5WZwffRLnTIsP9zJv_GDlujIRTH46tH4,14621
79
+ sticker_convert/uploaders/xcode_imessage.py,sha256=1gvOljf6kYsq_11tYhnF19Yf4oGY5y34te2DWBRMwf0,11254
80
+ sticker_convert/utils/callback.py,sha256=_w_dZ3DZTA9m4TjEg6NH_VOa5Dl2YHXdXAlwx_tBdoY,6061
81
81
  sticker_convert/utils/url_detect.py,sha256=Cw3SzHj0xQTgCY8KvXbgFGRn_VhDJuZvH0mWsiQOg5s,769
82
82
  sticker_convert/utils/auth/get_kakao_auth.py,sha256=ipAZ1DUd5CMTpUoxRXHVOFC3DKIpxwxpTYAfrOJ6UZ8,9829
83
83
  sticker_convert/utils/auth/get_line_auth.py,sha256=CAg5oAyqnzyAr1sP0iaecJPpmreeERiZnVxIX9X_Ib0,2682
@@ -89,12 +89,12 @@ sticker_convert/utils/files/metadata_handler.py,sha256=TJpQ-7KdnqQh09hwR6xB_scRL
89
89
  sticker_convert/utils/files/run_bin.py,sha256=QalA9je6liHxiOtxsjsFsIkc2t59quhcJCVpP1X3p50,1743
90
90
  sticker_convert/utils/files/sanitize_filename.py,sha256=HBklPGsHRJjFQUIC5rYTQsUrsuTtezZXIEA8CPhLP8A,2156
91
91
  sticker_convert/utils/media/apple_png_normalize.py,sha256=LbrQhc7LlYX4I9ek4XJsZE4l0MygBA1jB-PFiYLEkzk,3657
92
- sticker_convert/utils/media/codec_info.py,sha256=yXjgGN3AwwFiwPHTlM9mqEtH3fH8VegZpKkgj3TvUNA,15611
92
+ sticker_convert/utils/media/codec_info.py,sha256=SJSFvQzXHnGkj7MH9xJ5xiC4cqiOjFKckFKE_FICdT4,15562
93
93
  sticker_convert/utils/media/decrypt_kakao.py,sha256=4wq9ZDRnFkx1WmFZnyEogBofiLGsWQM_X69HlA36578,1947
94
94
  sticker_convert/utils/media/format_verify.py,sha256=Xf94jyqk_6M9IlFGMy0wYIgQKn_yg00nD4XW0CgAbew,5732
95
- sticker_convert-2.8.0.dist-info/LICENSE,sha256=gXf5dRMhNSbfLPYYTY_5hsZ1r7UU1OaKQEAQUhuIBkM,18092
96
- sticker_convert-2.8.0.dist-info/METADATA,sha256=M1OIHNyHntzmytdfECLmPnQ3r_veJG2y5W3JcoE845o,49132
97
- sticker_convert-2.8.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
98
- sticker_convert-2.8.0.dist-info/entry_points.txt,sha256=MNJ7XyC--ugxi5jS1nzjDLGnxCyLuaGdsVLnJhDHCqs,66
99
- sticker_convert-2.8.0.dist-info/top_level.txt,sha256=r9vfnB0l1ZnH5pTH5RvkobnK3Ow9m0RsncaOMAtiAtk,16
100
- sticker_convert-2.8.0.dist-info/RECORD,,
95
+ sticker_convert-2.8.1.dist-info/LICENSE,sha256=gXf5dRMhNSbfLPYYTY_5hsZ1r7UU1OaKQEAQUhuIBkM,18092
96
+ sticker_convert-2.8.1.dist-info/METADATA,sha256=BrT7dQzYs0b7LwI4wA7vEEMrLANAx-qwRVpJsQivKg4,49132
97
+ sticker_convert-2.8.1.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
98
+ sticker_convert-2.8.1.dist-info/entry_points.txt,sha256=MNJ7XyC--ugxi5jS1nzjDLGnxCyLuaGdsVLnJhDHCqs,66
99
+ sticker_convert-2.8.1.dist-info/top_level.txt,sha256=r9vfnB0l1ZnH5pTH5RvkobnK3Ow9m0RsncaOMAtiAtk,16
100
+ sticker_convert-2.8.1.dist-info/RECORD,,