sticker-convert 2.12.4__py3-none-any.whl → 2.13.1.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 +3 -0
- sticker_convert/converter.py +61 -58
- sticker_convert/downloaders/download_band.py +110 -0
- sticker_convert/downloaders/download_kakao.py +84 -22
- sticker_convert/downloaders/download_line.py +8 -4
- sticker_convert/gui.py +6 -3
- sticker_convert/gui_components/windows/advanced_compression_window.py +1 -1
- sticker_convert/gui_components/windows/discord_get_auth_window.py +3 -3
- sticker_convert/gui_components/windows/kakao_get_auth_window.py +25 -4
- sticker_convert/gui_components/windows/signal_get_auth_window.py +3 -3
- sticker_convert/gui_components/windows/viber_get_auth_window.py +16 -1
- sticker_convert/job.py +6 -0
- sticker_convert/resources/compression.json +47 -0
- sticker_convert/resources/help.json +1 -1
- sticker_convert/resources/input.json +10 -0
- sticker_convert/resources/memdump_linux.sh +0 -1
- sticker_convert/utils/auth/get_discord_auth.py +2 -2
- sticker_convert/utils/auth/get_kakao_desktop_auth.py +38 -43
- sticker_convert/utils/auth/get_signal_auth.py +2 -2
- sticker_convert/utils/auth/get_viber_auth.py +3 -5
- sticker_convert/utils/auth/telegram_api.py +3 -1
- sticker_convert/utils/auth/telethon_setup.py +21 -8
- sticker_convert/utils/chrome_remotedebug.py +27 -29
- sticker_convert/utils/chromiums/linux.py +52 -0
- sticker_convert/utils/chromiums/osx.py +68 -0
- sticker_convert/utils/chromiums/windows.py +45 -0
- sticker_convert/utils/media/codec_info.py +1 -1
- sticker_convert/utils/process.py +152 -108
- sticker_convert/utils/singletons.py +18 -0
- sticker_convert/utils/url_detect.py +3 -0
- sticker_convert/version.py +1 -1
- {sticker_convert-2.12.4.dist-info → sticker_convert-2.13.1.0.dist-info}/METADATA +37 -29
- {sticker_convert-2.12.4.dist-info → sticker_convert-2.13.1.0.dist-info}/RECORD +37 -32
- {sticker_convert-2.12.4.dist-info → sticker_convert-2.13.1.0.dist-info}/WHEEL +1 -1
- {sticker_convert-2.12.4.dist-info → sticker_convert-2.13.1.0.dist-info}/entry_points.txt +0 -0
- {sticker_convert-2.12.4.dist-info → sticker_convert-2.13.1.0.dist-info}/licenses/LICENSE +0 -0
- {sticker_convert-2.12.4.dist-info → sticker_convert-2.13.1.0.dist-info}/top_level.txt +0 -0
@@ -59,10 +59,25 @@ class ViberGetAuthWindow(BaseWindow):
|
|
59
59
|
justify="left",
|
60
60
|
anchor="w",
|
61
61
|
)
|
62
|
+
if platform.system() != "Darwin":
|
63
|
+
self.explanation_lbl3 = Label(
|
64
|
+
self.frame_info,
|
65
|
+
text="Note: This will download ProcDump and read memory of Viber Desktop",
|
66
|
+
justify="left",
|
67
|
+
anchor="w",
|
68
|
+
)
|
69
|
+
else:
|
70
|
+
self.explanation_lbl3 = Label(
|
71
|
+
self.frame_info,
|
72
|
+
text="Note: This will read memory of Viber Desktop",
|
73
|
+
justify="left",
|
74
|
+
anchor="w",
|
75
|
+
)
|
62
76
|
|
63
77
|
self.explanation_lbl0.grid(column=0, row=0, sticky="w", padx=3, pady=3)
|
64
78
|
self.explanation_lbl1.grid(column=0, row=1, sticky="w", padx=3, pady=3)
|
65
79
|
self.explanation_lbl2.grid(column=0, row=2, sticky="w", padx=3, pady=3)
|
80
|
+
self.explanation_lbl3.grid(column=0, row=3, sticky="w", padx=3, pady=3)
|
66
81
|
|
67
82
|
# Start button frame
|
68
83
|
self.launch_btn = Button(
|
@@ -109,7 +124,7 @@ class ViberGetAuthWindow(BaseWindow):
|
|
109
124
|
|
110
125
|
GUIUtils.finalize_window(self)
|
111
126
|
|
112
|
-
def cb_get_cred(self):
|
127
|
+
def cb_get_cred(self) -> None:
|
113
128
|
Thread(target=self.cb_get_cred_thread, daemon=True).start()
|
114
129
|
|
115
130
|
def cb_get_cred_thread(self) -> None:
|
sticker_convert/job.py
CHANGED
@@ -12,6 +12,7 @@ from typing import Any, Callable, Dict, List, Optional, Tuple
|
|
12
12
|
from urllib.parse import urlparse
|
13
13
|
|
14
14
|
from sticker_convert.converter import StickerConvert
|
15
|
+
from sticker_convert.downloaders.download_band import DownloadBand
|
15
16
|
from sticker_convert.downloaders.download_discord import DownloadDiscord
|
16
17
|
from sticker_convert.downloaders.download_kakao import DownloadKakao
|
17
18
|
from sticker_convert.downloaders.download_line import DownloadLine
|
@@ -28,6 +29,7 @@ from sticker_convert.utils.callback import CallbackReturn, CbQueueType, ResultsL
|
|
28
29
|
from sticker_convert.utils.files.json_resources_loader import OUTPUT_JSON
|
29
30
|
from sticker_convert.utils.files.metadata_handler import MetadataHandler
|
30
31
|
from sticker_convert.utils.media.codec_info import CodecInfo
|
32
|
+
from sticker_convert.utils.singletons import singletons
|
31
33
|
|
32
34
|
|
33
35
|
class Executor:
|
@@ -136,6 +138,7 @@ class Executor:
|
|
136
138
|
|
137
139
|
work_queue.put(None)
|
138
140
|
cb_queue.put("__PROCESS_DONE__")
|
141
|
+
singletons.close()
|
139
142
|
|
140
143
|
def start_workers(self, processes: int = 1) -> None:
|
141
144
|
self.cb_thread_instance = Thread(
|
@@ -564,6 +567,9 @@ class Job:
|
|
564
567
|
if self.opt_input.option == "kakao":
|
565
568
|
downloaders.append(DownloadKakao.start)
|
566
569
|
|
570
|
+
if self.opt_input.option == "band":
|
571
|
+
downloaders.append(DownloadBand.start)
|
572
|
+
|
567
573
|
if self.opt_input.option == "viber":
|
568
574
|
downloaders.append(DownloadViber.start)
|
569
575
|
|
@@ -328,6 +328,53 @@
|
|
328
328
|
"quantize_method": "imagequant",
|
329
329
|
"default_emoji": "😀"
|
330
330
|
},
|
331
|
+
"band": {
|
332
|
+
"size_max": {
|
333
|
+
"img": 0,
|
334
|
+
"vid": 0
|
335
|
+
},
|
336
|
+
"format": {
|
337
|
+
"img": ".png",
|
338
|
+
"vid": ".png"
|
339
|
+
},
|
340
|
+
"fps": {
|
341
|
+
"min": 1,
|
342
|
+
"max": 30,
|
343
|
+
"power": -0.5
|
344
|
+
},
|
345
|
+
"res": {
|
346
|
+
"w": {
|
347
|
+
"min": 100,
|
348
|
+
"max": 370
|
349
|
+
},
|
350
|
+
"h": {
|
351
|
+
"min": 100,
|
352
|
+
"max": 320
|
353
|
+
},
|
354
|
+
"power": 3
|
355
|
+
},
|
356
|
+
"quality": {
|
357
|
+
"min": 10,
|
358
|
+
"max": 95,
|
359
|
+
"power": 5
|
360
|
+
},
|
361
|
+
"color": {
|
362
|
+
"min": 32,
|
363
|
+
"max": 257,
|
364
|
+
"power": 3
|
365
|
+
},
|
366
|
+
"duration": {
|
367
|
+
"min": 83,
|
368
|
+
"max": 4000
|
369
|
+
},
|
370
|
+
"padding_percent": 0,
|
371
|
+
"bg_color": "",
|
372
|
+
"steps": 16,
|
373
|
+
"fake_vid": false,
|
374
|
+
"scale_filter": "bicubic",
|
375
|
+
"quantize_method": "imagequant",
|
376
|
+
"default_emoji": "😀"
|
377
|
+
},
|
331
378
|
"viber": {
|
332
379
|
"size_max": {
|
333
380
|
"img": 0,
|
@@ -64,7 +64,7 @@
|
|
64
64
|
"telethon_setup": "Setup Telethon",
|
65
65
|
"kakao_auth_token": "Set Kakao auth_token. Required for downloading animated stickers from https://e.kakao.com/t/xxxxx",
|
66
66
|
"kakao_get_auth": "Generate Kakao auth_token by simulating login. Kakao username, password, country code and phone number are also required.",
|
67
|
-
"kakao_get_auth_desktop": "Get Kakao auth_token from Kakao Desktop application
|
67
|
+
"kakao_get_auth_desktop": "Get Kakao auth_token from Kakao Desktop application.",
|
68
68
|
"kakao_bin_path": "Set Kakao Desktop application path for launching and getting auth_token.\nUseful for portable installation.",
|
69
69
|
"kakao_username": "Set Kakao username, which is email or phone number used for signing up Kakao account\nExample: +447700900142\nRequired for generating Kakao auth_token.",
|
70
70
|
"kakao_password": "Set Kakao password (Password of Kakao account).\nRequired for generating Kakao auth_token.",
|
@@ -59,6 +59,16 @@
|
|
59
59
|
"author": true
|
60
60
|
}
|
61
61
|
},
|
62
|
+
"band": {
|
63
|
+
"full_name": "Download from Naver Band",
|
64
|
+
"help": "Download Naver Band stickers from a URL / ID as input",
|
65
|
+
"example": "Example: https://www.band.us/sticker/xxxx OR 2535",
|
66
|
+
"address_lbls": "URL address / ID",
|
67
|
+
"metadata_provides": {
|
68
|
+
"title": true,
|
69
|
+
"author": false
|
70
|
+
}
|
71
|
+
},
|
62
72
|
"viber": {
|
63
73
|
"full_name": "Download from Viber",
|
64
74
|
"help": "Download viber stickers from a URL as input",
|
@@ -13,7 +13,7 @@ from sticker_convert.utils.process import killall
|
|
13
13
|
|
14
14
|
|
15
15
|
class GetDiscordAuth:
|
16
|
-
def __init__(self, cb_msg: Callable[..., None] = print):
|
16
|
+
def __init__(self, cb_msg: Callable[..., None] = print) -> None:
|
17
17
|
chromedriver_download_dir = CONFIG_DIR / "bin"
|
18
18
|
os.makedirs(chromedriver_download_dir, exist_ok=True)
|
19
19
|
|
@@ -72,7 +72,7 @@ class GetDiscordAuth:
|
|
72
72
|
if chrome_path is not None:
|
73
73
|
using_discord_app = True
|
74
74
|
else:
|
75
|
-
chrome_path = CRD.
|
75
|
+
chrome_path = CRD.get_chromium_path()
|
76
76
|
if chrome_path is None:
|
77
77
|
return (
|
78
78
|
None,
|
@@ -1,5 +1,4 @@
|
|
1
1
|
#!/usr/bin/env python3
|
2
|
-
import importlib.util
|
3
2
|
import os
|
4
3
|
import platform
|
5
4
|
import re
|
@@ -8,9 +7,9 @@ import time
|
|
8
7
|
from functools import partial
|
9
8
|
from getpass import getpass
|
10
9
|
from pathlib import Path
|
11
|
-
from typing import Callable,
|
10
|
+
from typing import Callable, Optional, Tuple, Union, cast
|
12
11
|
|
13
|
-
from sticker_convert.utils.process import
|
12
|
+
from sticker_convert.utils.process import find_pid_by_name, get_mem, killall
|
14
13
|
|
15
14
|
MSG_NO_BIN = """Kakao Desktop not detected.
|
16
15
|
Download and install Kakao Desktop,
|
@@ -28,10 +27,10 @@ MSG_PERMISSION_ERROR = "Failed to read Kakao process memory"
|
|
28
27
|
|
29
28
|
|
30
29
|
class GetKakaoDesktopAuth:
|
31
|
-
def __init__(self, cb_ask_str: Callable[..., str] = input):
|
30
|
+
def __init__(self, cb_ask_str: Callable[..., str] = input) -> None:
|
32
31
|
self.cb_ask_str = cb_ask_str
|
33
32
|
|
34
|
-
def launch_kakao(self, kakao_bin_path: str):
|
33
|
+
def launch_kakao(self, kakao_bin_path: str) -> None:
|
35
34
|
if platform.system() == "Windows":
|
36
35
|
subprocess.Popen([kakao_bin_path])
|
37
36
|
elif platform.system() == "Darwin":
|
@@ -97,13 +96,20 @@ class GetKakaoDesktopAuth:
|
|
97
96
|
self, kakao_bin_path: str, relaunch: bool = True
|
98
97
|
) -> Tuple[Optional[str], str]:
|
99
98
|
auth_token = None
|
100
|
-
|
101
|
-
if
|
102
|
-
|
99
|
+
kakao_pid: Union[str, int, None]
|
100
|
+
if platform.system() == "Windows":
|
101
|
+
is_wine = False
|
102
|
+
if relaunch:
|
103
|
+
kakao_pid = self.relaunch_kakao(kakao_bin_path)
|
104
|
+
else:
|
105
|
+
kakao_pid = find_pid_by_name("kakaotalk")
|
106
|
+
if kakao_pid is None:
|
107
|
+
return None, MSG_LAUNCH_FAIL
|
103
108
|
else:
|
104
|
-
|
105
|
-
|
106
|
-
|
109
|
+
is_wine = True
|
110
|
+
kakao_pid = "KakaoTalk.exe"
|
111
|
+
if relaunch and self.relaunch_kakao(kakao_bin_path) is None:
|
112
|
+
return None, MSG_LAUNCH_FAIL
|
107
113
|
|
108
114
|
if self.cb_ask_str == input:
|
109
115
|
pw_func = getpass
|
@@ -111,10 +117,10 @@ class GetKakaoDesktopAuth:
|
|
111
117
|
pw_func = partial(
|
112
118
|
self.cb_ask_str, initialvalue="", cli_show_initialvalue=False
|
113
119
|
)
|
114
|
-
s
|
120
|
+
s = get_mem(kakao_pid, pw_func, is_wine)
|
115
121
|
|
116
122
|
if s is None:
|
117
|
-
return None,
|
123
|
+
return None, "Failed to dump memory"
|
118
124
|
|
119
125
|
auth_token = None
|
120
126
|
for i in re.finditer(b"authorization: ", s):
|
@@ -140,6 +146,13 @@ class GetKakaoDesktopAuth:
|
|
140
146
|
return auth_token, msg
|
141
147
|
|
142
148
|
def get_auth_darwin(self, kakao_bin_path: str) -> Tuple[Optional[str], str]:
|
149
|
+
csrutil_status = subprocess.run(
|
150
|
+
["csrutil", "status"], capture_output=True, text=True
|
151
|
+
).stdout
|
152
|
+
|
153
|
+
if "enabled" in csrutil_status:
|
154
|
+
return None, MSG_SIP_ENABLED
|
155
|
+
|
143
156
|
killall("kakaotalk")
|
144
157
|
|
145
158
|
subprocess.run(
|
@@ -205,9 +218,10 @@ class GetKakaoDesktopAuth:
|
|
205
218
|
elif platform.system() == "Darwin":
|
206
219
|
kakao_bin_path = "/Applications/KakaoTalk.app"
|
207
220
|
else:
|
208
|
-
|
209
|
-
|
210
|
-
|
221
|
+
wineprefix = os.environ.get("WINEPREFIX")
|
222
|
+
if not (wineprefix and Path(wineprefix).exists()):
|
223
|
+
wineprefix = os.path.expanduser("~/.wine")
|
224
|
+
kakao_bin_path = f"{wineprefix}/drive_c/Program Files (x86)/Kakao/KakaoTalk/KakaoTalk.exe"
|
211
225
|
|
212
226
|
if Path(kakao_bin_path).exists():
|
213
227
|
return kakao_bin_path
|
@@ -220,7 +234,7 @@ class GetKakaoDesktopAuth:
|
|
220
234
|
) -> Tuple[Optional[str], str]:
|
221
235
|
# get_auth_by_dump()
|
222
236
|
# + Fast
|
223
|
-
# - Requires admin
|
237
|
+
# - Requires downloading procdump, or builtin method that needs admin
|
224
238
|
|
225
239
|
# get_auth_by_pme()
|
226
240
|
# + No admin (If have permission to read process)
|
@@ -233,32 +247,13 @@ class GetKakaoDesktopAuth:
|
|
233
247
|
if not kakao_bin_path:
|
234
248
|
return None, MSG_NO_BIN
|
235
249
|
|
236
|
-
if platform.system()
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
msg = ""
|
242
|
-
|
243
|
-
pme_present = importlib.util.find_spec("PyMemoryEditor") is not None
|
244
|
-
methods.append(self.get_auth_by_dump)
|
245
|
-
if pme_present:
|
246
|
-
methods.append(self.get_auth_by_pme)
|
247
|
-
if check_admin() is False:
|
248
|
-
methods.reverse()
|
249
|
-
|
250
|
-
for method in methods:
|
251
|
-
kakao_auth, msg = method(kakao_bin_path, relaunch)
|
252
|
-
relaunch = False
|
253
|
-
if kakao_auth is not None:
|
254
|
-
break
|
255
|
-
else:
|
256
|
-
csrutil_status = subprocess.run(
|
257
|
-
["csrutil", "status"], capture_output=True, text=True
|
258
|
-
).stdout
|
259
|
-
|
260
|
-
if "enabled" in csrutil_status:
|
261
|
-
return None, MSG_SIP_ENABLED
|
250
|
+
if platform.system() == "Windows":
|
251
|
+
kakao_auth, msg = self.get_auth_by_dump(kakao_bin_path)
|
252
|
+
if kakao_auth is None:
|
253
|
+
kakao_auth, msg = self.get_auth_by_pme(kakao_bin_path, False)
|
254
|
+
elif platform.system() == "Darwin":
|
262
255
|
kakao_auth, msg = self.get_auth_darwin(kakao_bin_path)
|
256
|
+
else:
|
257
|
+
kakao_auth, msg = self.get_auth_by_dump(kakao_bin_path)
|
263
258
|
|
264
259
|
return kakao_auth, msg
|
@@ -17,7 +17,7 @@ class GetSignalAuth:
|
|
17
17
|
self,
|
18
18
|
cb_msg: Callable[..., None] = print,
|
19
19
|
cb_ask_str: Callable[..., str] = input,
|
20
|
-
):
|
20
|
+
) -> None:
|
21
21
|
chromedriver_download_dir = CONFIG_DIR / "bin"
|
22
22
|
os.makedirs(chromedriver_download_dir, exist_ok=True)
|
23
23
|
|
@@ -26,7 +26,7 @@ class GetSignalAuth:
|
|
26
26
|
self.cb_ask_str = cb_ask_str
|
27
27
|
self.cb_msg = cb_msg
|
28
28
|
|
29
|
-
def download_signal_desktop(self):
|
29
|
+
def download_signal_desktop(self) -> None:
|
30
30
|
download_url = "https://signal.org/en/download/"
|
31
31
|
|
32
32
|
webbrowser.open(download_url)
|
@@ -28,7 +28,7 @@ MSG_PERMISSION_ERROR = "Failed to read Viber process memory"
|
|
28
28
|
|
29
29
|
|
30
30
|
class GetViberAuth:
|
31
|
-
def __init__(self, cb_ask_str: Callable[..., str] = input):
|
31
|
+
def __init__(self, cb_ask_str: Callable[..., str] = input) -> None:
|
32
32
|
self.cb_ask_str = cb_ask_str
|
33
33
|
|
34
34
|
def relaunch_viber(self, viber_bin_path: str) -> Optional[int]:
|
@@ -130,10 +130,10 @@ class GetViberAuth:
|
|
130
130
|
pw_func = partial(
|
131
131
|
self.cb_ask_str, initialvalue="", cli_show_initialvalue=False
|
132
132
|
)
|
133
|
-
s
|
133
|
+
s = get_mem(viber_pid, pw_func)
|
134
134
|
|
135
135
|
if s is None:
|
136
|
-
return None,
|
136
|
+
return None, "Failed to dump memory"
|
137
137
|
|
138
138
|
member_id_addr = s.find(b"X-Viber-Auth-Mid: ")
|
139
139
|
m_token_addr = s.find(b"X-Viber-Auth-Token: ")
|
@@ -217,8 +217,6 @@ class GetViberAuth:
|
|
217
217
|
methods.append(self.get_auth_by_dump)
|
218
218
|
if pme_present:
|
219
219
|
methods.append(self.get_auth_by_pme)
|
220
|
-
if check_admin() is False:
|
221
|
-
methods.reverse()
|
222
220
|
else:
|
223
221
|
if not os.path.isfile("/.dockerenv"):
|
224
222
|
methods.append(self.get_auth_by_dump)
|
@@ -342,10 +342,12 @@ class TelethonAPI(TelegramAPI):
|
|
342
342
|
self.cb = cb
|
343
343
|
self.cb_return = cb_return
|
344
344
|
|
345
|
-
success,
|
345
|
+
success, client, _, _ = await TelethonSetup(
|
346
346
|
self.opt_cred, self.cb_ask_str
|
347
347
|
).start_async()
|
348
348
|
|
349
|
+
if success is True and client is not None:
|
350
|
+
self.client = client
|
349
351
|
return success
|
350
352
|
|
351
353
|
async def exit(self) -> None:
|
@@ -1,5 +1,5 @@
|
|
1
1
|
#!/usr/bin/env python3
|
2
|
-
from typing import Callable, Tuple
|
2
|
+
from typing import Callable, Optional, Tuple
|
3
3
|
|
4
4
|
import anyio
|
5
5
|
from telethon import TelegramClient # type: ignore
|
@@ -22,7 +22,9 @@ Continue when done"""
|
|
22
22
|
|
23
23
|
|
24
24
|
class TelethonSetup:
|
25
|
-
def __init__(
|
25
|
+
def __init__(
|
26
|
+
self, opt_cred: CredOption, cb_ask_str: Callable[..., str] = input
|
27
|
+
) -> None:
|
26
28
|
self.cb_ask_str = cb_ask_str
|
27
29
|
self.opt_cred = opt_cred
|
28
30
|
|
@@ -56,28 +58,39 @@ class TelethonSetup:
|
|
56
58
|
def guide(self) -> None:
|
57
59
|
self.cb_ask_str(GUIDE_MSG)
|
58
60
|
|
59
|
-
def get_api_info(self) ->
|
61
|
+
def get_api_info(self) -> bool:
|
60
62
|
api_id_ask = "Enter api_id: "
|
61
63
|
wrong_hint = ""
|
64
|
+
|
62
65
|
while True:
|
63
66
|
telethon_api_id = self.cb_ask_str(wrong_hint + api_id_ask)
|
64
|
-
if telethon_api_id
|
67
|
+
if telethon_api_id == "":
|
68
|
+
return False
|
69
|
+
elif telethon_api_id.isnumeric():
|
65
70
|
self.opt_cred.telethon_api_id = int(telethon_api_id)
|
66
71
|
break
|
67
72
|
else:
|
68
73
|
wrong_hint = "Error: api_id should be numeric\n"
|
74
|
+
|
69
75
|
self.opt_cred.telethon_api_hash = self.cb_ask_str("Enter api_hash: ")
|
76
|
+
if self.opt_cred.telethon_api_hash == "":
|
77
|
+
return False
|
78
|
+
return True
|
70
79
|
|
71
80
|
def signin(self) -> Tuple[bool, TelegramClient, int, str]:
|
72
81
|
return anyio.run(self.signin_async)
|
73
82
|
|
74
|
-
def start(self) -> Tuple[bool, TelegramClient, int, str]:
|
83
|
+
def start(self) -> Tuple[bool, Optional[TelegramClient], int, str]:
|
84
|
+
cred_valid = False
|
75
85
|
if self.opt_cred.telethon_api_id == 0 or self.opt_cred.telethon_api_hash == "":
|
76
86
|
self.guide()
|
77
|
-
self.get_api_info()
|
78
|
-
|
87
|
+
cred_valid = self.get_api_info()
|
88
|
+
if cred_valid:
|
89
|
+
return self.signin()
|
90
|
+
else:
|
91
|
+
return False, None, 0, ""
|
79
92
|
|
80
|
-
async def start_async(self) -> Tuple[bool, TelegramClient, int, str]:
|
93
|
+
async def start_async(self) -> Tuple[bool, Optional[TelegramClient], int, str]:
|
81
94
|
if self.opt_cred.telethon_api_id == 0 or self.opt_cred.telethon_api_hash == "":
|
82
95
|
self.guide()
|
83
96
|
self.get_api_info()
|
@@ -5,12 +5,12 @@ import json
|
|
5
5
|
import os
|
6
6
|
import platform
|
7
7
|
import shutil
|
8
|
+
import signal
|
8
9
|
import socket
|
9
10
|
import subprocess
|
10
11
|
import time
|
11
|
-
from typing import Any, Dict, List, Optional,
|
12
|
+
from typing import Any, Dict, List, Optional, Union, cast
|
12
13
|
|
13
|
-
import browsers # type: ignore
|
14
14
|
import requests
|
15
15
|
import websocket
|
16
16
|
from PIL import Image
|
@@ -50,7 +50,7 @@ class CRD:
|
|
50
50
|
chrome_bin: str,
|
51
51
|
port: Optional[int] = None,
|
52
52
|
args: Optional[List[str]] = None,
|
53
|
-
):
|
53
|
+
) -> None:
|
54
54
|
if port is None:
|
55
55
|
port = get_free_port()
|
56
56
|
self.port = port
|
@@ -83,22 +83,16 @@ class CRD:
|
|
83
83
|
self.chrome_proc = subprocess.Popen(launch_cmd)
|
84
84
|
|
85
85
|
@staticmethod
|
86
|
-
def
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
if len(bs) == 0:
|
97
|
-
return None
|
98
|
-
bs = sorted(bs, key=lambda x: x[0])
|
99
|
-
return bs[0][1]
|
100
|
-
|
101
|
-
def connect(self, target_id: int = 0):
|
86
|
+
def get_chromium_path() -> Optional[str]:
|
87
|
+
if platform.system() == "Windows":
|
88
|
+
from sticker_convert.utils.chromiums.windows import get_chromium_path
|
89
|
+
elif platform.system() == "Darwin":
|
90
|
+
from sticker_convert.utils.chromiums.osx import get_chromium_path
|
91
|
+
else:
|
92
|
+
from sticker_convert.utils.chromiums.linux import get_chromium_path
|
93
|
+
return get_chromium_path()
|
94
|
+
|
95
|
+
def connect(self, target_id: int = 0) -> None:
|
102
96
|
self.cmd_id = 1
|
103
97
|
r = None
|
104
98
|
targets: List[Any] = []
|
@@ -137,7 +131,7 @@ class CRD:
|
|
137
131
|
|
138
132
|
raise RuntimeError("Websocket keep disconnecting")
|
139
133
|
|
140
|
-
def exec_js(self, js: str, context_id: Optional[int] = None):
|
134
|
+
def exec_js(self, js: str, context_id: Optional[int] = None) -> Union[str, bytes]:
|
141
135
|
command: Dict[str, Any] = {
|
142
136
|
"id": self.cmd_id,
|
143
137
|
"method": "Runtime.evaluate",
|
@@ -155,11 +149,11 @@ class CRD:
|
|
155
149
|
}
|
156
150
|
return self.send_cmd(command)
|
157
151
|
|
158
|
-
def screenshot(self, clip: Optional[Dict[str, int]] = None):
|
152
|
+
def screenshot(self, clip: Optional[Dict[str, int]] = None) -> Image.Image:
|
159
153
|
command: Dict[str, Any] = {
|
160
154
|
"id": self.cmd_id,
|
161
155
|
"method": "Page.captureScreenshot",
|
162
|
-
"params": {},
|
156
|
+
"params": {"captureBeyondViewport": True, "optimizeForSpeed": True},
|
163
157
|
}
|
164
158
|
if clip:
|
165
159
|
command["params"]["clip"] = clip
|
@@ -174,11 +168,11 @@ class CRD:
|
|
174
168
|
str, json.loads(r).get("result", {}).get("result", {}).get("value", "")
|
175
169
|
)
|
176
170
|
|
177
|
-
def navigate(self, url: str):
|
171
|
+
def navigate(self, url: str) -> None:
|
178
172
|
command = {"id": self.cmd_id, "method": "Page.navigate", "params": {"url": url}}
|
179
173
|
self.send_cmd(command)
|
180
174
|
|
181
|
-
def open_html_str(self, html: str):
|
175
|
+
def open_html_str(self, html: str) -> None:
|
182
176
|
command: Dict[str, Any] = {
|
183
177
|
"id": self.cmd_id,
|
184
178
|
"method": "Page.navigate",
|
@@ -198,24 +192,28 @@ class CRD:
|
|
198
192
|
}
|
199
193
|
self.send_cmd(command)
|
200
194
|
|
201
|
-
def runtime_enable(self):
|
195
|
+
def runtime_enable(self) -> None:
|
202
196
|
command = {
|
203
197
|
"method": "Runtime.enable",
|
204
198
|
}
|
205
199
|
self.send_cmd(command)
|
206
200
|
|
207
|
-
def runtime_disable(self):
|
201
|
+
def runtime_disable(self) -> None:
|
208
202
|
command = {
|
209
203
|
"method": "Runtime.disable",
|
210
204
|
}
|
211
205
|
self.send_cmd(command)
|
212
206
|
|
213
|
-
def reload(self):
|
207
|
+
def reload(self) -> None:
|
214
208
|
command = {
|
215
209
|
"method": "Page.reload",
|
216
210
|
}
|
217
211
|
self.send_cmd(command)
|
218
212
|
|
219
|
-
def close(self):
|
213
|
+
def close(self) -> None:
|
214
|
+
command = {
|
215
|
+
"method": "Browser.close",
|
216
|
+
}
|
217
|
+
self.send_cmd(command)
|
220
218
|
self.ws.close()
|
221
|
-
self.chrome_proc.
|
219
|
+
os.kill(self.chrome_proc.pid, signal.SIGTERM)
|
@@ -0,0 +1,52 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
import configparser
|
3
|
+
import os
|
4
|
+
import re
|
5
|
+
from typing import Optional
|
6
|
+
|
7
|
+
# Adopted from https://github.com/roniemartinez/browsers/blob/master/browsers/linux.py
|
8
|
+
|
9
|
+
LINUX_DESKTOP_ENTRY_LIST = (
|
10
|
+
("chrome", ("google-chrome",)),
|
11
|
+
("chromium", ("chromium", "chromium_chromium")),
|
12
|
+
("brave", ("brave-browser", "brave_brave")),
|
13
|
+
("brave-beta", ("brave-browser-beta",)),
|
14
|
+
("brave-nightly", ("brave-browser-nightly",)),
|
15
|
+
("msedge", ("microsoft-edge",)),
|
16
|
+
("opera", ("opera_opera",)),
|
17
|
+
("opera-beta", ("opera-beta_opera-beta",)),
|
18
|
+
("opera-developer", ("opera-developer_opera-developer",)),
|
19
|
+
("vivaldi", ("vivaldi_vivaldi-stable",)),
|
20
|
+
)
|
21
|
+
|
22
|
+
# $XDG_DATA_HOME and $XDG_DATA_DIRS are not always set
|
23
|
+
XDG_DATA_LOCATIONS = (
|
24
|
+
"~/.local/share/applications",
|
25
|
+
"/usr/share/applications",
|
26
|
+
"/var/lib/snapd/desktop/applications",
|
27
|
+
)
|
28
|
+
|
29
|
+
VERSION_PATTERN = re.compile(
|
30
|
+
r"\b(\S+\.\S+)\b"
|
31
|
+
) # simple pattern assuming all version strings have a dot on them
|
32
|
+
|
33
|
+
|
34
|
+
def get_chromium_path() -> Optional[str]:
|
35
|
+
for _, desktop_entries in LINUX_DESKTOP_ENTRY_LIST:
|
36
|
+
for application_dir in XDG_DATA_LOCATIONS:
|
37
|
+
for desktop_entry in desktop_entries:
|
38
|
+
path = os.path.join(application_dir, f"{desktop_entry}.desktop")
|
39
|
+
|
40
|
+
if not os.path.isfile(path):
|
41
|
+
continue
|
42
|
+
|
43
|
+
config = configparser.ConfigParser(interpolation=None)
|
44
|
+
config.read(path, encoding="utf-8")
|
45
|
+
executable_path = config.get("Desktop Entry", "Exec")
|
46
|
+
|
47
|
+
if executable_path.lower().endswith(" %u"):
|
48
|
+
executable_path = executable_path[:-3].strip()
|
49
|
+
|
50
|
+
return executable_path
|
51
|
+
|
52
|
+
return None
|