sticker-convert 2.13.3.0__py3-none-any.whl → 2.17.0.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.
Files changed (93) hide show
  1. sticker_convert/__main__.py +24 -27
  2. sticker_convert/auth/__init__.py +0 -0
  3. sticker_convert/auth/auth_base.py +19 -0
  4. sticker_convert/{utils/auth/get_discord_auth.py → auth/auth_discord.py} +149 -118
  5. sticker_convert/{utils/auth/get_kakao_auth.py → auth/auth_kakao_android_login.py} +331 -330
  6. sticker_convert/auth/auth_kakao_desktop_login.py +327 -0
  7. sticker_convert/{utils/auth/get_kakao_desktop_auth.py → auth/auth_kakao_desktop_memdump.py} +281 -263
  8. sticker_convert/{utils/auth/get_line_auth.py → auth/auth_line.py} +98 -80
  9. sticker_convert/{utils/auth/get_signal_auth.py → auth/auth_signal.py} +139 -135
  10. sticker_convert/auth/auth_telethon.py +161 -0
  11. sticker_convert/{utils/auth/get_viber_auth.py → auth/auth_viber.py} +250 -235
  12. sticker_convert/{utils/auth → auth}/telegram_api.py +736 -675
  13. sticker_convert/cli.py +623 -608
  14. sticker_convert/converter.py +1093 -1084
  15. sticker_convert/definitions.py +4 -0
  16. sticker_convert/downloaders/download_band.py +111 -110
  17. sticker_convert/downloaders/download_base.py +171 -166
  18. sticker_convert/downloaders/download_discord.py +92 -91
  19. sticker_convert/downloaders/download_kakao.py +417 -404
  20. sticker_convert/downloaders/download_line.py +484 -475
  21. sticker_convert/downloaders/download_ogq.py +80 -79
  22. sticker_convert/downloaders/download_signal.py +108 -105
  23. sticker_convert/downloaders/download_telegram.py +56 -55
  24. sticker_convert/downloaders/download_viber.py +121 -120
  25. sticker_convert/gui.py +788 -873
  26. sticker_convert/gui_components/frames/comp_frame.py +180 -166
  27. sticker_convert/gui_components/frames/config_frame.py +156 -113
  28. sticker_convert/gui_components/frames/control_frame.py +32 -30
  29. sticker_convert/gui_components/frames/cred_frame.py +232 -233
  30. sticker_convert/gui_components/frames/input_frame.py +139 -137
  31. sticker_convert/gui_components/frames/output_frame.py +112 -110
  32. sticker_convert/gui_components/frames/right_clicker.py +25 -23
  33. sticker_convert/gui_components/windows/advanced_compression_window.py +757 -757
  34. sticker_convert/gui_components/windows/base_window.py +7 -2
  35. sticker_convert/gui_components/windows/discord_get_auth_window.py +79 -82
  36. sticker_convert/gui_components/windows/kakao_get_auth_window.py +511 -321
  37. sticker_convert/gui_components/windows/line_get_auth_window.py +94 -102
  38. sticker_convert/gui_components/windows/signal_get_auth_window.py +84 -89
  39. sticker_convert/gui_components/windows/viber_get_auth_window.py +168 -168
  40. sticker_convert/ios-message-stickers-template/.github/FUNDING.yml +3 -3
  41. sticker_convert/ios-message-stickers-template/README.md +10 -10
  42. sticker_convert/ios-message-stickers-template/stickers/Info.plist +43 -43
  43. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Info.plist +31 -31
  44. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/Contents.json +6 -6
  45. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/Contents.json +20 -20
  46. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/Sticker 1.sticker/Contents.json +9 -9
  47. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/Sticker 2.sticker/Contents.json +9 -9
  48. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/Sticker Pack.stickerpack/Sticker 3.sticker/Contents.json +9 -9
  49. sticker_convert/ios-message-stickers-template/stickers StickerPackExtension/Stickers.xcstickers/iMessage App Icon.stickersiconset/Contents.json +91 -91
  50. sticker_convert/ios-message-stickers-template/stickers.xcodeproj/project.pbxproj +364 -364
  51. sticker_convert/ios-message-stickers-template/stickers.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -7
  52. sticker_convert/ios-message-stickers-template/stickers.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -8
  53. sticker_convert/ios-message-stickers-template/stickers.xcodeproj/xcuserdata/niklaspeterson.xcuserdatad/xcschemes/xcschememanagement.plist +14 -14
  54. sticker_convert/job.py +166 -130
  55. sticker_convert/job_option.py +1 -0
  56. sticker_convert/locales/en_US/LC_MESSAGES/base.mo +0 -0
  57. sticker_convert/locales/ja_JP/LC_MESSAGES/base.mo +0 -0
  58. sticker_convert/locales/zh_CN/LC_MESSAGES/base.mo +0 -0
  59. sticker_convert/locales/zh_TW/LC_MESSAGES/base.mo +0 -0
  60. sticker_convert/py.typed +0 -0
  61. sticker_convert/resources/NotoColorEmoji.ttf +0 -0
  62. sticker_convert/resources/help.ja_JP.json +88 -0
  63. sticker_convert/resources/help.json +10 -7
  64. sticker_convert/resources/help.zh_CN.json +88 -0
  65. sticker_convert/resources/help.zh_TW.json +88 -0
  66. sticker_convert/resources/input.ja_JP.json +74 -0
  67. sticker_convert/resources/input.json +121 -121
  68. sticker_convert/resources/input.zh_CN.json +74 -0
  69. sticker_convert/resources/input.zh_TW.json +74 -0
  70. sticker_convert/resources/output.ja_JP.json +38 -0
  71. sticker_convert/resources/output.zh_CN.json +38 -0
  72. sticker_convert/resources/output.zh_TW.json +38 -0
  73. sticker_convert/uploaders/compress_wastickers.py +186 -177
  74. sticker_convert/uploaders/upload_base.py +44 -35
  75. sticker_convert/uploaders/upload_signal.py +218 -203
  76. sticker_convert/uploaders/upload_telegram.py +353 -338
  77. sticker_convert/uploaders/upload_viber.py +178 -169
  78. sticker_convert/uploaders/xcode_imessage.py +295 -286
  79. sticker_convert/utils/callback.py +238 -6
  80. sticker_convert/utils/emoji.py +16 -4
  81. sticker_convert/utils/files/json_resources_loader.py +24 -19
  82. sticker_convert/utils/files/metadata_handler.py +3 -3
  83. sticker_convert/utils/translate.py +108 -0
  84. sticker_convert/utils/url_detect.py +40 -37
  85. sticker_convert/version.py +1 -1
  86. {sticker_convert-2.13.3.0.dist-info → sticker_convert-2.17.0.0.dist-info}/METADATA +89 -74
  87. {sticker_convert-2.13.3.0.dist-info → sticker_convert-2.17.0.0.dist-info}/RECORD +91 -74
  88. sticker_convert/utils/auth/telethon_setup.py +0 -97
  89. sticker_convert/utils/singletons.py +0 -18
  90. {sticker_convert-2.13.3.0.dist-info → sticker_convert-2.17.0.0.dist-info}/WHEEL +0 -0
  91. {sticker_convert-2.13.3.0.dist-info → sticker_convert-2.17.0.0.dist-info}/entry_points.txt +0 -0
  92. {sticker_convert-2.13.3.0.dist-info → sticker_convert-2.17.0.0.dist-info}/licenses/LICENSE +0 -0
  93. {sticker_convert-2.13.3.0.dist-info → sticker_convert-2.17.0.0.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <Workspace
3
- version = "1.0">
4
- <FileRef
5
- location = "self:">
6
- </FileRef>
7
- </Workspace>
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <Workspace
3
+ version = "1.0">
4
+ <FileRef
5
+ location = "self:">
6
+ </FileRef>
7
+ </Workspace>
@@ -1,8 +1,8 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
- <plist version="1.0">
4
- <dict>
5
- <key>IDEDidComputeMac32BitWarning</key>
6
- <true/>
7
- </dict>
8
- </plist>
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>IDEDidComputeMac32BitWarning</key>
6
+ <true/>
7
+ </dict>
8
+ </plist>
@@ -1,14 +1,14 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
- <plist version="1.0">
4
- <dict>
5
- <key>SchemeUserState</key>
6
- <dict>
7
- <key>stickers StickerPackExtension.xcscheme_^#shared#^_</key>
8
- <dict>
9
- <key>orderHint</key>
10
- <integer>0</integer>
11
- </dict>
12
- </dict>
13
- </dict>
14
- </plist>
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>SchemeUserState</key>
6
+ <dict>
7
+ <key>stickers StickerPackExtension.xcscheme_^#shared#^_</key>
8
+ <dict>
9
+ <key>orderHint</key>
10
+ <integer>0</integer>
11
+ </dict>
12
+ </dict>
13
+ </dict>
14
+ </plist>
sticker_convert/job.py CHANGED
@@ -8,10 +8,11 @@ from datetime import datetime
8
8
  from multiprocessing import Manager, Process, Value
9
9
  from pathlib import Path
10
10
  from threading import Thread
11
- from typing import Any, Callable, Dict, List, Optional, Tuple
11
+ from typing import TYPE_CHECKING, Any, Callable, Dict, List, Optional, Tuple, Union, cast
12
12
  from urllib.parse import urlparse
13
13
 
14
14
  from sticker_convert.converter import StickerConvert
15
+ from sticker_convert.definitions import RUNTIME_STATE
15
16
  from sticker_convert.downloaders.download_band import DownloadBand
16
17
  from sticker_convert.downloaders.download_discord import DownloadDiscord
17
18
  from sticker_convert.downloaders.download_kakao import DownloadKakao
@@ -27,26 +28,24 @@ from sticker_convert.uploaders.upload_telegram import UploadTelegram
27
28
  from sticker_convert.uploaders.upload_viber import UploadViber
28
29
  from sticker_convert.uploaders.xcode_imessage import XcodeImessage
29
30
  from sticker_convert.utils.callback import CallbackReturn, CbQueueType, ResultsListType, WorkQueueType
30
- from sticker_convert.utils.files.json_resources_loader import OUTPUT_JSON
31
+ from sticker_convert.utils.chrome_remotedebug import CRD
32
+ from sticker_convert.utils.files.json_resources_loader import load_resource_json
31
33
  from sticker_convert.utils.files.metadata_handler import MetadataHandler
32
34
  from sticker_convert.utils.media.codec_info import CodecInfo
33
- from sticker_convert.utils.singletons import singletons
35
+ from sticker_convert.utils.translate import I
36
+
37
+ if TYPE_CHECKING:
38
+ from sticker_convert.utils.callback import CallbackCli, CallbackGui
34
39
 
35
40
 
36
41
  class Executor:
37
- def __init__(
38
- self,
39
- cb_msg: Callable[..., None],
40
- cb_msg_block: Callable[..., None],
41
- cb_bar: Callable[..., None],
42
- cb_ask_bool: Callable[..., bool],
43
- cb_ask_str: Callable[..., str],
44
- ) -> None:
45
- self.cb_msg = cb_msg
46
- self.cb_msg_block = cb_msg_block
47
- self.cb_bar = cb_bar
48
- self.cb_ask_bool = cb_ask_bool
49
- self.cb_ask_str = cb_ask_str
42
+ def __init__(self, cb: Union[CallbackGui, CallbackCli]) -> None:
43
+ self.cb_msg = cb.cb_msg
44
+ self.cb_msg_block = cb.cb_msg_block
45
+ self.cb_msg_dynamic = cb.cb_msg_dynamic
46
+ self.cb_bar = cb.cb_bar
47
+ self.cb_ask_bool = cb.cb_ask_bool
48
+ self.cb_ask_str = cb.cb_ask_str
50
49
 
51
50
  self.manager = Manager()
52
51
  self.work_queue: WorkQueueType = self.manager.Queue()
@@ -90,7 +89,7 @@ class Executor:
90
89
  def cb(
91
90
  self,
92
91
  action: Optional[str],
93
- args: Optional[Tuple[str, ...]] = None,
92
+ args: Optional[Tuple[Any, ...]] = None,
94
93
  kwargs: Optional[Dict[str, Any]] = None,
95
94
  ) -> None:
96
95
  if args is None:
@@ -105,6 +104,8 @@ class Executor:
105
104
  self.cb_bar(update_bar=1)
106
105
  elif action == "msg_block":
107
106
  self.cb_return.set_response(self.cb_msg_block(*args, **kwargs))
107
+ elif action == "msg_dynamic":
108
+ self.cb_msg_dynamic(*args, **kwargs)
108
109
  elif action == "ask_bool":
109
110
  self.cb_return.set_response(self.cb_ask_bool(*args, **kwargs))
110
111
  elif action == "ask_str":
@@ -130,16 +131,24 @@ class Executor:
130
131
  arg_dump.append("CredOption(REDACTED)")
131
132
  else:
132
133
  arg_dump.append(i)
133
- e = "##### EXCEPTION #####\n"
134
- e += "Function: " + repr(work_func) + "\n"
135
- e += "Arguments: " + repr(arg_dump) + "\n"
136
- e += traceback.format_exc()
137
- e += "#####################"
134
+ e = I(
135
+ "##### EXCEPTION #####\n"
136
+ "Function: {function}\n"
137
+ "Arguments: {args}\n"
138
+ "{tb}\n"
139
+ "#####################"
140
+ ).format(
141
+ function=repr(work_func),
142
+ args=repr(arg_dump),
143
+ tb=traceback.format_exc(),
144
+ )
138
145
  cb_queue.put(e)
139
146
 
140
147
  work_queue.put(None)
141
148
  cb_queue.put("__PROCESS_DONE__")
142
- singletons.close()
149
+ crd = cast(CRD, RUNTIME_STATE.get("crd"))
150
+ if crd:
151
+ crd.close()
143
152
 
144
153
  def start_workers(self, processes: int = 1) -> None:
145
154
  self.cb_thread_instance = Thread(
@@ -178,7 +187,9 @@ class Executor:
178
187
  process.join()
179
188
  if process.exitcode != 0 and self.is_cancel_job.value == 0:
180
189
  self.cb_msg(
181
- f"Warning: A process exited with error (code {process.exitcode})"
190
+ I("Warning: A process exited with error (code {})").format(
191
+ process.exitcode
192
+ )
182
193
  )
183
194
  except KeyboardInterrupt:
184
195
  pass
@@ -208,31 +219,16 @@ class Job:
208
219
  opt_comp: CompOption,
209
220
  opt_output: OutputOption,
210
221
  opt_cred: CredOption,
211
- cb_msg: Callable[..., None],
212
- cb_msg_block: Callable[..., None],
213
- cb_bar: Callable[..., None],
214
- cb_ask_bool: Callable[..., bool],
215
- cb_ask_str: Callable[..., str],
222
+ cb: Union[CallbackCli, CallbackGui],
216
223
  ) -> None:
217
224
  self.opt_input = opt_input
218
225
  self.opt_comp = opt_comp
219
226
  self.opt_output = opt_output
220
227
  self.opt_cred = opt_cred
221
- self.cb_msg = cb_msg
222
- self.cb_msg_block = cb_msg_block
223
- self.cb_bar = cb_bar
224
- self.cb_ask_bool = cb_ask_bool
225
- self.cb_ask_str = cb_ask_str
226
228
 
227
229
  self.out_urls: List[str] = []
228
230
 
229
- self.executor = Executor(
230
- self.cb_msg,
231
- self.cb_msg_block,
232
- self.cb_bar,
233
- self.cb_ask_bool,
234
- self.cb_ask_str,
235
- )
231
+ self.executor = Executor(cb)
236
232
 
237
233
  def start(self) -> int:
238
234
  if Path(self.opt_input.dir).is_dir() is False:
@@ -264,22 +260,20 @@ class Job:
264
260
  break
265
261
  if not success:
266
262
  code = 1
267
- self.executor.cb("An error occured during this run.")
263
+ self.executor.cb(I("An error occured during this run."))
268
264
  break
269
265
 
270
- msg = "##########\n"
271
- msg += "Summary:\n"
272
- msg += "##########\n"
266
+ msg = I("##########\nSummary:\n##########\n")
273
267
 
274
268
  msg += "\n"
275
269
  msg += "\n".join(summaries)
276
270
  msg += "\n"
277
271
 
278
272
  if self.out_urls:
279
- msg += "Export results:\n"
273
+ msg += I("Export results:\n")
280
274
  msg += "\n".join(self.out_urls)
281
275
  else:
282
- msg += "Export result: None"
276
+ msg += I("Export result: None")
283
277
 
284
278
  self.executor.cb(msg)
285
279
 
@@ -294,29 +288,31 @@ class Job:
294
288
  info_msg = ""
295
289
  error_msg = ""
296
290
 
297
- save_to_local_tip = ""
298
- save_to_local_tip += " If you want to upload the results by yourself,\n"
299
- save_to_local_tip += ' select "Save to local directory only" for output\n'
291
+ save_to_local_tip = I(
292
+ "\n"
293
+ " If you want to upload the results by yourself,\n"
294
+ ' select "Save to local directory only" for output\n'
295
+ )
300
296
 
301
297
  if Path(self.opt_input.dir).resolve() == Path(self.opt_output.dir).resolve():
302
- error_msg += "\n"
303
- error_msg += "[X] Input and output directories cannot be the same\n"
298
+ error_msg += I("\n[X] Input and output directories cannot be the same\n")
304
299
 
305
300
  if self.opt_input.option == "auto":
306
- error_msg += "\n"
307
- error_msg += "[X] Unrecognized URL input source\n"
301
+ error_msg += I("\n[X] Unrecognized URL input source\n")
308
302
 
309
303
  if self.opt_input.option != "local" and not self.opt_input.url:
310
- error_msg += "\n"
311
- error_msg += "[X] URL address cannot be empty.\n"
312
- error_msg += " If you only want to use local files,\n"
313
- error_msg += ' choose "Save to local directory only"\n'
314
- error_msg += ' in "Input source"\n'
304
+ error_msg += I(
305
+ "\n"
306
+ "[X] URL address cannot be empty.\n"
307
+ " If you only want to use local files,\n"
308
+ ' choose "Save to local directory only"\n'
309
+ ' in "Input source"\n'
310
+ )
315
311
 
316
312
  if (
317
313
  self.opt_input.option == "telegram" or self.opt_output.option == "telegram"
318
314
  ) and not self.opt_cred.telegram_token:
319
- error_msg += (
315
+ error_msg += I(
320
316
  "[X] Downloading from and uploading to telegram requires bot token.\n"
321
317
  )
322
318
  error_msg += save_to_local_tip
@@ -325,24 +321,26 @@ class Job:
325
321
  self.opt_input.option.startswith("discord")
326
322
  and not self.opt_cred.discord_token
327
323
  ):
328
- error_msg += "[X] Downloading from Discord requires token.\n"
324
+ error_msg += I("[X] Downloading from Discord requires token.\n")
329
325
 
330
326
  if self.opt_output.option == "telegram" and not self.opt_cred.telegram_userid:
331
- error_msg += "[X] Uploading to telegram requires user_id \n"
332
- error_msg += " (From real account, not bot account).\n"
327
+ error_msg += I(
328
+ "[X] Uploading to telegram requires user_id \n"
329
+ " (From real account, not bot account).\n"
330
+ )
333
331
  error_msg += save_to_local_tip
334
332
 
335
333
  if self.opt_output.option == "signal" and not (
336
334
  self.opt_cred.signal_uuid and self.opt_cred.signal_password
337
335
  ):
338
- error_msg += "[X] Uploading to signal requires uuid and password.\n"
336
+ error_msg += I("[X] Uploading to signal requires uuid and password.\n")
339
337
  error_msg += save_to_local_tip
340
338
 
341
339
  if self.opt_output.option == "viber" and not self.opt_cred.viber_auth:
342
- error_msg += "[X] Uploading to Viber requires auth data.\n"
340
+ error_msg += I("[X] Uploading to Viber requires auth data.\n")
343
341
  error_msg += save_to_local_tip
344
342
 
345
- output_presets = OUTPUT_JSON
343
+ output_presets = load_resource_json("output")
346
344
 
347
345
  input_option = self.opt_input.option
348
346
  output_option = self.opt_output.option
@@ -354,23 +352,37 @@ class Job:
354
352
  if not MetadataHandler.check_metadata_provided(
355
353
  self.opt_input.dir, input_option, metadata
356
354
  ):
357
- error_msg += f"[X] {output_presets[output_option]['full_name']} requires {metadata}\n"
355
+ error_msg += I("[X] {output_option} requires {metadata}\n").format(
356
+ output_option=output_presets[output_option]["full_name"],
357
+ metadata=metadata,
358
+ )
358
359
  if self.opt_input.option == "local":
359
- error_msg += f" {metadata} was not supplied and {metadata}.txt is absent\n"
360
+ error_msg += I(
361
+ " {metadata} was not supplied and {metadata}.txt is absent\n"
362
+ ).format(metadata=metadata)
360
363
  else:
361
- error_msg += f" {metadata} was not supplied and input source will not provide {metadata}\n"
362
- error_msg += (
363
- f" Supply the {metadata} by filling in the option, or\n"
364
- )
365
- error_msg += f" Create {metadata}.txt with the {metadata} name\n"
364
+ error_msg += I(
365
+ " {metadata} was not supplied and input source will not provide {metadata}\n"
366
+ ).format(metadata=metadata)
367
+ error_msg += I(
368
+ " Supply the {metadata} by filling in the option, or\n"
369
+ " Create {metadata}.txt with the {metadata} name\n"
370
+ ).format(metadata=metadata)
366
371
  else:
367
- info_msg += f"[!] {output_presets[output_option]['full_name']} requires {metadata}\n"
372
+ info_msg += I("[!] {output_option} requires {metadata}\n").format(
373
+ output_option=output_presets[output_option]["full_name"],
374
+ metadata=metadata,
375
+ )
368
376
  if self.opt_input.option == "local":
369
- info_msg += f" {metadata} was not supplied but {metadata}.txt is present\n"
370
- info_msg += f" Using {metadata} name in {metadata}.txt\n"
377
+ info_msg += I(
378
+ " {metadata} was not supplied but {metadata}.txt is present\n"
379
+ " Using {metadata} name in {metadata}.txt\n"
380
+ ).format(metadata=metadata)
371
381
  else:
372
- info_msg += f" {metadata} was not supplied but input source will provide {metadata}\n"
373
- info_msg += f" Using {metadata} provided by input source\n"
382
+ info_msg += I(
383
+ f" {metadata} was not supplied but input source will provide {metadata}\n"
384
+ f" Using {metadata} provided by input source\n"
385
+ ).format(metadata=metadata)
374
386
 
375
387
  if info_msg != "":
376
388
  self.executor.cb(info_msg)
@@ -392,9 +404,11 @@ class Job:
392
404
  and self.opt_comp.preset not in self.opt_output.option
393
405
  )
