sticker-convert 2.8.13__py3-none-any.whl → 2.9.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.
- sticker_convert/cli.py +18 -0
- sticker_convert/downloaders/download_kakao.py +35 -13
- sticker_convert/gui.py +9 -0
- sticker_convert/gui_components/frames/cred_frame.py +21 -0
- sticker_convert/gui_components/windows/viber_get_auth_window.py +143 -0
- sticker_convert/job.py +8 -0
- sticker_convert/job_option.py +2 -0
- sticker_convert/resources/compression.json +2 -2
- sticker_convert/resources/help.json +3 -0
- sticker_convert/resources/memdump.sh +26 -0
- sticker_convert/resources/output.json +8 -0
- sticker_convert/uploaders/upload_viber.py +167 -0
- sticker_convert/utils/auth/get_viber_auth.py +315 -0
- sticker_convert/utils/files/metadata_handler.py +1 -1
- sticker_convert/utils/media/format_verify.py +10 -14
- sticker_convert/version.py +1 -1
- {sticker_convert-2.8.13.dist-info → sticker_convert-2.9.0.dist-info}/METADATA +28 -15
- {sticker_convert-2.8.13.dist-info → sticker_convert-2.9.0.dist-info}/RECORD +22 -18
- {sticker_convert-2.8.13.dist-info → sticker_convert-2.9.0.dist-info}/LICENSE +0 -0
- {sticker_convert-2.8.13.dist-info → sticker_convert-2.9.0.dist-info}/WHEEL +0 -0
- {sticker_convert-2.8.13.dist-info → sticker_convert-2.9.0.dist-info}/entry_points.txt +0 -0
- {sticker_convert-2.8.13.dist-info → sticker_convert-2.9.0.dist-info}/top_level.txt +0 -0
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())
|
@@ -3,13 +3,13 @@ from __future__ import annotations
|
|
3
3
|
|
4
4
|
import itertools
|
5
5
|
import json
|
6
|
+
import re
|
6
7
|
import zipfile
|
7
8
|
from io import BytesIO
|
8
9
|
from pathlib import Path
|
9
10
|
from typing import Any, List, Optional, Tuple, cast
|
10
11
|
from urllib.parse import urlparse
|
11
12
|
|
12
|
-
import js2py # type: ignore
|
13
13
|
import requests
|
14
14
|
from bs4 import BeautifulSoup
|
15
15
|
from bs4.element import Tag
|
@@ -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.
|
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:
|
@@ -72,17 +72,39 @@ class MetadataKakao:
|
|
72
72
|
js = js[func_start_pos:]
|
73
73
|
bracket_start_pos = js.find("{")
|
74
74
|
func_end_pos = search_bracket(js[bracket_start_pos:]) + bracket_start_pos
|
75
|
-
js = js[
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
)
|
85
|
-
|
75
|
+
js = js[bracket_start_pos + 1 : func_end_pos]
|
76
|
+
js = js.split(";")[0]
|
77
|
+
|
78
|
+
minus_num_regex = re.search(r"\-(.*?)\^", js)
|
79
|
+
if not minus_num_regex:
|
80
|
+
return None, None
|
81
|
+
minus_num_str = minus_num_regex.group(1)
|
82
|
+
if not minus_num_str.isnumeric():
|
83
|
+
return None, None
|
84
|
+
minus_num = int(minus_num_str)
|
85
|
+
|
86
|
+
xor_num_regex = re.search(r"\^(.*?)\)", js)
|
87
|
+
if not xor_num_regex:
|
88
|
+
return None, None
|
89
|
+
xor_num_str = xor_num_regex.group(1)
|
90
|
+
if not xor_num_str.isnumeric():
|
91
|
+
return None, None
|
92
|
+
xor_num = int(xor_num_str)
|
93
|
+
|
94
|
+
item_code = str(int(item_code_fake) - minus_num ^ xor_num)
|
95
|
+
|
96
|
+
# https://github.com/Nuitka/Nuitka/issues/385
|
97
|
+
# js2py not working if compiled by nuitka
|
98
|
+
# web2app_start_pos = js.find("daumtools.web2app(")
|
99
|
+
# js = js[:web2app_start_pos] + "return a;}"
|
100
|
+
# get_item_code = js2py.eval_js(js) # type: ignore
|
101
|
+
# kakao_scheme_link = cast(
|
102
|
+
# str,
|
103
|
+
# get_item_code(
|
104
|
+
# "kakaotalk://store/emoticon/${i}?referer=share_link", item_code_fake
|
105
|
+
# ),
|
106
|
+
# )
|
107
|
+
# item_code = urlparse(kakao_scheme_link).path.split("/")[-1]
|
86
108
|
|
87
109
|
return pack_title, item_code
|
88
110
|
|
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,143 @@
|
|
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
|
+
|
55
|
+
self.explanation_lbl0.grid(column=0, row=0, sticky="w", padx=3, pady=3)
|
56
|
+
self.explanation_lbl1.grid(column=0, row=1, sticky="w", padx=3, pady=3)
|
57
|
+
if self.explanation_lbl2 is not None:
|
58
|
+
self.explanation_lbl2.grid(column=0, row=2, sticky="w", padx=3, pady=3)
|
59
|
+
|
60
|
+
# Start button frame
|
61
|
+
self.launch_btn = Button(
|
62
|
+
self.frame_btns,
|
63
|
+
text="Launch Viber Desktop",
|
64
|
+
command=self.cb_launch_viber,
|
65
|
+
bootstyle="secondary", # type: ignore
|
66
|
+
)
|
67
|
+
|
68
|
+
self.get_cred_btn = Button(
|
69
|
+
self.frame_btns,
|
70
|
+
text="Get auth data",
|
71
|
+
command=self.cb_get_cred,
|
72
|
+
bootstyle="default", # type: ignore
|
73
|
+
)
|
74
|
+
|
75
|
+
self.launch_btn.pack()
|
76
|
+
self.get_cred_btn.pack()
|
77
|
+
|
78
|
+
# Config frame
|
79
|
+
self.setdir_lbl = Label(
|
80
|
+
self.frame_config,
|
81
|
+
text=self.gui.help["cred"]["viber_bin_path"],
|
82
|
+
justify="left",
|
83
|
+
anchor="w",
|
84
|
+
)
|
85
|
+
|
86
|
+
self.setdir_entry = Entry(
|
87
|
+
self.frame_config,
|
88
|
+
textvariable=self.gui.viber_bin_path_var,
|
89
|
+
width=32,
|
90
|
+
)
|
91
|
+
self.setdir_btn = Button(
|
92
|
+
self.frame_config,
|
93
|
+
text="Choose",
|
94
|
+
command=self.cb_setdir,
|
95
|
+
width=8,
|
96
|
+
bootstyle="secondary", # type: ignore
|
97
|
+
)
|
98
|
+
|
99
|
+
self.setdir_lbl.grid(column=0, row=0, columnspan=2, sticky="w", padx=3, pady=3)
|
100
|
+
self.setdir_entry.grid(column=0, row=1, sticky="w", padx=3, pady=3)
|
101
|
+
self.setdir_btn.grid(column=1, row=1, sticky="e", padx=3, pady=3)
|
102
|
+
|
103
|
+
GUIUtils.finalize_window(self)
|
104
|
+
|
105
|
+
def cb_get_cred(self) -> None:
|
106
|
+
m = GetViberAuth(self.cb_ask_str_viber)
|
107
|
+
|
108
|
+
viber_bin_path = None
|
109
|
+
if self.gui.viber_bin_path_var.get():
|
110
|
+
viber_bin_path = self.gui.viber_bin_path_var.get()
|
111
|
+
|
112
|
+
viber_auth, msg = m.get_cred(viber_bin_path)
|
113
|
+
|
114
|
+
if viber_auth:
|
115
|
+
if not self.gui.creds.get("viber"):
|
116
|
+
self.gui.creds["viber"] = {}
|
117
|
+
self.gui.creds["viber"]["auth"] = viber_auth
|
118
|
+
self.gui.viber_auth_var.set(viber_auth)
|
119
|
+
|
120
|
+
self.gui.save_creds()
|
121
|
+
self.gui.highlight_fields()
|
122
|
+
|
123
|
+
self.cb_msg_block_viber(msg)
|
124
|
+
|
125
|
+
def cb_launch_viber(self) -> None:
|
126
|
+
m = GetViberAuth(self.cb_ask_str_viber)
|
127
|
+
viber_bin_path = m.get_viber_desktop()
|
128
|
+
|
129
|
+
if self.gui.viber_auth_var.get():
|
130
|
+
viber_bin_path = self.gui.viber_auth_var.get()
|
131
|
+
|
132
|
+
if viber_bin_path:
|
133
|
+
Popen([viber_bin_path])
|
134
|
+
else:
|
135
|
+
self.cb_msg_block_viber("Error: Viber Desktop not installed.")
|
136
|
+
|
137
|
+
def cb_setdir(self) -> None:
|
138
|
+
orig_input_dir = self.gui.viber_bin_path_var.get()
|
139
|
+
if not Path(orig_input_dir).is_dir():
|
140
|
+
orig_input_dir = ""
|
141
|
+
input_dir = filedialog.askdirectory(initialdir=orig_input_dir)
|
142
|
+
if input_dir:
|
143
|
+
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:
|
sticker_convert/job_option.py
CHANGED
@@ -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
|
}
|
@@ -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
|
@@ -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,315 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
import os
|
3
|
+
import platform
|
4
|
+
import shutil
|
5
|
+
import subprocess
|
6
|
+
import time
|
7
|
+
from getpass import getpass
|
8
|
+
from pathlib import Path
|
9
|
+
from typing import Callable, Optional, Tuple, cast
|
10
|
+
|
11
|
+
from sticker_convert.definitions import ROOT_DIR
|
12
|
+
|
13
|
+
# psutil is missing on arm64 linux appimage
|
14
|
+
# Note: There is no Viber Desktop on arm64 linux anyway
|
15
|
+
try:
|
16
|
+
import psutil
|
17
|
+
|
18
|
+
PSUTIL_LOADED = True
|
19
|
+
except ModuleNotFoundError:
|
20
|
+
PSUTIL_LOADED = False # type: ignore
|
21
|
+
|
22
|
+
MSG_NO_BIN = """Viber Desktop not detected.
|
23
|
+
Download and install Viber Desktop,
|
24
|
+
then login to Viber Desktop and try again."""
|
25
|
+
|
26
|
+
MSG_NO_AUTH = """Viber Desktop installed,
|
27
|
+
but viber_auth not found.
|
28
|
+
Please login to Viber Desktop and try again."""
|
29
|
+
|
30
|
+
MSG_SIP_ENABLED = """You need to disable SIP:
|
31
|
+
1. Restart computer in Recovery mode
|
32
|
+
2. Launch Terminal from the Utilities menu
|
33
|
+
3. Run the command `csrutil disable`
|
34
|
+
4. Restart your computer"""
|
35
|
+
|
36
|
+
MSG_NO_PSUTIL = "Python package psutil is necessary"
|
37
|
+
|
38
|
+
|
39
|
+
def killall(name: str) -> bool:
|
40
|
+
if not PSUTIL_LOADED:
|
41
|
+
return False
|
42
|
+
|
43
|
+
result = False
|
44
|
+
|
45
|
+
for proc in psutil.process_iter(): # type: ignore
|
46
|
+
if name in proc.name().lower():
|
47
|
+
proc.kill()
|
48
|
+
result = True
|
49
|
+
|
50
|
+
return result
|
51
|
+
|
52
|
+
|
53
|
+
def find_pid_by_name(name: str) -> Optional[int]:
|
54
|
+
if not PSUTIL_LOADED:
|
55
|
+
return None
|
56
|
+
|
57
|
+
for proc in psutil.process_iter(): # type: ignore
|
58
|
+
if name in proc.name().lower():
|
59
|
+
return proc.pid
|
60
|
+
|
61
|
+
return None
|
62
|
+
|
63
|
+
|
64
|
+
class GetViberAuth:
|
65
|
+
def __init__(self, cb_ask_str: Callable[..., str] = input):
|
66
|
+
self.cb_ask_str = cb_ask_str
|
67
|
+
|
68
|
+
def get_auth_windows(self, viber_bin_path: str) -> Tuple[Optional[str], str]:
|
69
|
+
if not PSUTIL_LOADED:
|
70
|
+
return None, MSG_NO_PSUTIL
|
71
|
+
|
72
|
+
member_id = None
|
73
|
+
m_token = None
|
74
|
+
m_ts = None
|
75
|
+
|
76
|
+
killed = killall("viber")
|
77
|
+
if killed:
|
78
|
+
time.sleep(5)
|
79
|
+
subprocess.Popen([viber_bin_path])
|
80
|
+
time.sleep(10)
|
81
|
+
|
82
|
+
from PyMemoryEditor import OpenProcess # type: ignore
|
83
|
+
|
84
|
+
viber_pid = find_pid_by_name("viber")
|
85
|
+
with OpenProcess(pid=viber_pid) as process:
|
86
|
+
for address in process.search_by_value(str, 18, "X-Viber-Auth-Mid: "): # type: ignore
|
87
|
+
member_id_addr = cast(int, address) + 18
|
88
|
+
member_id_bytes = process.read_process_memory(member_id_addr, bytes, 20)
|
89
|
+
member_id_term = member_id_bytes.find(b"\x0d\x0a")
|
90
|
+
if member_id_term == -1:
|
91
|
+
continue
|
92
|
+
member_id = member_id_bytes[:member_id_term].decode(encoding="ascii")
|
93
|
+
break
|
94
|
+
if member_id is None:
|
95
|
+
return None, MSG_NO_AUTH
|
96
|
+
|
97
|
+
for address in process.search_by_value(str, 20, "X-Viber-Auth-Token: "): # type: ignore
|
98
|
+
m_token_addr = cast(int, address) + 20
|
99
|
+
m_token = process.read_process_memory(m_token_addr, str, 64)
|
100
|
+
break
|
101
|
+
if m_token is None:
|
102
|
+
return None, MSG_NO_AUTH
|
103
|
+
|
104
|
+
for address in process.search_by_value(str, 24, "X-Viber-Auth-Timestamp: "): # type: ignore
|
105
|
+
m_ts_addr = cast(int, address) + 24
|
106
|
+
m_ts = process.read_process_memory(m_ts_addr, str, 13)
|
107
|
+
break
|
108
|
+
if m_ts is None:
|
109
|
+
return None, MSG_NO_AUTH
|
110
|
+
|
111
|
+
killall("viber")
|
112
|
+
|
113
|
+
viber_auth = f"member_id:{member_id};m_token:{m_token};m_ts:{m_ts}"
|
114
|
+
msg = "Got viber_auth successfully:\n"
|
115
|
+
msg += f"{viber_auth=}\n"
|
116
|
+
|
117
|
+
return viber_auth, msg
|
118
|
+
|
119
|
+
def get_auth_linux(self, viber_bin_path: str) -> Tuple[Optional[str], str]:
|
120
|
+
if not PSUTIL_LOADED:
|
121
|
+
return None, MSG_NO_PSUTIL
|
122
|
+
|
123
|
+
member_id = None
|
124
|
+
m_token = None
|
125
|
+
m_ts = None
|
126
|
+
|
127
|
+
killed = killall("viber")
|
128
|
+
if killed:
|
129
|
+
time.sleep(5)
|
130
|
+
subprocess.Popen([viber_bin_path])
|
131
|
+
time.sleep(10)
|
132
|
+
|
133
|
+
viber_pid = find_pid_by_name("viber")
|
134
|
+
memdump_sh_path = (ROOT_DIR / "resources/memdump.sh").as_posix()
|
135
|
+
|
136
|
+
s = subprocess.run(
|
137
|
+
[
|
138
|
+
memdump_sh_path,
|
139
|
+
str(viber_pid),
|
140
|
+
],
|
141
|
+
capture_output=True,
|
142
|
+
).stdout
|
143
|
+
|
144
|
+
if s.find(b"X-Viber-Auth-Mid: ") != -1:
|
145
|
+
pass
|
146
|
+
elif shutil.which("pkexec") and os.getenv("DISPLAY"):
|
147
|
+
s = subprocess.run(
|
148
|
+
[
|
149
|
+
"pkexec",
|
150
|
+
memdump_sh_path,
|
151
|
+
str(viber_pid),
|
152
|
+
],
|
153
|
+
capture_output=True,
|
154
|
+
).stdout
|
155
|
+
else:
|
156
|
+
prompt = "Enter sudo password: "
|
157
|
+
if self.cb_ask_str != input:
|
158
|
+
sudo_password = self.cb_ask_str(
|
159
|
+
prompt, initialvalue="", cli_show_initialvalue=False
|
160
|
+
)
|
161
|
+
else:
|
162
|
+
sudo_password = getpass(prompt)
|
163
|
+
sudo_password_pipe = subprocess.Popen(
|
164
|
+
("echo", sudo_password), stdout=subprocess.PIPE
|
165
|
+
)
|
166
|
+
s = subprocess.run(
|
167
|
+
[
|
168
|
+
"sudo",
|
169
|
+
"-S",
|
170
|
+
memdump_sh_path,
|
171
|
+
str(viber_pid),
|
172
|
+
],
|
173
|
+
capture_output=True,
|
174
|
+
stdin=sudo_password_pipe.stdout,
|
175
|
+
).stdout
|
176
|
+
|
177
|
+
member_id_addr = s.find(b"X-Viber-Auth-Mid: ")
|
178
|
+
m_token_addr = s.find(b"X-Viber-Auth-Token: ")
|
179
|
+
m_ts_addr = s.find(b"X-Viber-Auth-Timestamp: ")
|
180
|
+
|
181
|
+
if member_id_addr == -1 or m_token_addr == -1 or m_ts_addr == -1:
|
182
|
+
return None, MSG_NO_AUTH
|
183
|
+
|
184
|
+
member_id_addr += 18
|
185
|
+
m_token_addr += 20
|
186
|
+
m_ts_addr += 24
|
187
|
+
|
188
|
+
member_id_bytes = s[member_id_addr : member_id_addr + 20]
|
189
|
+
member_id_term = member_id_bytes.find(b"\x0d\x0a")
|
190
|
+
if member_id_term == -1:
|
191
|
+
return None, MSG_NO_AUTH
|
192
|
+
member_id = member_id_bytes[:member_id_term].decode(encoding="ascii")
|
193
|
+
|
194
|
+
m_token = s[m_token_addr : m_token_addr + 64].decode(encoding="ascii")
|
195
|
+
m_ts = s[m_ts_addr : m_ts_addr + 13].decode(encoding="ascii")
|
196
|
+
|
197
|
+
killall("viber")
|
198
|
+
|
199
|
+
viber_auth = f"member_id:{member_id};m_token:{m_token};m_ts:{m_ts}"
|
200
|
+
msg = "Got viber_auth successfully:\n"
|
201
|
+
msg += f"{viber_auth=}\n"
|
202
|
+
|
203
|
+
return viber_auth, msg
|
204
|
+
|
205
|
+
def get_auth_darwin(self, viber_bin_path: str) -> Tuple[Optional[str], str]:
|
206
|
+
member_id = None
|
207
|
+
m_token = None
|
208
|
+
m_ts = None
|
209
|
+
|
210
|
+
csrutil_status = subprocess.run(
|
211
|
+
["csrutil", "status"], capture_output=True, text=True
|
212
|
+
).stdout
|
213
|
+
|
214
|
+
if "enabled" in csrutil_status:
|
215
|
+
return None, MSG_SIP_ENABLED
|
216
|
+
|
217
|
+
killed = killall("viber")
|
218
|
+
if killed:
|
219
|
+
time.sleep(5)
|
220
|
+
subprocess.run(
|
221
|
+
["open", "-n", viber_bin_path],
|
222
|
+
stdout=subprocess.DEVNULL,
|
223
|
+
stderr=subprocess.DEVNULL,
|
224
|
+
)
|
225
|
+
time.sleep(10)
|
226
|
+
|
227
|
+
viber_pid = subprocess.run(
|
228
|
+
["pgrep", "Viber"], capture_output=True, text=True
|
229
|
+
).stdout.strip()
|
230
|
+
subprocess.run(
|
231
|
+
[
|
232
|
+
"lldb",
|
233
|
+
"--attach-pid",
|
234
|
+
viber_pid,
|
235
|
+
"-o",
|
236
|
+
"process save-core /tmp/viber.dmp",
|
237
|
+
"-o",
|
238
|
+
"quit",
|
239
|
+
],
|
240
|
+
stdout=subprocess.DEVNULL,
|
241
|
+
stderr=subprocess.DEVNULL,
|
242
|
+
)
|
243
|
+
|
244
|
+
with open("/tmp/viber.dmp", "rb") as f:
|
245
|
+
s = f.read()
|
246
|
+
|
247
|
+
os.remove("/tmp/viber.dmp")
|
248
|
+
killall("viber")
|
249
|
+
|
250
|
+
member_id_addr = s.find(b"X-Viber-Auth-Mid: ")
|
251
|
+
m_token_addr = s.find(b"X-Viber-Auth-Token: ")
|
252
|
+
m_ts_addr = s.find(b"X-Viber-Auth-Timestamp: ")
|
253
|
+
|
254
|
+
if member_id_addr == -1 or m_token_addr == -1 or m_ts_addr == -1:
|
255
|
+
return None, MSG_NO_AUTH
|
256
|
+
|
257
|
+
member_id_addr += 18
|
258
|
+
m_token_addr += 20
|
259
|
+
m_ts_addr += 24
|
260
|
+
|
261
|
+
member_id_bytes = s[member_id_addr : member_id_addr + 20]
|
262
|
+
member_id_term = member_id_bytes.find(b"\x0d\x0a")
|
263
|
+
if member_id_term == -1:
|
264
|
+
return None, MSG_NO_AUTH
|
265
|
+
member_id = member_id_bytes[:member_id_term].decode(encoding="ascii")
|
266
|
+
|
267
|
+
m_token = s[m_token_addr : m_token_addr + 64].decode(encoding="ascii")
|
268
|
+
m_ts = s[m_ts_addr : m_ts_addr + 13].decode(encoding="ascii")
|
269
|
+
|
270
|
+
viber_auth = f"member_id:{member_id};m_token:{m_token};m_ts:{m_ts}"
|
271
|
+
msg = "Got viber_auth successfully:\n"
|
272
|
+
msg += f"{viber_auth=}\n"
|
273
|
+
|
274
|
+
return viber_auth, msg
|
275
|
+
|
276
|
+
def get_viber_desktop(self) -> Optional[str]:
|
277
|
+
if platform.system() == "Windows":
|
278
|
+
viber_bin_path = os.path.expandvars("%localappdata%/Viber/Viber.exe")
|
279
|
+
elif platform.system() == "Darwin":
|
280
|
+
viber_bin_path = "/Applications/Viber.app"
|
281
|
+
else:
|
282
|
+
if os.path.isfile("/opt/viber/Viber"):
|
283
|
+
viber_bin_path = "/opt/viber/Viber"
|
284
|
+
else:
|
285
|
+
viber_which = shutil.which("Viber")
|
286
|
+
if viber_which is None:
|
287
|
+
viber_which = shutil.which("viber")
|
288
|
+
if viber_which is None:
|
289
|
+
viber_which = shutil.which("viber.AppImage")
|
290
|
+
if viber_which is None:
|
291
|
+
viber_bin_path = "viber"
|
292
|
+
else:
|
293
|
+
viber_bin_path = viber_which
|
294
|
+
|
295
|
+
if Path(viber_bin_path).is_file() or Path(viber_bin_path).is_dir():
|
296
|
+
return viber_bin_path
|
297
|
+
|
298
|
+
return None
|
299
|
+
|
300
|
+
def get_cred(
|
301
|
+
self,
|
302
|
+
viber_bin_path: Optional[str] = None,
|
303
|
+
) -> Tuple[Optional[str], str]:
|
304
|
+
if not viber_bin_path:
|
305
|
+
viber_bin_path = self.get_viber_desktop()
|
306
|
+
|
307
|
+
if not viber_bin_path:
|
308
|
+
return None, MSG_NO_BIN
|
309
|
+
|
310
|
+
if platform.system() == "Windows":
|
311
|
+
return self.get_auth_windows(viber_bin_path)
|
312
|
+
elif platform.system() == "Darwin":
|
313
|
+
return self.get_auth_darwin(viber_bin_path)
|
314
|
+
else:
|
315
|
+
return self.get_auth_linux(viber_bin_path)
|
@@ -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
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
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
|
|
sticker_convert/version.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: sticker-convert
|
3
|
-
Version: 2.
|
3
|
+
Version: 2.9.0
|
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>
|
@@ -371,13 +371,14 @@ Requires-Dist: av ~=12.1.0
|
|
371
371
|
Requires-Dist: beautifulsoup4 ~=4.12.3
|
372
372
|
Requires-Dist: rookiepy ~=0.5.1
|
373
373
|
Requires-Dist: imagequant ~=1.1.1
|
374
|
-
Requires-Dist: js2py ~=0.74
|
375
374
|
Requires-Dist: memory-tempfile ~=2.2.3
|
376
375
|
Requires-Dist: mergedeep ~=1.3.4
|
377
376
|
Requires-Dist: numpy >=1.22.4
|
378
377
|
Requires-Dist: Pillow ~=10.3.0
|
379
378
|
Requires-Dist: pyoxipng ~=9.0.0
|
380
379
|
Requires-Dist: python-telegram-bot ~=21.2
|
380
|
+
Requires-Dist: psutil ~=5.9.8
|
381
|
+
Requires-Dist: PyMemoryEditor ~=1.5.22
|
381
382
|
Requires-Dist: requests ~=2.32.3
|
382
383
|
Requires-Dist: rlottie-python ~=1.3.5
|
383
384
|
Requires-Dist: signalstickers-client-fork-laggykiller ~=3.3.0.post2
|
@@ -483,24 +484,27 @@ usage: sticker-convert.py [-h] [--version] [--no-confirm] [--no-progress] [--cus
|
|
483
484
|
[--input-dir INPUT_DIR]
|
484
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]
|
485
486
|
[--output-dir OUTPUT_DIR] [--author AUTHOR] [--title TITLE]
|
486
|
-
[--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]
|
487
488
|
[--no-compress]
|
488
489
|
[--preset {auto,signal,telegram,telegram_emoji,whatsapp,line,kakao,viber,imessage_small,imessage_medium,imessage_large,custom}]
|
489
490
|
[--steps STEPS] [--processes PROCESSES] [--fps-min FPS_MIN] [--fps-max FPS_MAX]
|
490
491
|
[--fps-power FPS_POWER] [--res-min RES_MIN] [--res-max RES_MAX] [--res-w-min RES_W_MIN]
|
491
|
-
[--res-w-max RES_W_MAX] [--res-h-min RES_H_MIN] [--res-h-max RES_H_MAX]
|
492
|
-
[--
|
493
|
-
[--
|
494
|
-
[--
|
495
|
-
[--
|
496
|
-
[--
|
497
|
-
[--
|
498
|
-
[--
|
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]
|
499
501
|
[--signal-data-dir SIGNAL_DATA_DIR] [--telegram-token TELEGRAM_TOKEN]
|
500
|
-
[--telegram-userid TELEGRAM_USERID] [--kakao-auth-token KAKAO_AUTH_TOKEN]
|
501
|
-
[--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]
|
502
504
|
[--kakao-country-code KAKAO_COUNTRY_CODE] [--kakao-phone-number KAKAO_PHONE_NUMBER]
|
503
|
-
[--line-get-auth] [--line-cookies LINE_COOKIES] [--
|
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]
|
504
508
|
|
505
509
|
CLI for stickers-convert
|
506
510
|
|
@@ -550,6 +554,7 @@ Output options:
|
|
550
554
|
--export-telegram-emoji
|
551
555
|
Upload to Telegram (Custom emoji)
|
552
556
|
--export-whatsapp Create a .wastickers file for uploading to WhatsApp
|
557
|
+
--export-viber Upload to Viber
|
553
558
|
--export-imessage Create Xcode project for importing to iMessage
|
554
559
|
|
555
560
|
Compression options:
|
@@ -668,6 +673,14 @@ Credentials options:
|
|
668
673
|
--line-get-auth Get Line cookies from browser, which is required to create custom message stickers.
|
669
674
|
--line-cookies LINE_COOKIES
|
670
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.
|
671
684
|
--save-cred SAVE_CRED
|
672
685
|
Save Signal and Telegram credentials.
|
673
686
|
```
|
@@ -840,5 +853,5 @@ See [docs/TODO.md](docs/TODO.md)
|
|
840
853
|
- Banner generated from [GitHub Socialify](https://socialify.git.ci/)
|
841
854
|
|
842
855
|
## DISCLAIMER
|
843
|
-
- 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.
|
844
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=
|
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=
|
7
|
-
sticker_convert/job.py,sha256=
|
8
|
-
sticker_convert/job_option.py,sha256=
|
9
|
-
sticker_convert/version.py,sha256=
|
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=UUJ5qrYrmZsock_EC-nYp5wKxs3ZAkgVkQPLxSv6l1E,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=
|
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=
|
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=_LOAhyNEp4OL24i_PsVtXYE01EArH-9gOOdEaFG4H30,4876
|
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,38 @@ 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=
|
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=
|
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/
|
75
|
+
sticker_convert/resources/memdump.sh,sha256=YbdX5C5RyCnoeDUE6JgTo8nQXKhrUw5-kFDx5bQp9tY,651
|
76
|
+
sticker_convert/resources/output.json,sha256=V4OseXEm3O16cAjHDVZRq8-SY-0_7cFFR_cyF-0Y_eQ,1570
|
75
77
|
sticker_convert/uploaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
76
78
|
sticker_convert/uploaders/compress_wastickers.py,sha256=SMPf1_ir30ZKO2ChHspDFuyaufx0XeVBVLOlHmawEdY,6021
|
77
79
|
sticker_convert/uploaders/upload_base.py,sha256=uQupPn6r4zrlAzpKzzX7CgvZb69ATyrwPKahWOQj0ds,1203
|
78
80
|
sticker_convert/uploaders/upload_signal.py,sha256=eZNfTwnZzPmJcl_UCfJT6rrmLlNpD2EKfxrO2jdi1yg,6396
|
79
81
|
sticker_convert/uploaders/upload_telegram.py,sha256=XnspO9VVbKND0gybUwdFTSzDBVDxLw9O_R7chnVQ0t0,15695
|
82
|
+
sticker_convert/uploaders/upload_viber.py,sha256=DiY54RstBtVJEfp6rGo0cpABx0X2qI873pJ6tTH-Q9U,6189
|
80
83
|
sticker_convert/uploaders/xcode_imessage.py,sha256=1gvOljf6kYsq_11tYhnF19Yf4oGY5y34te2DWBRMwf0,11254
|
81
84
|
sticker_convert/utils/callback.py,sha256=spYUGlklOs1yPZAxoqwOWgR1sdimpfM8a27if3TaVYk,6155
|
82
85
|
sticker_convert/utils/url_detect.py,sha256=L2QwE2jwN85MoyYsW_4GvBHuoedrlhoIdAmzwrmaKLs,840
|
83
86
|
sticker_convert/utils/auth/get_kakao_auth.py,sha256=ipAZ1DUd5CMTpUoxRXHVOFC3DKIpxwxpTYAfrOJ6UZ8,9829
|
84
87
|
sticker_convert/utils/auth/get_line_auth.py,sha256=8l8ha2vQmk3rHGvDE7PkcxQXbH3oe62LKbI3qVUtvqc,2196
|
85
88
|
sticker_convert/utils/auth/get_signal_auth.py,sha256=6Sx-lMuyBHeX1RpjAWI8u03qnRu9fmO4p89pd7fowOE,4925
|
89
|
+
sticker_convert/utils/auth/get_viber_auth.py,sha256=U3_8qxVifiZ7T47PMW6Cdo7CcLJnUW-_rf8QIYL9bYY,9984
|
86
90
|
sticker_convert/utils/files/cache_store.py,sha256=etfe614OAhAyrnM5fGeESKq6R88YLNqkqkxSzEmZ0V0,1047
|
87
91
|
sticker_convert/utils/files/json_manager.py,sha256=Vr6pZJdLMkrJJWN99210aduVHb0ILyf0SSTaw4TZqgc,541
|
88
92
|
sticker_convert/utils/files/json_resources_loader.py,sha256=flZFixUXRTrOAhvRQpuSQgmJ69yXL94sxukcowLT1JQ,1049
|
89
|
-
sticker_convert/utils/files/metadata_handler.py,sha256=
|
93
|
+
sticker_convert/utils/files/metadata_handler.py,sha256=KDwzCwSckTob2VacOvzLdu1256WLicmzXgkhfFvRBzo,10108
|
90
94
|
sticker_convert/utils/files/run_bin.py,sha256=QalA9je6liHxiOtxsjsFsIkc2t59quhcJCVpP1X3p50,1743
|
91
95
|
sticker_convert/utils/files/sanitize_filename.py,sha256=HBklPGsHRJjFQUIC5rYTQsUrsuTtezZXIEA8CPhLP8A,2156
|
92
96
|
sticker_convert/utils/media/apple_png_normalize.py,sha256=LbrQhc7LlYX4I9ek4XJsZE4l0MygBA1jB-PFiYLEkzk,3657
|
93
97
|
sticker_convert/utils/media/codec_info.py,sha256=1QfW3wgZ5vOk7T4XtLHYvJK1x8RbASRPSvhKEPkcu9A,15747
|
94
98
|
sticker_convert/utils/media/decrypt_kakao.py,sha256=4wq9ZDRnFkx1WmFZnyEogBofiLGsWQM_X69HlA36578,1947
|
95
|
-
sticker_convert/utils/media/format_verify.py,sha256=
|
96
|
-
sticker_convert-2.
|
97
|
-
sticker_convert-2.
|
98
|
-
sticker_convert-2.
|
99
|
-
sticker_convert-2.
|
100
|
-
sticker_convert-2.
|
101
|
-
sticker_convert-2.
|
99
|
+
sticker_convert/utils/media/format_verify.py,sha256=MH68GLJfXeL8WFT8emtj355K5BLAtUX64tQ59nugx2c,5673
|
100
|
+
sticker_convert-2.9.0.dist-info/LICENSE,sha256=gXf5dRMhNSbfLPYYTY_5hsZ1r7UU1OaKQEAQUhuIBkM,18092
|
101
|
+
sticker_convert-2.9.0.dist-info/METADATA,sha256=aGTUdCCINVKxrj8kM3b5pMpMDKbVu51_uuvVR8ee_2A,51091
|
102
|
+
sticker_convert-2.9.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
103
|
+
sticker_convert-2.9.0.dist-info/entry_points.txt,sha256=MNJ7XyC--ugxi5jS1nzjDLGnxCyLuaGdsVLnJhDHCqs,66
|
104
|
+
sticker_convert-2.9.0.dist-info/top_level.txt,sha256=r9vfnB0l1ZnH5pTH5RvkobnK3Ow9m0RsncaOMAtiAtk,16
|
105
|
+
sticker_convert-2.9.0.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|