sticker-convert 2.8.14__py3-none-any.whl → 2.9.1__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 CHANGED
@@ -17,6 +17,7 @@ from sticker_convert.job_option import CompOption, CredOption, InputOption, Outp
17
17
  from sticker_convert.utils.auth.get_kakao_auth import GetKakaoAuth
18
18
  from sticker_convert.utils.auth.get_line_auth import GetLineAuth
19
19
  from sticker_convert.utils.auth.get_signal_auth import GetSignalAuth
20
+ from sticker_convert.utils.auth.get_viber_auth import GetViberAuth
20
21
  from sticker_convert.utils.callback import Callback
21
22
  from sticker_convert.utils.files.json_manager import JsonManager
22
23
  from sticker_convert.utils.url_detect import UrlDetect
@@ -452,6 +453,9 @@ class CLI:
452
453
  line_cookies=args.line_cookies
453
454
  if args.line_cookies
454
455
  else creds.get("line", {}).get("cookies"),
456
+ viber_auth=args.viber_auth
457
+ if args.viber_auth
458
+ else creds.get("viber", {}).get("auth"),
455
459
  )
456
460
 
457
461
  if args.kakao_get_auth:
@@ -501,6 +505,20 @@ class CLI:
501
505
  "Failed to get Line cookies. Have you logged in the web browser?"
502
506
  )
503
507
 
508
+ if args.viber_get_auth:
509
+ get_viber_auth = GetViberAuth(self.cb.ask_str)
510
+
511
+ viber_bin_path = None
512
+ if args.viber_bin_path:
513
+ viber_bin_path = args.viber_bin_path
514
+
515
+ viber_auth, msg = get_viber_auth.get_cred(viber_bin_path)
516
+
517
+ if viber_auth:
518
+ opt_cred.viber_auth = viber_auth
519
+
520
+ self.cb.msg(msg)
521
+
504
522
  if args.save_cred:
505
523
  creds_path = CONFIG_DIR / "creds.json"
506
524
  JsonManager.save_json(creds_path, opt_cred.to_dict())
@@ -47,7 +47,7 @@ class MetadataKakao:
47
47
  headers = {"User-Agent": "Android"}
48
48
 
49
49
  response = requests.get(url, headers=headers)
50
- soup = BeautifulSoup(response.text, "html.parser")
50
+ soup = BeautifulSoup(response.content.decode("utf-8", "ignore"), "html.parser")
51
51
 
52
52
  pack_title_tag = soup.find("title") # type: ignore
53
53
  if not pack_title_tag:
sticker_convert/gui.py CHANGED
@@ -159,6 +159,8 @@ class GUI(Window):
159
159
  self.kakao_country_code_var = StringVar(self)
160
160
  self.kakao_phone_number_var = StringVar(self)
161
161
  self.line_cookies_var = StringVar(self)
162
+ self.viber_auth_var = StringVar(self)
163
+ self.viber_bin_path_var = StringVar(self)
162
164
 
163
165
  # Config
164
166
  self.settings_save_cred_var = BooleanVar()
@@ -385,6 +387,7 @@ class GUI(Window):
385
387
  self.creds.get("kakao", {}).get("phone_number", "")
386
388
  )
387
389
  self.line_cookies_var.set(self.creds.get("line", {}).get("cookies", ""))
390
+ self.viber_auth_var.set(self.creds.get("viber", {}).get("auth", ""))
388
391
 
389
392
  def get_input_name(self) -> str:
390
393
  return [
@@ -545,6 +548,7 @@ class GUI(Window):
545
548
  kakao_country_code=self.kakao_country_code_var.get(),
546
549
  kakao_phone_number=self.kakao_phone_number_var.get(),
547
550
  line_cookies=self.line_cookies_var.get(),
551
+ viber_auth=self.viber_auth_var.get(),
548
552
  )
549
553
 
550
554
  def start_process(self) -> None:
@@ -771,6 +775,11 @@ class GUI(Window):
771
775
  else:
772
776
  self.cred_frame.telegram_userid_entry.config(bootstyle="default") # type: ignore
773
777
 
778
+ if output_option == "viber" and not self.viber_auth_var.get():
779
+ self.cred_frame.viber_auth_entry.config(bootstyle="warning") # type: ignore
780
+ else:
781
+ self.cred_frame.viber_auth_entry.config(bootstyle="default") # type: ignore
782
+
774
783
  if (
775
784
  urlparse(url).netloc == "e.kakao.com"
776
785
  and not self.kakao_auth_token_var.get()
@@ -8,6 +8,7 @@ from sticker_convert.gui_components.frames.right_clicker import RightClicker
8
8
  from sticker_convert.gui_components.windows.kakao_get_auth_window import KakaoGetAuthWindow
9
9
  from sticker_convert.gui_components.windows.line_get_auth_window import LineGetAuthWindow
10
10
  from sticker_convert.gui_components.windows.signal_get_auth_window import SignalGetAuthWindow
11
+ from sticker_convert.gui_components.windows.viber_get_auth_window import ViberGetAuthWindow
11
12
 
12
13
  if TYPE_CHECKING:
13
14
  from sticker_convert.gui import GUI # type: ignore
@@ -103,6 +104,20 @@ class CredFrame(LabelFrame):
103
104
  bootstyle="secondary", # type: ignore
104
105
  )
105
106
 