394
406
  ):
395
- msg = "Compression preset does not match export option\n"
396
- msg += "You may continue, but the files will need to be compressed again before export\n"
397
- msg += "You are recommended to choose the matching option for compression and output. Continue?"
407
+ msg = I(
408
+ "Compression preset does not match export option\n"
409
+ "You may continue, but the files will need to be compressed again before export\n"
410
+ "You are recommended to choose the matching option for compression and output. Continue?"
411
+ )
398
412
 
399
413
  self.executor.cb("ask_bool", (msg,))
400
414
  response = self.executor.cb_return.get_response()
@@ -409,8 +423,10 @@ class Job:
409
423
  ("color_power", self.opt_comp.color_power),
410
424
  ):
411
425
  if value < -1:
412
- error_msg += "\n"
413
- error_msg += f"[X] {param} should be between -1 and positive infinity. {value} was given."
426
+ error_msg += I(
427
+ "\n"
428
+ "[X] {param} should be between -1 and positive infinity. {value} was given."
429
+ ).format(param=param, value=value)
414
430
 
415
431
  if self.opt_comp.scale_filter not in (
416
432
  "nearest",
@@ -420,13 +436,11 @@ class Job:
420
436
  "bicubic",
421
437
  "lanczos",
422
438
  ):
423
- error_msg += "\n"
424
- error_msg += (
425
- f"[X] scale_filter {self.opt_comp.scale_filter} is not valid option\n"
426
- )
427
- error_msg += (
439
+ error_msg += I(
440
+ "\n"
441
+ "[X] scale_filter {scale_filter} is not valid option\n"
428
442
  " Valid options: nearest, box, bilinear, hamming, bicubic, lanczos"
429
- )
443
+ ).format(scale_filter=self.opt_comp.scale_filter)
430
444
 
