pyloid 0.22.1__py3-none-any.whl → 0.23.1__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.
- pyloid/browser_window.py +164 -89
- pyloid/js_api/base.py +234 -8
- pyloid/js_api/window_api.py +9 -52
- pyloid/pyloid.py +477 -18
- pyloid/rpc.py +339 -0
- pyloid/store.py +172 -0
- pyloid/url_interceptor.py +24 -0
- {pyloid-0.22.1.dist-info → pyloid-0.23.1.dist-info}/LICENSE +1 -1
- {pyloid-0.22.1.dist-info → pyloid-0.23.1.dist-info}/METADATA +4 -1
- {pyloid-0.22.1.dist-info → pyloid-0.23.1.dist-info}/RECORD +11 -8
- {pyloid-0.22.1.dist-info → pyloid-0.23.1.dist-info}/WHEEL +0 -0
pyloid/browser_window.py
CHANGED
@@ -9,7 +9,18 @@ from PySide6.QtGui import (
|
|
9
9
|
QKeySequence,
|
10
10
|
QShortcut,
|
11
11
|
)
|
12
|
-
from PySide6.QtCore import
|
12
|
+
from PySide6.QtCore import (
|
13
|
+
Qt,
|
14
|
+
QPoint,
|
15
|
+
QUrl,
|
16
|
+
QEvent,
|
17
|
+
QFile,
|
18
|
+
QEventLoop,
|
19
|
+
QTimer,
|
20
|
+
QObject,
|
21
|
+
Signal,
|
22
|
+
Slot,
|
23
|
+
)
|
13
24
|
from PySide6.QtWebEngineCore import (
|
14
25
|
QWebEnginePage,
|
15
26
|
QWebEngineSettings,
|
@@ -27,7 +38,13 @@ from .js_api.base import BaseAPI
|
|
27
38
|
from PySide6.QtGui import QPixmap, QMovie
|
28
39
|
from PySide6.QtWidgets import QSplashScreen, QLabel
|
29
40
|
from typing import TYPE_CHECKING, Any
|
30
|
-
from PySide6.QtWebEngineCore import
|
41
|
+
from PySide6.QtWebEngineCore import (
|
42
|
+
QWebEngineSettings,
|
43
|
+
QWebEngineDesktopMediaRequest,
|
44
|
+
)
|
45
|
+
|
46
|
+
from .url_interceptor import CustomUrlInterceptor
|
47
|
+
from .rpc import PyloidRPC
|
31
48
|
|
32
49
|
if TYPE_CHECKING:
|
33
50
|
from .pyloid import _Pyloid
|
@@ -42,10 +59,6 @@ class CustomWebPage(QWebEnginePage):
|
|
42
59
|
self._desktop_media_handler = None
|
43
60
|
self._url_handlers = {} # URL 핸들러 저장을 위한 딕셔너리 추가
|
44
61
|
|
45
|
-
# interceptor ( all url request )
|
46
|
-
# self.interceptor = CustomUrlInterceptor()
|
47
|
-
# self.profile().setUrlRequestInterceptor(self.interceptor)
|
48
|
-
|
49
62
|
def _handlePermissionRequest(self, origin: QUrl, feature: QWebEnginePage.Feature):
|
50
63
|
# print(origin, feature)
|
51
64
|
|
@@ -83,7 +96,7 @@ class CustomWebPage(QWebEnginePage):
|
|
83
96
|
window_index = windows_model.index(i)
|
84
97
|
window_name = windows_model.data(window_index)
|
85
98
|
print(f"Window {i}: {window_name}")
|
86
|
-
|
99
|
+
|
87
100
|
request.selectWindow(windows_model.index(3))
|
88
101
|
|
89
102
|
# # interceptor ( navigation request )
|
@@ -96,53 +109,47 @@ class CustomWebPage(QWebEnginePage):
|
|
96
109
|
# return True
|
97
110
|
|
98
111
|
|
99
|
-
# interceptor ( all url request )
|
100
|
-
# class CustomUrlInterceptor(QWebEngineUrlRequestInterceptor):
|
101
|
-
# def interceptRequest(self, info):
|
102
|
-
# url = info.requestUrl().toString()
|
103
|
-
# print(url)
|
104
|
-
|
105
112
|
# class CustomInterceptor(QWebEngineUrlRequestInterceptor):
|
106
113
|
# def __init__(self, index_path=None):
|
107
114
|
# super().__init__()
|
108
115
|
# self.index_path = get_production_path()
|
109
116
|
# self.last_path = "/"
|
110
|
-
|
117
|
+
|
111
118
|
# def interceptRequest(self, info):
|
112
119
|
# url = info.requestUrl()
|
113
120
|
# navigation_type = info.navigationType()
|
114
121
|
|
115
122
|
# print("--------------------------------")
|
116
|
-
|
123
|
+
|
117
124
|
# if navigation_type == QWebEnginePage.NavigationType.NavigationTypeTyped:
|
118
125
|
# print("NavigationTypeTyped")
|
119
|
-
|
126
|
+
|
120
127
|
# if navigation_type == QWebEnginePage.NavigationType.NavigationTypeReload:
|
121
128
|
# print("NavigationTypeReload")
|
122
|
-
|
129
|
+
|
123
130
|
# if navigation_type == QWebEnginePage.NavigationType.NavigationTypeBackForward:
|
124
131
|
# print("NavigationTypeBackForward")
|
125
|
-
|
132
|
+
|
126
133
|
# if navigation_type == QWebEnginePage.NavigationType.NavigationTypeLinkClicked:
|
127
134
|
# print("NavigationTypeLinkClicked")
|
128
|
-
|
135
|
+
|
129
136
|
# if navigation_type == QWebEnginePage.NavigationType.NavigationTypeFormSubmitted:
|
130
137
|
# print("NavigationTypeFormSubmitted")
|
131
|
-
|
138
|
+
|
132
139
|
# if navigation_type == QWebEnginePage.NavigationType.NavigationTypeTyped:
|
133
140
|
# print("NavigationTypeTyped")
|
134
|
-
|
141
|
+
|
135
142
|
# if navigation_type == QWebEnginePage.NavigationType.NavigationTypeOther:
|
136
143
|
# print("NavigationTypeOther")
|
137
|
-
|
144
|
+
|
138
145
|
# print(navigation_type.value)
|
139
|
-
|
146
|
+
|
140
147
|
# print(url)
|
141
148
|
# print(url.scheme())
|
142
149
|
# print(url.host())
|
143
150
|
# print(url.url())
|
144
151
|
# print(self.last_path)
|
145
|
-
|
152
|
+
|
146
153
|
# self.last_path = url.path()
|
147
154
|
|
148
155
|
|
@@ -300,12 +307,24 @@ class _BrowserWindow:
|
|
300
307
|
frame: bool = True,
|
301
308
|
context_menu: bool = False,
|
302
309
|
dev_tools: bool = False,
|
303
|
-
js_apis: List[PyloidAPI] = [],
|
310
|
+
# js_apis: List[PyloidAPI] = [],
|
311
|
+
rpc: Optional[PyloidRPC] = None,
|
304
312
|
):
|
305
313
|
###########################################################################################
|
306
314
|
self.id = str(uuid.uuid4()) # Generate unique ID
|
307
315
|
self._window = QMainWindow()
|
308
316
|
self.web_view = CustomWebEngineView(self)
|
317
|
+
|
318
|
+
if rpc:
|
319
|
+
self.rpc = rpc
|
320
|
+
self.rpc_url = rpc.url
|
321
|
+
else:
|
322
|
+
self.rpc = None
|
323
|
+
self.rpc_url = None
|
324
|
+
|
325
|
+
# interceptor ( all url request )
|
326
|
+
self.interceptor = CustomUrlInterceptor(rpc_url=self.rpc_url)
|
327
|
+
self.web_view.page().setUrlRequestInterceptor(self.interceptor)
|
309
328
|
|
310
329
|
self._window.closeEvent = self.closeEvent # Override closeEvent method
|
311
330
|
###########################################################################################
|
@@ -318,9 +337,12 @@ class _BrowserWindow:
|
|
318
337
|
self.frame = frame
|
319
338
|
self.context_menu = context_menu
|
320
339
|
self.dev_tools = dev_tools
|
321
|
-
|
322
|
-
|
323
|
-
|
340
|
+
|
341
|
+
self.js_apis = [BaseAPI(self.id, self.app.data, self.app)]
|
342
|
+
|
343
|
+
# for js_api in js_apis:
|
344
|
+
# self.js_apis.append(js_api)
|
345
|
+
|
324
346
|
self.shortcuts = {}
|
325
347
|
self.close_on_load = True
|
326
348
|
self.splash_screen = None
|
@@ -453,12 +475,11 @@ class _BrowserWindow:
|
|
453
475
|
# Register additional JS APIs
|
454
476
|
if self.js_apis:
|
455
477
|
for js_api in self.js_apis:
|
456
|
-
# Define window_id, window, and app for each JS API
|
457
|
-
js_api.window_id = self.id
|
458
|
-
js_api.window = self
|
459
|
-
js_api.app = self.app
|
460
478
|
|
461
|
-
|
479
|
+
if js_api.__class__.__name__ == "BaseAPI":
|
480
|
+
self.channel.registerObject("__PYLOID__", js_api)
|
481
|
+
else:
|
482
|
+
self.channel.registerObject(js_api.__class__.__name__, js_api)
|
462
483
|
|
463
484
|
self.web_view.page().setWebChannel(self.channel)
|
464
485
|
|
@@ -470,10 +491,10 @@ class _BrowserWindow:
|
|
470
491
|
|
471
492
|
# Set F12 shortcut
|
472
493
|
self.set_dev_tools(self.dev_tools)
|
473
|
-
|
494
|
+
|
474
495
|
# 프로필 가져오기 및 인터셉터 설정
|
475
496
|
profile = self.web_view.page().profile()
|
476
|
-
|
497
|
+
|
477
498
|
# # 기존 인터셉터가 있다면 제거
|
478
499
|
# if self.interceptor:
|
479
500
|
# profile.setUrlRequestInterceptor(None)
|
@@ -527,13 +548,13 @@ class _BrowserWindow:
|
|
527
548
|
}
|
528
549
|
}
|
529
550
|
};
|
530
|
-
console.log('pyloid.EventAPI object initialized:', window.pyloid.EventAPI);
|
531
|
-
|
551
|
+
// console.log('pyloid.EventAPI object initialized:', window.pyloid.EventAPI);
|
552
|
+
|
532
553
|
%s
|
533
554
|
|
534
555
|
document.addEventListener('mousedown', function (e) {
|
535
556
|
if (e.target.hasAttribute('data-pyloid-drag-region')) {
|
536
|
-
window.
|
557
|
+
window.__PYLOID__.startSystemDrag();
|
537
558
|
}
|
538
559
|
});
|
539
560
|
|
@@ -545,14 +566,17 @@ class _BrowserWindow:
|
|
545
566
|
console.error('QWebChannel is not defined.');
|
546
567
|
}
|
547
568
|
"""
|
548
|
-
js_api_init = "\n".join(
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
)
|
555
|
-
|
569
|
+
# js_api_init = "\n".join(
|
570
|
+
# [
|
571
|
+
# f"window['{js_api.__class__.__name__}'] = channel.objects['{js_api.__class__.__name__}'];\n"
|
572
|
+
# f"console.log('{js_api.__class__.__name__} object initialized:', window.pyloid['{js_api.__class__.__name__}']);"
|
573
|
+
# for js_api in self.js_apis
|
574
|
+
# ]
|
575
|
+
# )
|
576
|
+
|
577
|
+
base_api_init = "window['__PYLOID__'] = channel.objects['__PYLOID__'];\n"
|
578
|
+
|
579
|
+
self.web_view.page().runJavaScript(js_code % base_api_init)
|
556
580
|
|
557
581
|
# if splash screen is set, close it when the page is loaded
|
558
582
|
if self.close_on_load and self.splash_screen:
|
@@ -826,6 +850,7 @@ class _BrowserWindow:
|
|
826
850
|
self.dev_tools_window = QMainWindow(self._window)
|
827
851
|
dev_tools_view = QWebEngineView(self.dev_tools_window)
|
828
852
|
dev_tools_view.setPage(self.web_view.page().devToolsPage())
|
853
|
+
|
829
854
|
self.dev_tools_window.setCentralWidget(dev_tools_view)
|
830
855
|
self.dev_tools_window.resize(800, 600)
|
831
856
|
self.dev_tools_window.show()
|
@@ -1994,14 +2019,30 @@ class _BrowserWindow:
|
|
1994
2019
|
class BrowserWindow(QObject):
|
1995
2020
|
command_signal = Signal(str, str, object)
|
1996
2021
|
result_signal = Signal(str, object)
|
1997
|
-
|
1998
|
-
def __init__(
|
2022
|
+
|
2023
|
+
def __init__(
|
2024
|
+
self,
|
2025
|
+
app,
|
2026
|
+
title: str,
|
2027
|
+
width: int,
|
2028
|
+
height: int,
|
2029
|
+
x: int,
|
2030
|
+
y: int,
|
2031
|
+
frame: bool,
|
2032
|
+
context_menu: bool,
|
2033
|
+
dev_tools: bool,
|
2034
|
+
rpc: Optional[PyloidRPC] = None,
|
2035
|
+
):
|
1999
2036
|
super().__init__()
|
2000
|
-
self._window = _BrowserWindow(
|
2037
|
+
self._window = _BrowserWindow(
|
2038
|
+
app, title, width, height, x, y, frame, context_menu, dev_tools, rpc
|
2039
|
+
)
|
2001
2040
|
self.command_signal.connect(self._handle_command)
|
2002
|
-
|
2041
|
+
|
2003
2042
|
@Slot(str, str, object)
|
2004
|
-
def _handle_command(
|
2043
|
+
def _handle_command(
|
2044
|
+
self, command_id: str, command_type: str, params: object
|
2045
|
+
) -> None:
|
2005
2046
|
"""
|
2006
2047
|
Handles commands sent from multiple threads.
|
2007
2048
|
Calls the corresponding method of _BrowserWindow based on the command type and returns the result.
|
@@ -2065,7 +2106,9 @@ class BrowserWindow(QObject):
|
|
2065
2106
|
elif command_type == "capture":
|
2066
2107
|
result = self._window.capture(params["save_path"])
|
2067
2108
|
elif command_type == "add_shortcut":
|
2068
|
-
result = self._window.add_shortcut(
|
2109
|
+
result = self._window.add_shortcut(
|
2110
|
+
params["key_sequence"], params["callback"]
|
2111
|
+
)
|
2069
2112
|
elif command_type == "remove_shortcut":
|
2070
2113
|
result = self._window.remove_shortcut(params["key_sequence"])
|
2071
2114
|
elif command_type == "get_all_shortcuts":
|
@@ -2093,9 +2136,13 @@ class BrowserWindow(QObject):
|
|
2093
2136
|
elif command_type == "set_resizable":
|
2094
2137
|
result = self._window.set_resizable(params["resizable"])
|
2095
2138
|
elif command_type == "set_minimum_size":
|
2096
|
-
result = self._window.set_minimum_size(
|
2139
|
+
result = self._window.set_minimum_size(
|
2140
|
+
params["min_width"], params["min_height"]
|
2141
|
+
)
|
2097
2142
|
elif command_type == "set_maximum_size":
|
2098
|
-
result = self._window.set_maximum_size(
|
2143
|
+
result = self._window.set_maximum_size(
|
2144
|
+
params["max_width"], params["max_height"]
|
2145
|
+
)
|
2099
2146
|
elif command_type == "get_minimum_size":
|
2100
2147
|
result = self._window.get_minimum_size()
|
2101
2148
|
elif command_type == "get_maximum_size":
|
@@ -2108,7 +2155,7 @@ class BrowserWindow(QObject):
|
|
2108
2155
|
params.get("close_on_load", True),
|
2109
2156
|
params.get("stay_on_top", True),
|
2110
2157
|
params.get("clickable", True),
|
2111
|
-
params.get("position", "center")
|
2158
|
+
params.get("position", "center"),
|
2112
2159
|
)
|
2113
2160
|
elif command_type == "set_gif_splash_screen":
|
2114
2161
|
result = self._window.set_gif_splash_screen(
|
@@ -2116,7 +2163,7 @@ class BrowserWindow(QObject):
|
|
2116
2163
|
params.get("close_on_load", True),
|
2117
2164
|
params.get("stay_on_top", True),
|
2118
2165
|
params.get("clickable", True),
|
2119
|
-
params.get("position", "center")
|
2166
|
+
params.get("position", "center"),
|
2120
2167
|
)
|
2121
2168
|
elif command_type == "close_splash_screen":
|
2122
2169
|
result = self._window.close_splash_screen()
|
@@ -2124,35 +2171,36 @@ class BrowserWindow(QObject):
|
|
2124
2171
|
return None
|
2125
2172
|
|
2126
2173
|
self.result_signal.emit(command_id, result)
|
2127
|
-
|
2128
|
-
def execute_command(
|
2174
|
+
|
2175
|
+
def execute_command(
|
2176
|
+
self, command_type: str, params: object, timeout: Optional[int] = None
|
2177
|
+
):
|
2129
2178
|
command_id = str(uuid.uuid4())
|
2130
|
-
|
2179
|
+
|
2131
2180
|
result_data = [None]
|
2132
2181
|
loop = QEventLoop()
|
2133
|
-
|
2182
|
+
|
2134
2183
|
if timeout:
|
2135
2184
|
timer = QTimer()
|
2136
2185
|
timer.setSingleShot(True)
|
2137
2186
|
timer.timeout.connect(loop.quit)
|
2138
2187
|
timer.start(timeout)
|
2139
|
-
|
2188
|
+
|
2140
2189
|
def on_result(received_id, result):
|
2141
2190
|
if received_id == command_id:
|
2142
|
-
result_data[0] = result
|
2191
|
+
result_data[0] = result
|
2143
2192
|
loop.quit()
|
2144
2193
|
|
2145
|
-
|
2146
2194
|
self.result_signal.connect(on_result, Qt.QueuedConnection)
|
2147
|
-
|
2195
|
+
|
2148
2196
|
self.command_signal.emit(command_id, command_type, params)
|
2149
|
-
|
2197
|
+
|
2150
2198
|
loop.exec()
|
2151
|
-
|
2199
|
+
|
2152
2200
|
self.result_signal.disconnect(on_result)
|
2153
|
-
|
2201
|
+
|
2154
2202
|
return result_data[0]
|
2155
|
-
|
2203
|
+
|
2156
2204
|
# -------------------------------------------------------------------
|
2157
2205
|
# Execute_command wrapper functions
|
2158
2206
|
# -------------------------------------------------------------------
|
@@ -2211,7 +2259,9 @@ class BrowserWindow(QObject):
|
|
2211
2259
|
>>> window.load_html(html_content)
|
2212
2260
|
>>> window.show()
|
2213
2261
|
"""
|
2214
|
-
return self.execute_command(
|
2262
|
+
return self.execute_command(
|
2263
|
+
"load_html", {"html_content": html_content, "base_url": base_url}
|
2264
|
+
)
|
2215
2265
|
|
2216
2266
|
def set_title(self, title: str) -> None:
|
2217
2267
|
"""
|
@@ -2558,7 +2608,9 @@ class BrowserWindow(QObject):
|
|
2558
2608
|
>>> window.add_shortcut("Ctrl+C", on_shortcut)
|
2559
2609
|
>>> app.run()
|
2560
2610
|
"""
|
2561
|
-
return self.execute_command(
|
2611
|
+
return self.execute_command(
|
2612
|
+
"add_shortcut", {"key_sequence": key_sequence, "callback": callback}
|
2613
|
+
)
|
2562
2614
|
|
2563
2615
|
def remove_shortcut(self, key_sequence: str) -> None:
|
2564
2616
|
"""
|
@@ -2810,7 +2862,9 @@ class BrowserWindow(QObject):
|
|
2810
2862
|
>>> window.set_minimum_size(400, 300)
|
2811
2863
|
>>> app.run()
|
2812
2864
|
"""
|
2813
|
-
return self.execute_command(
|
2865
|
+
return self.execute_command(
|
2866
|
+
"set_minimum_size", {"min_width": min_width, "min_height": min_height}
|
2867
|
+
)
|
2814
2868
|
|
2815
2869
|
def set_maximum_size(self, max_width: int, max_height: int) -> None:
|
2816
2870
|
"""
|
@@ -2830,7 +2884,9 @@ class BrowserWindow(QObject):
|
|
2830
2884
|
>>> window.set_maximum_size(1024, 768)
|
2831
2885
|
>>> app.run()
|
2832
2886
|
"""
|
2833
|
-
return self.execute_command(
|
2887
|
+
return self.execute_command(
|
2888
|
+
"set_maximum_size", {"max_width": max_width, "max_height": max_height}
|
2889
|
+
)
|
2834
2890
|
|
2835
2891
|
def get_minimum_size(self) -> "Dict[str, int]":
|
2836
2892
|
"""
|
@@ -2889,7 +2945,14 @@ class BrowserWindow(QObject):
|
|
2889
2945
|
"""
|
2890
2946
|
return self.execute_command("get_resizable", {})
|
2891
2947
|
|
2892
|
-
def set_static_image_splash_screen(
|
2948
|
+
def set_static_image_splash_screen(
|
2949
|
+
self,
|
2950
|
+
image_path: str,
|
2951
|
+
close_on_load: bool = True,
|
2952
|
+
stay_on_top: bool = True,
|
2953
|
+
clickable: bool = True,
|
2954
|
+
position: str = "center",
|
2955
|
+
) -> None:
|
2893
2956
|
"""
|
2894
2957
|
Sets the static image splash screen of the window.
|
2895
2958
|
|
@@ -2911,15 +2974,25 @@ class BrowserWindow(QObject):
|
|
2911
2974
|
--------
|
2912
2975
|
>>> window.set_static_image_splash_screen("./assets/loading.png", close_on_load=True, stay_on_top=True)
|
2913
2976
|
"""
|
2914
|
-
return self.execute_command(
|
2915
|
-
"
|
2916
|
-
|
2917
|
-
|
2918
|
-
|
2919
|
-
|
2920
|
-
|
2977
|
+
return self.execute_command(
|
2978
|
+
"set_static_image_splash_screen",
|
2979
|
+
{
|
2980
|
+
"image_path": image_path,
|
2981
|
+
"close_on_load": close_on_load,
|
2982
|
+
"stay_on_top": stay_on_top,
|
2983
|
+
"clickable": clickable,
|
2984
|
+
"position": position,
|
2985
|
+
},
|
2986
|
+
)
|
2921
2987
|
|
2922
|
-
def set_gif_splash_screen(
|
2988
|
+
def set_gif_splash_screen(
|
2989
|
+
self,
|
2990
|
+
gif_path: str,
|
2991
|
+
close_on_load: bool = True,
|
2992
|
+
stay_on_top: bool = True,
|
2993
|
+
clickable: bool = True,
|
2994
|
+
position: str = "center",
|
2995
|
+
) -> None:
|
2923
2996
|
"""
|
2924
2997
|
Sets the gif splash screen of the window.
|
2925
2998
|
|
@@ -2941,13 +3014,16 @@ class BrowserWindow(QObject):
|
|
2941
3014
|
--------
|
2942
3015
|
>>> window.set_gif_splash_screen("./assets/loading.gif", close_on_load=True, stay_on_top=True)
|
2943
3016
|
"""
|
2944
|
-
return self.execute_command(
|
2945
|
-
"
|
2946
|
-
|
2947
|
-
|
2948
|
-
|
2949
|
-
|
2950
|
-
|
3017
|
+
return self.execute_command(
|
3018
|
+
"set_gif_splash_screen",
|
3019
|
+
{
|
3020
|
+
"gif_path": gif_path,
|
3021
|
+
"close_on_load": close_on_load,
|
3022
|
+
"stay_on_top": stay_on_top,
|
3023
|
+
"clickable": clickable,
|
3024
|
+
"position": position,
|
3025
|
+
},
|
3026
|
+
)
|
2951
3027
|
|
2952
3028
|
def close_splash_screen(self) -> None:
|
2953
3029
|
"""
|
@@ -2958,4 +3034,3 @@ class BrowserWindow(QObject):
|
|
2958
3034
|
>>> window.close_splash_screen()
|
2959
3035
|
"""
|
2960
3036
|
return self.execute_command("close_splash_screen", {})
|
2961
|
-
|