107
+ self.viber_auth_lbl = Label(
108
+ self, text="Viber auth", width=18, justify="left", anchor="w"
109
+ )
110
+ self.viber_auth_entry = Entry(
111
+ self, textvariable=self.gui.viber_auth_var, width=35
112
+ )
113
+ self.viber_auth_entry.bind("<Button-3><ButtonRelease-3>", RightClicker)
114
+ self.viber_get_auth_btn = Button(
115
+ self,
116
+ text="Generate",
117
+ command=self.cb_viber_get_auth,
118
+ bootstyle="secondary", # type: ignore
119
+ )
120
+
106
121
  self.help_btn = Button(
107
122
  self,
108
123
  text="Get help",
@@ -133,6 +148,9 @@ class CredFrame(LabelFrame):
133
148
  self.line_cookies_lbl.grid(column=0, row=6, sticky="w", padx=3, pady=3)
134
149
  self.line_cookies_entry.grid(column=1, row=6, sticky="w", padx=3, pady=3)
135
150
  self.line_get_auth_btn.grid(column=2, row=6, sticky="e", padx=3, pady=3)
151
+ self.viber_auth_lbl.grid(column=0, row=7, sticky="w", padx=3, pady=3)
152
+ self.viber_auth_entry.grid(column=1, row=7, sticky="w", padx=3, pady=3)
153
+ self.viber_get_auth_btn.grid(column=2, row=7, sticky="e", padx=3, pady=3)
136
154
  self.help_btn.grid(column=2, row=8, sticky="e", padx=3, pady=3)
137
155
 
138
156
  def cb_cred_help(self, *_: Any) -> None:
@@ -150,6 +168,9 @@ class CredFrame(LabelFrame):
150
168
  def cb_line_get_auth(self, *_: Any) -> None:
151
169
  LineGetAuthWindow(self.gui)
152
170
 
171
+ def cb_viber_get_auth(self, *_: Any) -> None:
172
+ ViberGetAuthWindow(self.gui)
173
+
153
174
  def set_states(self, state: str) -> None:
154
175
  self.signal_uuid_entry.config(state=state)
155
176
  self.signal_password_entry.config(state=state)
@@ -0,0 +1,149 @@
1
+ #!/usr/bin/env python3
2
+ import platform
3
+ from functools import partial
4
+ from pathlib import Path
5
+ from subprocess import Popen
6
+ from tkinter import filedialog
7
+ from typing import Any
8
+
9
+ from ttkbootstrap import Button, Entry, Frame, Label # type: ignore
10
+
11
+ from sticker_convert.gui_components.gui_utils import GUIUtils
12
+ from sticker_convert.gui_components.windows.base_window import BaseWindow
13
+ from sticker_convert.utils.auth.get_viber_auth import GetViberAuth
14
+
15
+
16
+ class ViberGetAuthWindow(BaseWindow):
17
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
18
+ super().__init__(*args, **kwargs)
19
+
20
+ self.title("Get Viber auth data")
21
+
22
+ self.cb_msg_block_viber = partial(self.gui.cb_msg_block, parent=self)
23
+ self.cb_ask_str_viber = partial(self.gui.cb_ask_str, parent=self)
24
+
25
+ self.frame_info = Frame(self.scrollable_frame)
26
+ self.frame_btns = Frame(self.scrollable_frame)
27
+ self.frame_config = Frame(self.scrollable_frame)
28
+
29
+ self.frame_info.grid(column=0, row=0, sticky="news", padx=3, pady=3)
30
+ self.frame_btns.grid(column=0, row=1, sticky="news", padx=3, pady=3)
31
+ self.frame_config.grid(column=0, row=2, sticky="news", padx=3, pady=3)
32
+
33
+ # Info frame
34
+ self.explanation_lbl0 = Label(
35
+ self.frame_info,
36
+ text="Please install Viber Desktop and login first.",
37
+ justify="left",
38
+ anchor="w",
39
+ )
40
+ self.explanation_lbl1 = Label(
41
+ self.frame_info,
42
+ text="It may take a minute to get auth data.",
43
+ justify="left",
44
+ anchor="w",
45
+ )
46
+ self.explanation_lbl2 = None
47
+ if platform.system() == "Darwin":
48
+ self.explanation_lbl2 = Label(
49
+ self.frame_info,
50
+ text="You need to disable SIP and may be asked for user password.",
51
+ justify="left",
52
+ anchor="w",
53
+ )
54
+ else:
55
+ self.explanation_lbl2 = Label(
56
+ self.frame_info,
57
+ text="You may be asked for admin password.",
58
+ justify="left",
59
+ anchor="w",
60
+ )
61
+
62
+ self.explanation_lbl0.grid(column=0, row=0, sticky="w", padx=3, pady=3)
63
+ self.explanation_lbl1.grid(column=0, row=1, sticky="w", padx=3, pady=3)
64
+ self.explanation_lbl2.grid(column=0, row=2, sticky="w", padx=3, pady=3)
65
+
66
+ # Start button frame
67
+ self.launch_btn = Button(
68
+ self.frame_btns,
69
+ text="Launch Viber Desktop",
70
+ command=self.cb_launch_viber,
71
+ bootstyle="secondary", # type: ignore
72
+ )
73
+
74
+ self.get_cred_btn = Button(
75
+ self.frame_btns,
76
+ text="Get auth data",
77
+ command=self.cb_get_cred,
78
+ bootstyle="default", # type: ignore
79
+ )
80
+
81
+ self.launch_btn.pack()
82
+ self.get_cred_btn.pack()
83
+
84
+ # Config frame
85
+ self.setdir_lbl = Label(
86
+ self.frame_config,
87
+ text=self.gui.help["cred"]["viber_bin_path"],
88
+ justify="left",
89
+ anchor="w",
90
+ )
91
+
92
+ self.setdir_entry = Entry(
93
+ self.frame_config,
94
+ textvariable=self.gui.viber_bin_path_var,
95
+ width=32,
96
+ )
97
+ self.setdir_btn = Button(
98
+ self.frame_config,
99
+ text="Choose",
100
+ command=self.cb_setdir,
101
+ width=8,
102
+ bootstyle="secondary", # type: ignore
103
+ )
104
+
105
+ self.setdir_lbl.grid(column=0, row=0, columnspan=2, sticky="w", padx=3, pady=3)
106
+ self.setdir_entry.grid(column=0, row=1, sticky="w", padx=3, pady=3)
107
+ self.setdir_btn.grid(column=1, row=1, sticky="e", padx=3, pady=3)
108
+
109
+ GUIUtils.finalize_window(self)
110
+
111
+ def cb_get_cred(self) -> None:
112
+ m = GetViberAuth(self.cb_ask_str_viber)
113
+
114
+ viber_bin_path = None
115
+ if self.gui.viber_bin_path_var.get():
116
+ viber_bin_path = self.gui.viber_bin_path_var.get()
117
+
118
+ viber_auth, msg = m.get_cred(viber_bin_path)
119
+
120
+ if viber_auth:
121
+ if not self.gui.creds.get("viber"):
122
+ self.gui.creds["viber"] = {}
123
+ self.gui.creds["viber"]["auth"] = viber_auth
124
+ self.gui.viber_auth_var.set(viber_auth)
125
+
126
+ self.gui.save_creds()
127
+ self.gui.highlight_fields()
128
+
129
+ self.cb_msg_block_viber(msg)
130
+
131
+ def cb_launch_viber(self) -> None:
132
+ m = GetViberAuth(self.cb_ask_str_viber)
133
+ viber_bin_path = m.get_viber_desktop()
134
+
135
+ if self.gui.viber_auth_var.get():
136
+ viber_bin_path = self.gui.viber_auth_var.get()
137
+
138
+ if viber_bin_path:
139
+ Popen([viber_bin_path])
140
+ else:
141
+ self.cb_msg_block_viber("Error: Viber Desktop not installed.")
142
+
143
+ def cb_setdir(self) -> None:
144
+ orig_input_dir = self.gui.viber_bin_path_var.get()
145
+ if not Path(orig_input_dir).is_dir():
146
+ orig_input_dir = ""
147
+ input_dir = filedialog.askdirectory(initialdir=orig_input_dir)
148
+ if input_dir:
149
+ self.gui.viber_bin_path_var.set(input_dir)
sticker_convert/job.py CHANGED
@@ -21,6 +21,7 @@ from sticker_convert.job_option import CompOption, CredOption, InputOption, Outp
21
21
  from sticker_convert.uploaders.compress_wastickers import CompressWastickers
22
22
  from sticker_convert.uploaders.upload_signal import UploadSignal
23
23
  from sticker_convert.uploaders.upload_telegram import UploadTelegram
24
+ from sticker_convert.uploaders.upload_viber import UploadViber
24
25
  from sticker_convert.uploaders.xcode_imessage import XcodeImessage
25
26
  from sticker_convert.utils.callback import CallbackReturn, CbQueueType, ResultsListType, WorkQueueType
26
27
  from sticker_convert.utils.files.json_resources_loader import OUTPUT_JSON
@@ -305,6 +306,10 @@ class Job:
305
306
  error_msg += "[X] Uploading to signal requires uuid and password.\n"
306
307
  error_msg += save_to_local_tip
307
308
 
309
+ if self.opt_output.option == "viber" and not self.opt_cred.viber_auth:
310
+ error_msg += "[X] Uploading to Viber requires auth data.\n"
311
+ error_msg += save_to_local_tip
312
+
308
313
  output_presets = OUTPUT_JSON
309
314
 
310
315
  input_option = self.opt_input.option
@@ -656,6 +661,9 @@ class Job:
656
661
  if self.opt_output.option == "imessage":
657
662
  exporters.append(XcodeImessage.start)
658
663
 
664
+ if self.opt_output.option == "viber":
665
+ exporters.append(UploadViber.start)
666
+
659
667
  self.executor.start_workers(processes=1)
660
668
 
661
669
  for exporter in exporters:
@@ -222,6 +222,7 @@ class CredOption(BaseOption):
222
222
  kakao_country_code: str = ""
223
223
  kakao_phone_number: str = ""
224
224
  line_cookies: str = ""
225
+ viber_auth: str = ""
225
226
 
226
227
  def to_dict(self) -> Dict[Any, Any]:
227
228
  return {
@@ -235,4 +236,5 @@ class CredOption(BaseOption):
235
236
  "phone_number": self.kakao_phone_number,
236
237
  },
237
238
  "line": {"cookies": self.line_cookies},
239
+ "viber": {"auth": self.viber_auth},
238
240
  }
@@ -338,8 +338,8 @@
338
338
  "vid": ".png"
339
339
  },
340
340
  "fps": {
341
- "min": 1,
342
- "max": 1,
341
+ "min": 0,
342
+ "max": 0,
343
343
  "power": 1
344
344
  },
345
345
  "res": {
@@ -69,6 +69,9 @@
69
69
  "kakao_phone_number": "Set Kakao phone number (Phone number associated with your Kakao account)\nDo NOT enter country code\nExample: 7700900142\nUsed for send / receive verification code via SMS.\nRequired for generating Kakao auth_token.",
70
70
  "line_get_auth": "Get Line cookies from browser, which is required to create custom message stickers.",
71
71
  "line_cookies": "Set Line cookies, which is required to create custom message stickers.",
72
+ "viber_auth": "Set Viber authentication data.\nRequired for uploading Viber stickers.",
73
+ "viber_get_auth": "Generate Viber authentication data.",
74
+ "viber_bin_path": "Specify location of Viber Desktop application.\nUseful for portable installation.",
72
75
  "save_cred": "Save Signal and Telegram credentials."
73
76
  }