431
445
  if self.opt_comp.quantize_method not in (
432
446
  "imagequant",
@@ -435,18 +449,19 @@ class Job:
435
449
  "mediancut",
436
450
  "none",
437
451
  ):
438
- error_msg += "\n"
439
- error_msg += f"[X] quantize_method {self.opt_comp.quantize_method} is not valid option\n"
440
- error_msg += " Valid options: imagequant, fastoctree, maxcoverage, mediancut, none"
452
+ I(
453
+ "\n"
454
+ "[X] quantize_method {quantize_method} is not valid option\n"
455
+ " Valid options: imagequant, fastoctree, maxcoverage, mediancut, none"
456
+ ).format(quantize_method=self.opt_comp.quantize_method)
441
457
 
442
458
  if self.opt_comp.bg_color:
443
459
  try:
444
460
  _, _, _ = bytes.fromhex(self.opt_comp.bg_color)
445
461
  except ValueError:
446
- error_msg += "\n"
447
- error_msg += (
448
- f"[X] bg_color {self.opt_comp.bg_color} is not valid color hex"
449
- )
462
+ error_msg += I(
463
+ "\n[X] bg_color {bg_color} is not valid color hex"
464
+ ).format(bg_color=self.opt_comp.bg_color)
450
465
 
451
466
  # Warn about unable to download animated Kakao stickers with such link
452
467
  if (
@@ -454,12 +469,14 @@ class Job:
454
469
  and urlparse(self.opt_input.url).netloc == "e.kakao.com"
455
470
  and not self.opt_cred.kakao_auth_token
456
471
  ):
457
- msg = "To download ANIMATED stickers from e.kakao.com,\n"
458
- msg += "you need to generate auth_token.\n"
459
- msg += "Alternatively, you can generate share link (emoticon.kakao.com/items/xxxxx)\n"
460
- msg += "from Kakao app on phone.\n"
461
- msg += "You are adviced to read documentations.\n"
462
- msg += "If you continue, you will only download static stickers. Continue?"
472
+ msg = I(
473
+ "To download ANIMATED stickers from e.kakao.com,\n"
474
+ "you need to generate auth_token.\n"
475
+ "Alternatively, you can generate share link (emoticon.kakao.com/items/xxxxx)\n"
476
+ "from Kakao app on phone.\n"
477
+ "You are adviced to read documentations.\n"
478
+ "If you continue, you will only download static stickers. Continue?"
479
+ )
463
480
 
464
481
  self.executor.cb("ask_bool", (msg,))
465
482
  response = self.executor.cb_return.get_response()
@@ -489,15 +506,22 @@ class Job:
489
506
 
490
507
  related_files = MetadataHandler.get_files_related_to_sticker_convert(path)