74
77
  }
@@ -0,0 +1,26 @@
1
+ #!/bin/bash
2
+ # Reference: https://github.com/hajzer/bash-memory-dump
3
+
4
+ OS_PAGESIZE=`getconf PAGESIZE`
5
+
6
+ PID=$1
7
+ PID_MAPS=/proc/$PID/maps
8
+ PID_MEM=/proc/$PID/mem
9
+
10
+ rm -f /tmp/viber.dmp.$PID
11
+ grep rw-p $PID_MAPS |
12
+ while IFS='' read -r line || [[ -n "$line" ]]; do
13
+ range=`echo $line | awk '{print $1;}'`
14
+
15
+ vma_start=$(( 0x`echo $range | cut -d- -f1` ))
16
+ vma_end=$(( 0x`echo $range | cut -d- -f2` ))
17
+ vma_size=$(( $vma_end - $vma_start ))
18
+
19
+ dd_start=$(( $vma_start / $OS_PAGESIZE ))
20
+ dd_bs=$OS_PAGESIZE
21
+ dd_count=$(( $vma_size / $OS_PAGESIZE ))
22
+
23
+ set +e
24
+ dd if="$PID_MEM" bs="$dd_bs" skip="$dd_start" count="$dd_count"
25
+ set -e
26
+ done
@@ -0,0 +1,8 @@
1
+ param($processId)
2
+ $dumpFilePath = "$Env:TEMP\memdump.bin.$processId"
3
+
4
+ Powershell -c rundll32.exe C:\Windows\System32\comsvcs.dll, MiniDump $processId $dumpFilePath full
5
+
6
+ icacls $dumpFilePath /remove "Everyone"
7
+ icacls $dumpFilePath /grant "Everyone:(r)"
8
+ icacls $dumpFilePath /grant "Everyone:(w)"
@@ -23,6 +23,14 @@
23
23
  "author": false
24
24
  }
25
25
  },