491
508
  if any(i for i in path.iterdir() if i not in related_files):
492
- msg = "WARNING: {} directory is set to {}.\n"
493
- msg += 'It does not have default name of "{}",\n'
494
- msg += "and It seems like it contains PERSONAL DATA.\n"
495
- msg += "During execution, contents of this directory\n"
496
- msg += 'maybe MOVED to "archive_*".\n'
497
- msg += "THIS MAY CAUSE DAMAGE TO YOUR DATA. Continue?"
509
+ msg = I(
510
+ "WARNING: {path_type} directory is set to {path}.\n"
511
+ 'It does not have default name of "{default_name}",\n'
512
+ "and It seems like it contains PERSONAL DATA.\n"
513
+ "During execution, contents of this directory\n"
514
+ 'maybe MOVED to "archive_*".\n'
515
+ "THIS MAY CAUSE DAMAGE TO YOUR DATA. Continue?"
516
+ )
498
517
 
499
518
  self.executor.cb(
500
- "ask_bool", (msg.format(path_type, path, default_name),)
519
+ "ask_bool",
520
+ (
521
+ msg.format(
522
+ path_type=path_type, path=path, default_name=default_name
523
+ ),
524
+ ),
501
525
  )
502
526
  response = self.executor.cb_return.get_response()
503
527
 
@@ -525,16 +549,18 @@ class Job:
525
549
 
526
550
  if self.opt_input.option == "local":
527
551
  self.executor.cb(
528
- "Skip moving old files in input directory as input source is local"
552
+ I("Skip moving old files in input directory as input source is local")
529
553
  )
530
554
  elif len(in_dir_files) == 0:
531
555
  self.executor.cb(
532
- "Skip moving old files in input directory as input source is empty"
556
+ I("Skip moving old files in input directory as input source is empty")
533
557
  )
534
558
  else:
535
559
  archive_dir = Path(self.opt_input.dir, dir_name)
536
560
  self.executor.cb(
537
- f"Moving old files in input directory to {archive_dir} as input source is not local"
561
+ I(
562
+ "Moving old files in input directory to {archive_dir} as input source is not local"
563
+ ).format(archive_dir=archive_dir)
538
564
  )
539
565
  archive_dir.mkdir(exist_ok=True)
540
566
  for old_path in in_dir_files:
@@ -543,15 +569,19 @@ class Job:
543
569
 
544
570
  if self.opt_comp.no_compress:
545
571
  self.executor.cb(
546
- "Skip moving old files in output directory as no_compress is True"
572
+ I("Skip moving old files in output directory as no_compress is True")
547
573
  )