26
+ "viber": {
27
+ "full_name": "Upload to Viber",
28
+ "help": "Upload to Viber",
29
+ "metadata_requirements": {
30
+ "title": true,
31
+ "author": false
32
+ }
33
+ },
26
34
  "whatsapp": {
27
35
  "full_name": "Compress to .wastickers (WhatsApp)",
28
36
  "help": "Create a .wastickers file for uploading to WhatsApp",
@@ -0,0 +1,167 @@
1
+ #!/usr/bin/env python3
2
+ import copy
3
+ import json
4
+ import shutil
5
+ import zipfile
6
+ from pathlib import Path
7
+ from typing import Any, Dict, List
8
+
9
+ import requests
10
+
11
+ from sticker_convert.converter import StickerConvert
12
+ from sticker_convert.job_option import CompOption, CredOption, OutputOption
13
+ from sticker_convert.uploaders.upload_base import UploadBase
14
+ from sticker_convert.utils.callback import CallbackProtocol, CallbackReturn
15
+ from sticker_convert.utils.files.cache_store import CacheStore
16
+ from sticker_convert.utils.files.metadata_handler import MetadataHandler
17
+ from sticker_convert.utils.files.sanitize_filename import sanitize_filename
18
+ from sticker_convert.utils.media.format_verify import FormatVerify
19
+
20
+
21
+ class UploadViber(UploadBase):
22
+ def __init__(self, *args: Any, **kwargs: Any) -> None:
23
+ super().__init__(*args, **kwargs)
24
+
25
+ self.base_spec.set_size_max(0)
26
+ self.base_spec.square = True
27
+
28
+ self.png_spec = copy.deepcopy(self.base_spec)
29
+ self.png_spec.set_res_max(490)
30
+ self.png_spec.set_format((".png",))
31
+
32
+ self.png_cover_spec = copy.deepcopy(self.base_spec)
33
+ self.png_cover_spec.set_res_max(120)
34
+ self.png_spec.set_format((".png",))
35
+
36
+ self.opt_comp_merged = copy.deepcopy(self.opt_comp)
37
+ self.opt_comp_merged.merge(self.png_spec)
38
+
39
+ def upload_stickers_viber(self) -> List[str]:
40
+ urls: List[str] = []
41
+
42
+ if not self.opt_cred.viber_auth:
43
+ self.cb.put("Viber auth required for uploading to viber")
44
+ return urls
45
+
46
+ upload_data_base: Dict[str, str] = {}
47
+ for i in self.opt_cred.viber_auth.split(";"):
48
+ j = i.split(":")
49
+ upload_data_base[j[0]] = j[1]
50
+
51
+ if upload_data_base.get("member_id") is None:
52
+ self.cb.put("Invalid Viber auth: Missing member_id")
53
+ return urls
54
+ if upload_data_base.get("m_token") is None:
55
+ self.cb.put("Invalid Viber auth: Missing m_token")
56
+ return urls
57
+ if upload_data_base.get("m_ts") is None:
58
+ self.cb.put("Invalid Viber auth: Missing m_ts")
59
+ return urls
60
+
61
+ title, author, _ = MetadataHandler.get_metadata(
62
+ self.opt_output.dir,
63
+ title=self.opt_output.title,
64
+ author=self.opt_output.author,
65
+ )
66
+ if title is None:
67
+ raise TypeError(f"title cannot be {title}")
68
+ if author is None:
69
+ author = ""
70
+
71
+ packs = MetadataHandler.split_sticker_packs(
72
+ self.opt_output.dir,
73
+ title=title,
74
+ file_per_pack=24,
75
+ separate_image_anim=False,
76
+ )
77
+
78
+ cover_path_old = MetadataHandler.get_cover(self.opt_output.dir)
79
+ if cover_path_old:
80
+ cover_path = cover_path_old
81
+ else:
82
+ cover_path_old = MetadataHandler.get_stickers_present(self.opt_output.dir)[
83
+ 0
84
+ ]
85
+ cover_path = self.opt_output.dir / "cover.png"
86
+
87
+ if not FormatVerify.check_file(cover_path_old, spec=self.png_cover_spec):
88
+ StickerConvert.convert(
89
+ cover_path_old,
90
+ cover_path,
91
+ self.opt_comp_merged,
92
+ self.cb,
93
+ self.cb_return,
94
+ )
95
+
96
+ for pack_title, stickers in packs.items():
97
+ with CacheStore.get_cache_store(path=self.opt_comp.cache_dir) as tempdir:
98
+ for num, src in enumerate(stickers):
99
+ self.cb.put(f"Verifying {src} for uploading to Viber")
100
+
101
+ dst = Path(tempdir, f"{str(num).zfill(2)}.png")
102
+
103
+ if FormatVerify.check_file(src, spec=self.png_spec):
104
+ shutil.copy(src, dst)
105
+ else:
106
+ StickerConvert.convert(
107
+ Path(src),
108
+ Path(dst),
109
+ self.opt_comp_merged,
110
+ self.cb,
111
+ self.cb_return,
112
+ )
113
+
114
+ out_f = Path(
115
+ self.opt_output.dir, sanitize_filename(pack_title + ".zip")
116
+ ).as_posix()
117
+
118
+ with zipfile.ZipFile(out_f, "w", zipfile.ZIP_DEFLATED) as zipf:
119
+ for file in Path(tempdir).iterdir():
120
+ file_path = Path(tempdir, file.name)
121
+ zipf.write(file_path, arcname=file_path.name)
122
+
123
+ upload_data = copy.deepcopy(upload_data_base)
124
+ upload_data["title"] = pack_title
125
+ upload_data["description"] = author
126
+ upload_data["shareable"] = "1"
127
+
128
+ with open(out_f, "rb") as f, open(cover_path, "rb") as g:
129
+ r = requests.post(
130
+ "https://market.api.viber.com/2/users/custom-sticker-packs/create",
131
+ files={
132
+ "file": ("upload.zip", f),
133
+ "file_icon": ("color_icon.png", g),
134
+ },
135
+ data=upload_data,
136
+ )
137
+
138
+ if r.ok:
139
+ rjson = json.loads(r.text)
140
+ if rjson["status"] == 1:
141
+ pack_id = rjson["custom_sticker_pack"]["id"]
142
+ url = f"https://stickers.viber.com/pages/custom-sticker-packs/{pack_id}"
143
+ urls.append(url)
144
+ self.cb.put(f"Uploaded {pack_title}")
145
+ else:
146
+ self.cb.put(
147
+ f"Failed to upload {pack_title}: {r.status_code} {r.text}"
148
+ )
149
+ if rjson["status"] == 103:
150
+ self.cb.put(
151
+ "Viber auth data may have expired. Try to regenerate it?"
152
+ )
153
+ else:
154
+ self.cb.put(f"Failed to upload {pack_title}: {r.status_code} {r.text}")
155
+
156
+ return urls
157
+
158
+ @staticmethod
159
+ def start(
160
+ opt_output: OutputOption,
161
+ opt_comp: CompOption,
162
+ opt_cred: CredOption,
163
+ cb: CallbackProtocol,
164
+ cb_return: CallbackReturn,
165
+ ) -> List[str]:
166
+ exporter = UploadViber(opt_output, opt_comp, opt_cred, cb, cb_return)
167
+ return exporter.upload_stickers_viber()
@@ -0,0 +1,441 @@
1
+ #!/usr/bin/env python3
2
+ import importlib.util
3
+ import os
4
+ import platform
5
+ import shutil
6
+ import signal
7
+ import subprocess
8
+ import time
9
+ from getpass import getpass
10
+ from pathlib import Path
11
+ from typing import Callable, List, Optional, Tuple, cast
12
+
13
+ from sticker_convert.definitions import ROOT_DIR
14
+
15
+ MSG_NO_BIN = """Viber Desktop not detected.
16
+ Download and install Viber Desktop,
17
+ then login to Viber Desktop and try again."""
18
+ MSG_NO_AUTH = """Viber Desktop installed,
19
+ but viber_auth not found.
20
+ Please login to Viber Desktop and try again."""
21
+ MSG_SIP_ENABLED = """You need to disable SIP:
22
+ 1. Restart computer in Recovery mode
23
+ 2. Launch Terminal from the Utilities menu
24
+ 3. Run the command `csrutil disable`
25
+ 4. Restart your computer"""
26
+ MSG_NO_PGREP = "pgrep command or psutil python package is necessary"
27
+ MSG_LAUNCH_FAIL = "Failed to launch Viber"
28
+ MSG_PERMISSION_ERROR = "Failed to read Viber process memory"
29
+
30
+
31
+ def check_admin_windows() -> bool:
32
+ username = os.getenv("username")
33
+ if username is None:
34
+ return False
35
+
36
+ s = subprocess.run(
37
+ ["net", "user", username],
38
+ capture_output=True,
39
+ text=True,
40
+ ).stdout
41
+
42
+ return True if "*Administrators" in s else False
43
+
44
+
45
+ def check_admin_linux() -> bool:
46
+ s = subprocess.run(
47
+ ["sudo", "-l"],
48
+ capture_output=True,
49
+ text=True,
50
+ ).stdout
51
+
52
+ return True if "may run the following commands" in s else False
53
+
54
+
55
+ def killall(name: str) -> bool:
56
+ result = False
57
+
58
+ while True:
59
+ pid = find_pid_by_name(name)
60
+ if pid is not None:
61
+ os.kill(pid, signal.SIGTERM)
62
+ result = True
63
+ else:
64
+ break
65
+
66
+ return result
67
+
68
+
69
+ def find_pid_by_name(name: str) -> Optional[int]:
70
+ if platform.system() == "Windows":
71
+ s = subprocess.run(
72
+ ["powershell", "-c", "Get-Process", f"*{name}*"],
73
+ capture_output=True,
74
+ text=True,
75
+ ).stdout
76
+
77
+ for line in s.split("\n"):
78
+ if name in line.lower():
79
+ info = name.split()
80
+ pid = info[5]
81
+ if pid.isnumeric():
82
+ return int(pid)
83
+
84
+ return None
85
+ else:
86
+ if platform.system() == "Darwin":
87
+ pattern = "Viber"
88
+ else:
89
+ pattern = ".*[Vv]iber.*"
90
+ pid = (
91
+ subprocess.run(["pgrep", pattern], capture_output=True, text=True)
92
+ .stdout.split("\n")[0]
93
+ .strip()
94
+ )
95
+ if pid == "" or pid.isnumeric() is False:
96
+ return None
97
+ else:
98
+ return int(pid)
99
+
100
+
101
+ if importlib.util.find_spec("psutil"):
102
+ import psutil
103
+
104
+ def killall(name: str) -> bool:
105
+ result = False
106
+
107
+ for proc in psutil.process_iter(): # type: ignore
108
+ if name in proc.name().lower():
109
+ proc.kill()
110
+ result = True
111
+
112
+ return result
113
+
114
+ def find_pid_by_name(name: str) -> Optional[int]:
115
+ for proc in psutil.process_iter(): # type: ignore
116
+ if name in proc.name().lower():
117
+ return proc.pid
118
+
119
+ return None
120
+
121
+
122
+ class GetViberAuth:
123
+ def __init__(self, cb_ask_str: Callable[..., str] = input):
124
+ self.cb_ask_str = cb_ask_str
125
+
126
+ def relaunch_viber(self, viber_bin_path: str) -> Optional[int]:
127
+ killed = killall("viber")
128
+ if killed:
129
+ time.sleep(5)
130
+
131
+ if platform.system() == "Darwin":
132
+ cmd = ["open", "-n", viber_bin_path]
133
+ else:
134
+ cmd = [viber_bin_path]
135
+ subprocess.Popen(cmd)
136
+ time.sleep(10)
137
+
138
+ return find_pid_by_name("viber")
139
+
140
+ def get_mem_windows(self, viber_pid: int) -> Tuple[Optional[bytes], str]:
141
+ from pathlib import WindowsPath
142
+
143
+ memdump_ps_path = str(WindowsPath(ROOT_DIR / "resources/memdump_windows.ps1"))
144
+ arglist = (
145
+ f'-NoProfile -ExecutionPolicy Bypass -File "{memdump_ps_path}" {viber_pid}'
146
+ )
147
+ dump_fpath = os.path.expandvars(f"%temp%/memdump.bin.{viber_pid}")
148
+
149
+ cmd = [
150
+ "powershell",
151
+ "-NoProfile",
152
+ "-ExecutionPolicy",
153
+ "Bypass",
154
+ "-Command",
155
+ f"Start-Process -Verb RunAs powershell -ArgumentList '{arglist}'",
156
+ ]
157
+
158
+ subprocess.run(cmd, capture_output=True, text=True)
159
+
160
+ while True:
161
+ try:
162
+ with open(dump_fpath, "rb") as f:
163
+ s = f.read()
164
+ if len(s) != 0:
165
+ break
166
+ time.sleep(1)
167
+ except (FileNotFoundError, PermissionError):
168
+ pass
169
+
170
+ while True:
171
+ try:
172
+ os.remove(dump_fpath)
173
+ break
174
+ except PermissionError:
175
+ pass
176
+
177
+ return s, ""
178
+
179
+ def get_mem_linux(self, viber_pid: int) -> Tuple[Optional[bytes], str]:
180
+ memdump_sh_path = (ROOT_DIR / "resources/memdump_linux.sh").as_posix()
181
+
182
+ s = subprocess.run(
183
+ [
184
+ memdump_sh_path,
185
+ str(viber_pid),
186
+ ],
187
+ capture_output=True,
188
+ ).stdout
189
+
190
+ if len(s) > 1000:
191
+ pass
192
+ elif shutil.which("pkexec") and os.getenv("DISPLAY"):
193
+ s = subprocess.run(
194
+ [
195
+ "pkexec",
196
+ memdump_sh_path,
197
+ str(viber_pid),
198
+ ],
199
+ capture_output=True,
200
+ ).stdout
201
+ else:
202
+ prompt = "Enter sudo password: "
203
+ if self.cb_ask_str != input:
204
+ sudo_password = self.cb_ask_str(
205
+ prompt, initialvalue="", cli_show_initialvalue=False
206
+ )
207
+ else:
208
+ sudo_password = getpass(prompt)
209
+ sudo_password_pipe = subprocess.Popen(
210
+ ("echo", sudo_password), stdout=subprocess.PIPE
211
+ )
212
+ s = subprocess.run(
213
+ [
214
+ "sudo",
215
+ "-S",
216
+ memdump_sh_path,
217
+ str(viber_pid),
218
+ ],
219
+ capture_output=True,
220
+ stdin=sudo_password_pipe.stdout,
221
+ ).stdout
222
+
223
+ return s, ""
224
+
225
+ def get_mem_darwin(self, viber_pid: int) -> Tuple[Optional[bytes], str]:
226
+ subprocess.run(
227
+ [
228
+ "lldb",
229
+ "--attach-pid",
230
+ str(viber_pid),
231
+ "-o",
232
+ "process save-core /tmp/viber.dmp",
233
+ "-o",
234
+ "quit",
235
+ ],
236
+ stdout=subprocess.DEVNULL,
237
+ stderr=subprocess.DEVNULL,
238
+ )
239
+
240
+ with open("/tmp/viber.dmp", "rb") as f:
241
+ s = f.read()
242
+
243
+ os.remove("/tmp/viber.dmp")
244
+
245
+ return s, ""
246
+
247
+ def get_auth_by_pme(
248
+ self, viber_bin_path: str, relaunch: bool = True
249
+ ) -> Tuple[Optional[str], str]:
250
+ from PyMemoryEditor import OpenProcess # type: ignore
251
+
252
+ member_id = None
253
+ m_token = None
254
+ m_ts = None
255
+
256
+ if relaunch:
257
+ viber_pid = self.relaunch_viber(viber_bin_path)
258
+ else:
259
+ viber_pid = find_pid_by_name("viber")
260
+ if viber_pid is None:
261
+ return None, MSG_LAUNCH_FAIL
262
+
263
+ try:
264
+ with OpenProcess(pid=int(viber_pid)) as process:
265
+ for address in process.search_by_value(str, 18, "X-Viber-Auth-Mid: "): # type: ignore
266
+ member_id_addr = cast(int, address) + 18
267
+ member_id_bytes = process.read_process_memory(
268
+ member_id_addr, bytes, 20
269
+ )
270
+ member_id_term = member_id_bytes.find(b"\x0d\x0a")
271
+ if member_id_term == -1:
272
+ continue
273
+ member_id = member_id_bytes[:member_id_term].decode(
274
+ encoding="ascii"
275
+ )
276
+ break
277
+ if member_id is None:
278
+ return None, MSG_NO_AUTH
279
+
280
+ for address in process.search_by_value(str, 20, "X-Viber-Auth-Token: "): # type: ignore
281
+ m_token_addr = cast(int, address) + 20
282
+ m_token = process.read_process_memory(m_token_addr, str, 64)
283
+ break
284
+ if m_token is None:
285
+ return None, MSG_NO_AUTH
286
+
287
+ for address in process.search_by_value( # type: ignore
288
+ str, 24, "X-Viber-Auth-Timestamp: "
289
+ ):
290
+ m_ts_addr = cast(int, address) + 24
291
+ m_ts = process.read_process_memory(m_ts_addr, str, 13)
292
+ break
293
+ if m_ts is None:
294
+ return None, MSG_NO_AUTH
295
+ except PermissionError:
296
+ return None, MSG_PERMISSION_ERROR
297
+
298
+ viber_auth = f"member_id:{member_id};m_token:{m_token};m_ts:{m_ts}"
299
+ msg = "Got viber_auth successfully:\n"
300
+ msg += f"{viber_auth=}\n"
301
+
302
+ return viber_auth, msg
303
+
304
+ def get_auth_by_dump(
305
+ self, viber_bin_path: str, relaunch: bool = True
306
+ ) -> Tuple[Optional[str], str]:
307
+ member_id = None
308
+ m_token = None
309
+ m_ts = None
310
+
311
+ if platform.system() == "Darwin":
312
+ csrutil_status = subprocess.run(
313
+ ["csrutil", "status"], capture_output=True, text=True
314
+ ).stdout
315
+
316
+ if "enabled" in csrutil_status:
317
+ return None, MSG_SIP_ENABLED
318
+ elif (
319
+ platform.system() != "Windows"
320
+ and shutil.which("pgrep") is None
321
+ and importlib.find_loader("psutil") is None
322
+ ):
323
+ return None, MSG_NO_PGREP
324
+
325
+ if relaunch:
326
+ viber_pid = self.relaunch_viber(viber_bin_path)
327
+ else:
328
+ viber_pid = find_pid_by_name("viber")
329
+ if viber_pid is None:
330
+ return None, MSG_LAUNCH_FAIL
331
+
332
+ if platform.system() == "Windows":
333
+ s, msg = self.get_mem_windows(viber_pid)
334
+ elif platform.system() == "Darwin":
335
+ s, msg = self.get_mem_darwin(viber_pid)
336
+ else:
337
+ s, msg = self.get_mem_linux(viber_pid)
338
+
339
+ if s is None:
340
+ return None, msg
341
+
342
+ member_id_addr = s.find(b"X-Viber-Auth-Mid: ")
343
+ m_token_addr = s.find(b"X-Viber-Auth-Token: ")
344
+ m_ts_addr = s.find(b"X-Viber-Auth-Timestamp: ")
345
+
346
+ if member_id_addr == -1 or m_token_addr == -1 or m_ts_addr == -1:
347
+ return None, MSG_NO_AUTH
348
+
349
+ member_id_addr += 18
350
+ m_token_addr += 20
351
+ m_ts_addr += 24
352
+
353
+ member_id_bytes = s[member_id_addr : member_id_addr + 20]
354
+ member_id_term = member_id_bytes.find(b"\x0d\x0a")
355
+ if member_id_term == -1:
356
+ return None, MSG_NO_AUTH
357
+ member_id = member_id_bytes[:member_id_term].decode(encoding="ascii")
358
+
359
+ m_token = s[m_token_addr : m_token_addr + 64].decode(encoding="ascii")
360
+ m_ts = s[m_ts_addr : m_ts_addr + 13].decode(encoding="ascii")
361
+
362
+ viber_auth = f"member_id:{member_id};m_token:{m_token};m_ts:{m_ts}"
363
+ msg = "Got viber_auth successfully:\n"
364
+ msg += f"{viber_auth=}\n"
365
+
366
+ return viber_auth, msg
367
+
368
+ def get_viber_desktop(self) -> Optional[str]:
369
+ if platform.system() == "Windows":
370
+ viber_bin_path = os.path.expandvars("%localappdata%/Viber/Viber.exe")
371
+ elif platform.system() == "Darwin":
372
+ viber_bin_path = "/Applications/Viber.app"
373
+ else:
374
+ if os.path.isfile("/opt/viber/Viber"):
375
+ viber_bin_path = "/opt/viber/Viber"
376
+ else:
377
+ viber_which = shutil.which("Viber")
378
+ if viber_which is None:
379
+ viber_which = shutil.which("viber")
380
+ if viber_which is None:
381
+ viber_which = shutil.which("viber.AppImage")
382
+ if viber_which is None:
383
+ viber_bin_path = "viber"
384
+ else:
385
+ viber_bin_path = viber_which
386
+
387
+ if Path(viber_bin_path).is_file() or Path(viber_bin_path).is_dir():
388
+ return viber_bin_path
389
+
390
+ return None
391
+
392
+ def get_cred(
393
+ self,
394
+ viber_bin_path: Optional[str] = None,
395
+ ) -> Tuple[Optional[str], str]:
396
+ if not viber_bin_path:
397
+ viber_bin_path = self.get_viber_desktop()
398
+
399
+ if not viber_bin_path:
400
+ return None, MSG_NO_BIN
401
+
402
+ # get_auth_by_dump()
403
+ # + Fast
404
+ # - Requires admin
405
+
406
+ # get_auth_by_pme()
407
+ # + No admin (If have permission to read process)
408
+ # - Slow
409
+ # - Cannot run on macOS
410
+
411
+ # If admin, prefer get_auth_by_dump() over get_auth_by_pme(), vice versa
412
+ methods: List[Callable[[str, bool], Tuple[Optional[str], str]]] = []
413
+ relaunch = True
414
+ viber_auth = None
415
+ msg = ""
416
+
417
+ pme_present = importlib.util.find_spec("PyMemoryEditor") is not None
418
+ if platform.system() == "Darwin":
419
+ methods.append(self.get_auth_by_dump)
420
+ elif platform.system() == "Windows":
421
+ methods.append(self.get_auth_by_dump)
422
+ if pme_present:
423
+ methods.append(self.get_auth_by_pme)
424
+ if check_admin_windows() is False:
425
+ methods.reverse()
426
+ else:
427
+ if not os.path.isfile("/.dockerenv"):
428
+ methods.append(self.get_auth_by_dump)
429
+ if pme_present:
430
+ methods.append(self.get_auth_by_pme)
431
+ if check_admin_linux() is False:
432
+ methods.reverse()
433
+
434
+ for method in methods:
435
+ viber_auth, msg = method(viber_bin_path, relaunch)
436
+ relaunch = False
437
+ if viber_auth is not None:
438
+ break
439
+
440
+ killall("viber")
441
+ return viber_auth, msg
@@ -37,7 +37,7 @@ RELATED_NAME = (
37
37
  )
38
38
 
39
39
  BLACKLIST_PREFIX = ("cover",)
40
- BLACKLIST_SUFFIX = (".txt", ".m4a", ".wastickers", ".DS_Store", "._.DS_Store")
40
+ BLACKLIST_SUFFIX = (".txt", ".m4a", ".wastickers", ".zip", ".DS_Store", "._.DS_Store")
41
41
 
42
42
  XCODE_IMESSAGE_ICONSET = {
43
43
  "App-Store-1024x1024pt.png": (1024, 1024),
@@ -124,20 +124,16 @@ class FormatVerify:
124
124
  else:
125
125
  file_animated = CodecInfo.is_anim(file)
126
126
 
127
- if (
128
- file_animated is True
129
- and size
130
- and size[1] is not None
131
- and file_size > size[1]
132
- ):
133
- return False
134
- if (
135
- file_animated is False
136
- and size
137
- and size[0] is not None
138
- and file_size > size[0]
139
- ):
140
- return False
127
+ if file_animated is True:
128
+ if not size[1]:
129
+ return True
130
+ elif file_size > size[1]:
131
+ return False
132
+ else:
133
+ if not size[0]:
134
+ return True
135
+ elif file_size > size[0]:
136
+ return False
141
137
 
142
138
  return True
143
139
 
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env python3
2
2
 
3
- __version__ = "2.8.14"
3
+ __version__ = "2.9.1"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: sticker-convert
3
- Version: 2.8.14
3
+ Version: 2.9.1
4
4
  Summary: Convert (animated) stickers to/from WhatsApp, Telegram, Signal, Line, Kakao, Viber, iMessage. Written in Python.
5
5
  Author-email: laggykiller <chaudominic2@gmail.com>
6
6
  Maintainer-email: laggykiller <chaudominic2@gmail.com>
@@ -376,9 +376,11 @@ Requires-Dist: mergedeep ~=1.3.4
376
376
  Requires-Dist: numpy >=1.22.4
377
377
  Requires-Dist: Pillow ~=10.3.0
378
378
  Requires-Dist: pyoxipng ~=9.0.0
379
- Requires-Dist: python-telegram-bot ~=21.2
379
+ Requires-Dist: python-telegram-bot ~=21.3
380
+ Requires-Dist: psutil ~=5.9.8
381
+ Requires-Dist: PyMemoryEditor ~=1.5.22
380
382
  Requires-Dist: requests ~=2.32.3
381
- Requires-Dist: rlottie-python ~=1.3.5
383
+ Requires-Dist: rlottie-python ~=1.3.6
382
384
  Requires-Dist: signalstickers-client-fork-laggykiller ~=3.3.0.post2
383
385
  Requires-Dist: sqlcipher3-wheels ~=0.5.2.post1
384
386
  Requires-Dist: tqdm ~=4.66.4
@@ -482,24 +484,27 @@ usage: sticker-convert.py [-h] [--version] [--no-confirm] [--no-progress] [--cus
482
484
  [--input-dir INPUT_DIR]
483
485
  [--download-auto DOWNLOAD_AUTO | --download-signal DOWNLOAD_SIGNAL | --download-telegram DOWNLOAD_TELEGRAM | --download-line DOWNLOAD_LINE | --download-kakao DOWNLOAD_KAKAO | --download-viber DOWNLOAD_VIBER]
484
486
  [--output-dir OUTPUT_DIR] [--author AUTHOR] [--title TITLE]
485
- [--export-signal | --export-telegram | --export-telegram-emoji | --export-whatsapp | --export-imessage]
487
+ [--export-signal | --export-telegram | --export-telegram-emoji | --export-whatsapp | --export-viber | --export-imessage]
486
488
  [--no-compress]
487
489
  [--preset {auto,signal,telegram,telegram_emoji,whatsapp,line,kakao,viber,imessage_small,imessage_medium,imessage_large,custom}]
488
490
  [--steps STEPS] [--processes PROCESSES] [--fps-min FPS_MIN] [--fps-max FPS_MAX]
489
491
  [--fps-power FPS_POWER] [--res-min RES_MIN] [--res-max RES_MAX] [--res-w-min RES_W_MIN]
490
- [--res-w-max RES_W_MAX] [--res-h-min RES_H_MIN] [--res-h-max RES_H_MAX] [--res-power RES_POWER]
491
- [--quality-min QUALITY_MIN] [--quality-max QUALITY_MAX] [--quality-power QUALITY_POWER]
492
- [--color-min COLOR_MIN] [--color-max COLOR_MAX] [--color-power COLOR_POWER]
493
- [--duration-min DURATION_MIN] [--duration-max DURATION_MAX] [--padding-percent PADDING_PERCENT]
494
- [--bg-color BG_COLOR] [--vid-size-max VID_SIZE_MAX] [--img-size-max IMG_SIZE_MAX]
495
- [--vid-format VID_FORMAT] [--img-format IMG_FORMAT] [--fake-vid] [--scale-filter SCALE_FILTER]
496
- [--quantize-method QUANTIZE_METHOD] [--cache-dir CACHE_DIR] [--default-emoji DEFAULT_EMOJI]
497
- [--signal-uuid SIGNAL_UUID] [--signal-password SIGNAL_PASSWORD] [--signal-get-auth]
492
+ [--res-w-max RES_W_MAX] [--res-h-min RES_H_MIN] [--res-h-max RES_H_MAX]
493
+ [--res-power RES_POWER] [--quality-min QUALITY_MIN] [--quality-max QUALITY_MAX]
494
+ [--quality-power QUALITY_POWER] [--color-min COLOR_MIN] [--color-max COLOR_MAX]
495
+ [--color-power COLOR_POWER] [--duration-min DURATION_MIN] [--duration-max DURATION_MAX]
496
+ [--padding-percent PADDING_PERCENT] [--bg-color BG_COLOR] [--vid-size-max VID_SIZE_MAX]
497
+ [--img-size-max IMG_SIZE_MAX] [--vid-format VID_FORMAT] [--img-format IMG_FORMAT]
498
+ [--fake-vid] [--scale-filter SCALE_FILTER] [--quantize-method QUANTIZE_METHOD]
499
+ [--cache-dir CACHE_DIR] [--default-emoji DEFAULT_EMOJI] [--signal-uuid SIGNAL_UUID]
500
+ [--signal-password SIGNAL_PASSWORD] [--signal-get-auth]
498
501
  [--signal-data-dir SIGNAL_DATA_DIR] [--telegram-token TELEGRAM_TOKEN]
499
- [--telegram-userid TELEGRAM_USERID] [--kakao-auth-token KAKAO_AUTH_TOKEN] [--kakao-get-auth]
500
- [--kakao-username KAKAO_USERNAME] [--kakao-password KAKAO_PASSWORD]
502
+ [--telegram-userid TELEGRAM_USERID] [--kakao-auth-token KAKAO_AUTH_TOKEN]
503
+ [--kakao-get-auth] [--kakao-username KAKAO_USERNAME] [--kakao-password KAKAO_PASSWORD]
501
504
  [--kakao-country-code KAKAO_COUNTRY_CODE] [--kakao-phone-number KAKAO_PHONE_NUMBER]
502
- [--line-get-auth] [--line-cookies LINE_COOKIES] [--save-cred SAVE_CRED]
505
+ [--line-get-auth] [--line-cookies LINE_COOKIES] [--viber-auth VIBER_AUTH]
506
+ [--viber-get-auth VIBER_GET_AUTH] [--viber-bin-path VIBER_BIN_PATH]
507
+ [--save-cred SAVE_CRED]
503
508
 
504
509
  CLI for stickers-convert
505
510
 
@@ -549,6 +554,7 @@ Output options:
549
554
  --export-telegram-emoji
550
555
  Upload to Telegram (Custom emoji)
551
556
  --export-whatsapp Create a .wastickers file for uploading to WhatsApp
557
+ --export-viber Upload to Viber
552
558
  --export-imessage Create Xcode project for importing to iMessage
553
559
 
554
560
  Compression options:
@@ -667,6 +673,14 @@ Credentials options:
667
673
  --line-get-auth Get Line cookies from browser, which is required to create custom message stickers.
668
674
  --line-cookies LINE_COOKIES
669
675
  Set Line cookies, which is required to create custom message stickers.
676
+ --viber-auth VIBER_AUTH
677
+ Set Viber authentication data.
678
+ Required for uploading Viber stickers.
679
+ --viber-get-auth VIBER_GET_AUTH
680
+ Generate Viber authentication data.
681
+ --viber-bin-path VIBER_BIN_PATH
682
+ Specify location of Viber Desktop application.
683
+ Useful for portable installation.
670
684
  --save-cred SAVE_CRED
671
685
  Save Signal and Telegram credentials.
672
686
  ```
@@ -839,5 +853,5 @@ See [docs/TODO.md](docs/TODO.md)
839
853
  - Banner generated from [GitHub Socialify](https://socialify.git.ci/)
840
854
 
841
855
  ## DISCLAIMER
842
- - The author of this repo is NOT affiliated with Signal, Telegram, WhatsApp, Line, Kakao or Sticker Maker.
856
+ - The author of this repo is NOT affiliated with Signal, Telegram, WhatsApp, Line, Kakao, Viber, iMessage or Sticker Maker.
843
857
  - The author of this repo is NOT repsonsible for any legal consequences and loss incurred from using this repo.
@@ -1,15 +1,15 @@
1
1
  sticker_convert/__init__.py,sha256=iQnv6UOOA69c3soAn7ZOnAIubTIQSUxtq1Uhh8xRWvU,102
2
2
  sticker_convert/__main__.py,sha256=6RJauR-SCSSTT3TU7FFB6B6PVwsCxO2xZXtmZ3jc2Is,463
3
- sticker_convert/cli.py,sha256=DUPaI0Vw-a63TxxC2SSskLd1PlAuQtFOklggMo04IJc,18854
3
+ sticker_convert/cli.py,sha256=GO_rBmOAslgf-SHcvLjUE6rHzpBVfGi389RxuJZSkEU,19438
4
4
  sticker_convert/converter.py,sha256=XMiYzIzlcdvx_AFyyk7j-Zdyj3ablLFJFUZ6tjrlGIs,35861
5
5
  sticker_convert/definitions.py,sha256=ZhP2ALCEud-w9ZZD4c3TDG9eHGPZyaAL7zPUsJAbjtE,2073
6
- sticker_convert/gui.py,sha256=TRPGwMhSMPHnZppHmw2OWHKTJtGoeLpGWD0eRYi4_yk,30707
7
- sticker_convert/job.py,sha256=vKv1--y4MVmZV_IBpUhEfNEiUeEqrTR1umzlALPXKdw,25775
8
- sticker_convert/job_option.py,sha256=JHAFCxp7-dDwD-1PbpYLAFRF3OoJu8cj_BjOm5r8Gp8,7732
9
- sticker_convert/version.py,sha256=xfnmuNP-PsbPT9tAIe1hZe8BVTotwNbxoJXlFmvcuP4,47
6
+ sticker_convert/gui.py,sha256=hZOp2SyEYKbCRm9SRTItBqEk724SHtSqK_Txo0wpL8Q,31194
7
+ sticker_convert/job.py,sha256=4C2WwB3PFldacqI8UPnM10thM087VLEl9wn6P9_LtS0,26128
8
+ sticker_convert/job_option.py,sha256=yFwHEhW8Gzp9dfiXakkCREfejAIJhiOxwD4Wlg9jcPk,7805
9
+ sticker_convert/version.py,sha256=baBhLdXSz6WrhsijOG00KYOzp3-KSIDIG59dfAQPMrQ,46
10
10
  sticker_convert/downloaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
11
11
  sticker_convert/downloaders/download_base.py,sha256=x18bI2mPpbXRnSmStBHEb1IvN-VPCilOHLQUs6YPUEU,4041
12
- sticker_convert/downloaders/download_kakao.py,sha256=hHilDDzYaGU5BQmOwMF0NKnsysxh8loybfoFSNQQdSw,14955
12
+ sticker_convert/downloaders/download_kakao.py,sha256=TCygK-LiSkk3yEYZymZsHVwtW5JmQX6JeIneh25XxFA,14984
13
13
  sticker_convert/downloaders/download_line.py,sha256=9WzOWujTbZdAqBi52k21OUEfRmcV1loCaJiDmg6dklw,17853
14
14
  sticker_convert/downloaders/download_signal.py,sha256=PfwscdbcEd_5C3Ecs0F8Qc8si1sLzLodAdnsHVwXgac,3063
15
15
  sticker_convert/downloaders/download_telegram.py,sha256=jufMqc78aXOPDr7fQf9ykkNyhQ7KVCp4gRBxs09NgMo,4614
@@ -20,7 +20,7 @@ sticker_convert/gui_components/frames/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCe
20
20
  sticker_convert/gui_components/frames/comp_frame.py,sha256=9k_UntKKi2G_g0byzoj1rdTqOq7q9mcnXiy799bYnr0,7257
21
21
  sticker_convert/gui_components/frames/config_frame.py,sha256=b3X4QAnGpde0OhthXHmjSyU_Yb5tYRUFXmy04Yi8Zmo,4316
22
22
  sticker_convert/gui_components/frames/control_frame.py,sha256=_XiOJ9JPUfiysDghGG04sEVLrXG9TMVlDZ60W0LhYVI,835
23
- sticker_convert/gui_components/frames/cred_frame.py,sha256=I3XrOv7kUOsvFWquuzWWpZWbLclqKQXgD7dx5pcTuY4,6499
23
+ sticker_convert/gui_components/frames/cred_frame.py,sha256=QCAmDfSgL-ykGxPsL_9kWFssbtVdrh17IWW28oxzdDg,7429
24
24
  sticker_convert/gui_components/frames/input_frame.py,sha256=5Vz1d6J1jkofvvzm43DxeIW_CjWfxa2QPYFnkAAiAfM,5040
25
25
  sticker_convert/gui_components/frames/output_frame.py,sha256=n2WLk22h61DoZli8WbFhd-h2CqWAebDXnBa051JBuOc,4260
26
26
  sticker_convert/gui_components/frames/progress_frame.py,sha256=LWUZg_iL7iiNTfu7N5Ct_pklZdghxihENi7DP9YozOE,4915
@@ -31,6 +31,7 @@ sticker_convert/gui_components/windows/base_window.py,sha256=xBE1peGMPvWsdrFej0C
31
31
  sticker_convert/gui_components/windows/kakao_get_auth_window.py,sha256=AvXB2Q8pAPkKILHTvlLGV9jfBcvskCA4arko4nvBTdo,7115
32
32
  sticker_convert/gui_components/windows/line_get_auth_window.py,sha256=S4ES_lk2-GDvPokZtYALnUc5zW1VbS4WulNqO9K1aSs,3375
33
33
  sticker_convert/gui_components/windows/signal_get_auth_window.py,sha256=kbJPe558lLP4PbPT2mCw4Xgh06FX5mBEZXoW-Q1LvWY,4584
34
+ sticker_convert/gui_components/windows/viber_get_auth_window.py,sha256=Ne0DG4wog7Pzw-fPsbr7HX40okFFo1INusVCSwSAQdQ,5051
34
35
  sticker_convert/ios-message-stickers-template/.gitignore,sha256=4uuTph_9eHfqXHUavLOmGOji6aIHOif2bUEU_hCBn4Y,9
35
36
  sticker_convert/ios-message-stickers-template/README.md,sha256=oN0FvJkCWWjSZ3PMrCvY3T1zCsdkZYFgGHAoFh0Kmt8,467
36
37
  sticker_convert/ios-message-stickers-template/.github/FUNDING.yml,sha256=3LlmdSAGDsBA2o_C1iBYTNLwkABnyZuN0zxgPPyd-f8,70
@@ -67,35 +68,39 @@ sticker_convert/resources/NotoColorEmoji.ttf,sha256=LurIVaCIA8bSCfjrdO1feYr0bhKL
67
68
  sticker_convert/resources/appicon.icns,sha256=FB2DVTOQcFfQNZ9RcyG3z9c9k7eOiI1qw0IJhXMRFg4,5404
68
69
  sticker_convert/resources/appicon.ico,sha256=-ldugcl2Yq2pBRTktnhGKWInpKyWzRjCiPvMr3XPTlc,38078
69
70
  sticker_convert/resources/appicon.png,sha256=6XBEQz7PnerqS43aRkwpWolFG4WvKMuQ-st1ly-_JPg,5265
70
- sticker_convert/resources/compression.json,sha256=8SAv5m7_R2QFaU656W7gpliCJF9ZmGdE_XfnJU3D0ZE,12156
71
+ sticker_convert/resources/compression.json,sha256=tNBGCmFqZ4Bsik1-xtvkOSlRu1uF6KdkggNTUtjWTYU,12156
71
72
  sticker_convert/resources/emoji.json,sha256=sXSuKusyG1L2Stuf9BL5ZqfzOIOdeAeE3RXcrXAsLdY,413367
72
- sticker_convert/resources/help.json,sha256=9A7zXYrHMkIE75MhDD3xoFuk9jofFRGCVVXH_g_h9bk,6634
73
+ sticker_convert/resources/help.json,sha256=VgRYw5iNQGn_CDA4pTnk5QUO21lsx0JIvWgUV2kHPvY,6906
73
74
  sticker_convert/resources/input.json,sha256=S3CkInBMLrk5OS9aJfuTCDsf_64NOjNT3IKQr7d1hM0,2665
74
- sticker_convert/resources/output.json,sha256=QYP2gqDvEaAm5I9bH4NReaB1XMLboevv69u-V8YdZUs,1373
75
+ sticker_convert/resources/memdump_linux.sh,sha256=YbdX5C5RyCnoeDUE6JgTo8nQXKhrUw5-kFDx5bQp9tY,651
76
+ sticker_convert/resources/memdump_windows.ps1,sha256=CfyNSSEW3HJOkTu-mKrP3qh5aprN-1VCBfj-R1fELA0,302
77
+ sticker_convert/resources/output.json,sha256=V4OseXEm3O16cAjHDVZRq8-SY-0_7cFFR_cyF-0Y_eQ,1570
75
78
  sticker_convert/uploaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
76
79
  sticker_convert/uploaders/compress_wastickers.py,sha256=SMPf1_ir30ZKO2ChHspDFuyaufx0XeVBVLOlHmawEdY,6021
77
80
  sticker_convert/uploaders/upload_base.py,sha256=uQupPn6r4zrlAzpKzzX7CgvZb69ATyrwPKahWOQj0ds,1203
78
81
  sticker_convert/uploaders/upload_signal.py,sha256=eZNfTwnZzPmJcl_UCfJT6rrmLlNpD2EKfxrO2jdi1yg,6396
79
82
  sticker_convert/uploaders/upload_telegram.py,sha256=XnspO9VVbKND0gybUwdFTSzDBVDxLw9O_R7chnVQ0t0,15695
83
+ sticker_convert/uploaders/upload_viber.py,sha256=DiY54RstBtVJEfp6rGo0cpABx0X2qI873pJ6tTH-Q9U,6189
80
84
  sticker_convert/uploaders/xcode_imessage.py,sha256=1gvOljf6kYsq_11tYhnF19Yf4oGY5y34te2DWBRMwf0,11254
81
85
  sticker_convert/utils/callback.py,sha256=spYUGlklOs1yPZAxoqwOWgR1sdimpfM8a27if3TaVYk,6155
82
86
  sticker_convert/utils/url_detect.py,sha256=L2QwE2jwN85MoyYsW_4GvBHuoedrlhoIdAmzwrmaKLs,840
83
87
  sticker_convert/utils/auth/get_kakao_auth.py,sha256=ipAZ1DUd5CMTpUoxRXHVOFC3DKIpxwxpTYAfrOJ6UZ8,9829
84
88
  sticker_convert/utils/auth/get_line_auth.py,sha256=8l8ha2vQmk3rHGvDE7PkcxQXbH3oe62LKbI3qVUtvqc,2196
85
89
  sticker_convert/utils/auth/get_signal_auth.py,sha256=6Sx-lMuyBHeX1RpjAWI8u03qnRu9fmO4p89pd7fowOE,4925
90
+ sticker_convert/utils/auth/get_viber_auth.py,sha256=UUdnESATVGj-mrDuM_5wq75ouQFqPvFtdyqjGDqxi5Y,13734
86
91
  sticker_convert/utils/files/cache_store.py,sha256=etfe614OAhAyrnM5fGeESKq6R88YLNqkqkxSzEmZ0V0,1047
87
92
  sticker_convert/utils/files/json_manager.py,sha256=Vr6pZJdLMkrJJWN99210aduVHb0ILyf0SSTaw4TZqgc,541
88
93
  sticker_convert/utils/files/json_resources_loader.py,sha256=flZFixUXRTrOAhvRQpuSQgmJ69yXL94sxukcowLT1JQ,1049
89
- sticker_convert/utils/files/metadata_handler.py,sha256=UVKpwflsXwiVh-F-HNr0UcrixebfKQTU44iaPUhz-qw,10100
94
+ sticker_convert/utils/files/metadata_handler.py,sha256=KDwzCwSckTob2VacOvzLdu1256WLicmzXgkhfFvRBzo,10108
90
95
  sticker_convert/utils/files/run_bin.py,sha256=QalA9je6liHxiOtxsjsFsIkc2t59quhcJCVpP1X3p50,1743
91
96
  sticker_convert/utils/files/sanitize_filename.py,sha256=HBklPGsHRJjFQUIC5rYTQsUrsuTtezZXIEA8CPhLP8A,2156
92
97
  sticker_convert/utils/media/apple_png_normalize.py,sha256=LbrQhc7LlYX4I9ek4XJsZE4l0MygBA1jB-PFiYLEkzk,3657
93
98
  sticker_convert/utils/media/codec_info.py,sha256=1QfW3wgZ5vOk7T4XtLHYvJK1x8RbASRPSvhKEPkcu9A,15747
94
99
  sticker_convert/utils/media/decrypt_kakao.py,sha256=4wq9ZDRnFkx1WmFZnyEogBofiLGsWQM_X69HlA36578,1947
95
- sticker_convert/utils/media/format_verify.py,sha256=Xf94jyqk_6M9IlFGMy0wYIgQKn_yg00nD4XW0CgAbew,5732
96
- sticker_convert-2.8.14.dist-info/LICENSE,sha256=gXf5dRMhNSbfLPYYTY_5hsZ1r7UU1OaKQEAQUhuIBkM,18092
97
- sticker_convert-2.8.14.dist-info/METADATA,sha256=oMOCYbDpT4foe2pN0gsrfAAG1DASm8ak3uUjc9tpCpA,50376
98
- sticker_convert-2.8.14.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
99
- sticker_convert-2.8.14.dist-info/entry_points.txt,sha256=MNJ7XyC--ugxi5jS1nzjDLGnxCyLuaGdsVLnJhDHCqs,66
100
- sticker_convert-2.8.14.dist-info/top_level.txt,sha256=r9vfnB0l1ZnH5pTH5RvkobnK3Ow9m0RsncaOMAtiAtk,16
101
- sticker_convert-2.8.14.dist-info/RECORD,,
100
+ sticker_convert/utils/media/format_verify.py,sha256=MH68GLJfXeL8WFT8emtj355K5BLAtUX64tQ59nugx2c,5673
101
+ sticker_convert-2.9.1.dist-info/LICENSE,sha256=gXf5dRMhNSbfLPYYTY_5hsZ1r7UU1OaKQEAQUhuIBkM,18092
102
+ sticker_convert-2.9.1.dist-info/METADATA,sha256=Sim5kcFjuwRWedkvQhuAIyCMmpYRQ-bA3cAIqQiZuFw,51091
103
+ sticker_convert-2.9.1.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
104
+ sticker_convert-2.9.1.dist-info/entry_points.txt,sha256=MNJ7XyC--ugxi5jS1nzjDLGnxCyLuaGdsVLnJhDHCqs,66
105
+ sticker_convert-2.9.1.dist-info/top_level.txt,sha256=r9vfnB0l1ZnH5pTH5RvkobnK3Ow9m0RsncaOMAtiAtk,16
106
+ sticker_convert-2.9.1.dist-info/RECORD,,