548
574
  elif len(out_dir_files) == 0:
549
575
  self.executor.cb(
550
- "Skip moving old files in output directory as output source is empty"
576
+ I("Skip moving old files in output directory as output source is empty")
551
577
  )
552
578
  else:
553
579
  archive_dir = Path(self.opt_output.dir, dir_name)
554
- self.executor.cb(f"Moving old files in output directory to {archive_dir}")
580
+ self.executor.cb(
581
+ I("Moving old files in output directory to {archive_dir}").format(
582
+ archive_dir=archive_dir
583
+ )
584
+ )
555
585
  os.makedirs(archive_dir)
556
586
  for old_path in out_dir_files:
557
587
  new_path = Path(archive_dir, old_path.name)
@@ -587,10 +617,10 @@ class Job:
587
617
  downloaders.append(DownloadDiscord.start)
588
618
 
589
619
  if len(downloaders) > 0:
590
- self.executor.cb("Downloading...")
620
+ self.executor.cb(I("Downloading..."))
591
621
  else:
592
- self.executor.cb("Skipped download (No files to download)")
593
- return True, "Download: Skipped (No files to download)"
622
+ self.executor.cb(I("Skipped download (No files to download)"))
623
+ return True, I("Download: Skipped (No files to download)")
594
624
 
595
625
  self.executor.start_workers(processes=1)
596
626
 
@@ -620,7 +650,7 @@ class Job:
620
650
 
621
651
  def compress(self) -> Tuple[bool, str]:
622
652
  if self.opt_comp.no_compress is True:
623
- self.executor.cb("Skipped compression (no_compress is set to True)")
653
+ self.executor.cb(I("Skipped compression (no_compress is set to True)"))
624
654
  in_dir_files = [
625
655
  i
626
656
  for i in sorted(self.opt_input.dir.iterdir())
@@ -633,15 +663,17 @@ class Job:
633
663
  ]
634
664
  if len(in_dir_files) == 0:
635
665
  self.executor.cb(
636
- "Input directory is empty, nothing to copy to output directory"
666
+ I("Input directory is empty, nothing to copy to output directory")
637
667
  )
638
668
  elif len(out_dir_files) != 0:
639
669
  self.executor.cb(
640
- "Output directory is not empty, not copying files from input directory"
670
+ I(
671
+ "Output directory is not empty, not copying files from input directory"
672
+ )
641
673
  )
642
674
  else:
643
675
  self.executor.cb(
644
- "Output directory is empty, copying files from input directory"
676
+ I("Output directory is empty, copying files from input directory")
645
677
  )
646
678
  for i in in_dir_files:
647
679
  src_f = Path(self.opt_input.dir, i.name)
@@ -674,7 +706,7 @@ class Job:
674
706
 
675
707
  in_fs_count = len(in_fs)
676
708
  if in_fs_count == 0:
677
- self.executor.cb("Skipped compression (No files to compress)")
709
+ self.executor.cb(I("Skipped compression (No files to compress)"))
678
710
  return True, "Compress: Skipped (No files to compress)"
679
711
 
680
712
  self.executor.cb(msg)
@@ -717,10 +749,10 @@ class Job:
717
749
 
718
750
  def export(self) -> Tuple[bool, str]:
719
751
  if self.opt_output.option == "local":
720
- self.executor.cb("Skipped export (Saving to local directory only)")
721
- return True, "Export: Skipped (Saving to local directory only)"
752
+ self.executor.cb(I("Skipped export (Saving to local directory only)"))
753
+ return True, I("Export: Skipped (Saving to local directory only)")
722
754
 
723
- self.executor.cb("Exporting...")
755
+ self.executor.cb(I("Exporting..."))
724
756
 
725
757
  exporters: List[Callable[..., Tuple[int, int, List[str]]]] = []
726
758
 
@@ -762,7 +794,11 @@ class Job:
762
794
  ) as f:
763
795
  f.write("\n".join(self.out_urls))
764
796
  else:
765
- self.executor.cb("An error occured while exporting stickers")
766
- return False, f"Export: {stickers_ok}/{stickers_total} stickers success"
767
-
768
- return True, f"Export: {stickers_ok}/{stickers_total} stickers success"
797
+ self.executor.cb(I("An error occured while exporting stickers"))
798
+ return False, I(
799
+ "Export: {stickers_ok}/{stickers_total} stickers success"
800
+ ).format(stickers_ok=stickers_ok, stickers_total=stickers_total)
801
+
802
+ return True, I(
803
+ "Export: {stickers_ok}/{stickers_total} stickers success"
804
+ ).format(stickers_ok=stickers_ok, stickers_total=stickers_total)
@@ -223,6 +223,7 @@ class CredOption(BaseOption):
223
223
  kakao_auth_token: str = ""
224
224
  kakao_username: str = ""
225
225
  kakao_password: str = ""
226
+ kakao_device_uuid: str = ""
226
227
  kakao_country_code: str = ""
227
228
  kakao_phone_number: str = ""
228
229
  line_cookies: str = ""
File without changes