pyloid 0.20.2.dev0__tar.gz → 0.21.0.dev1__tar.gz
Sign up to get free protection for your applications and to get access to all the features.
- {pyloid-0.20.2.dev0 → pyloid-0.21.0.dev1}/PKG-INFO +3 -3
- {pyloid-0.20.2.dev0 → pyloid-0.21.0.dev1}/pyproject.toml +3 -3
- {pyloid-0.20.2.dev0 → pyloid-0.21.0.dev1}/src/pyloid/browser_window.py +92 -28
- {pyloid-0.20.2.dev0 → pyloid-0.21.0.dev1}/src/pyloid/builder/spec.py +42 -23
- {pyloid-0.20.2.dev0 → pyloid-0.21.0.dev1}/LICENSE +0 -0
- {pyloid-0.20.2.dev0 → pyloid-0.21.0.dev1}/README.md +0 -0
- {pyloid-0.20.2.dev0 → pyloid-0.21.0.dev1}/src/pyloid/__init__.py +0 -0
- {pyloid-0.20.2.dev0 → pyloid-0.21.0.dev1}/src/pyloid/api.py +0 -0
- {pyloid-0.20.2.dev0 → pyloid-0.21.0.dev1}/src/pyloid/autostart.py +0 -0
- {pyloid-0.20.2.dev0 → pyloid-0.21.0.dev1}/src/pyloid/builder/__init__.py +0 -0
- {pyloid-0.20.2.dev0 → pyloid-0.21.0.dev1}/src/pyloid/builder/build_config.schema.json +0 -0
- {pyloid-0.20.2.dev0 → pyloid-0.21.0.dev1}/src/pyloid/custom/titlebar.py +0 -0
- {pyloid-0.20.2.dev0 → pyloid-0.21.0.dev1}/src/pyloid/filewatcher.py +0 -0
- {pyloid-0.20.2.dev0 → pyloid-0.21.0.dev1}/src/pyloid/js_api/event_api.py +0 -0
- {pyloid-0.20.2.dev0 → pyloid-0.21.0.dev1}/src/pyloid/js_api/window_api.py +0 -0
- {pyloid-0.20.2.dev0 → pyloid-0.21.0.dev1}/src/pyloid/monitor.py +0 -0
- {pyloid-0.20.2.dev0 → pyloid-0.21.0.dev1}/src/pyloid/pyloid.py +0 -0
- {pyloid-0.20.2.dev0 → pyloid-0.21.0.dev1}/src/pyloid/thread_pool.py +0 -0
- {pyloid-0.20.2.dev0 → pyloid-0.21.0.dev1}/src/pyloid/timer.py +0 -0
- {pyloid-0.20.2.dev0 → pyloid-0.21.0.dev1}/src/pyloid/tray.py +0 -0
- {pyloid-0.20.2.dev0 → pyloid-0.21.0.dev1}/src/pyloid/utils.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.3
|
2
2
|
Name: pyloid
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.21.0.dev1
|
4
4
|
Summary:
|
5
5
|
Author: aesthetics-of-record
|
6
6
|
Author-email: 111675679+aesthetics-of-record@users.noreply.github.com
|
@@ -11,8 +11,8 @@ Classifier: Programming Language :: Python :: 3.10
|
|
11
11
|
Classifier: Programming Language :: Python :: 3.11
|
12
12
|
Classifier: Programming Language :: Python :: 3.12
|
13
13
|
Classifier: Programming Language :: Python :: 3.13
|
14
|
-
Requires-Dist: pyinstaller (>=6.
|
15
|
-
Requires-Dist: pyside6 (>=6.8.1,<7.0.0)
|
14
|
+
Requires-Dist: pyinstaller (>=6.12.0,<7.0.0)
|
15
|
+
Requires-Dist: pyside6 (>=6.8.2.1,<7.0.0.0)
|
16
16
|
Description-Content-Type: text/markdown
|
17
17
|
|
18
18
|
# Pyloid 👋
|
@@ -1,6 +1,6 @@
|
|
1
1
|
[tool.poetry]
|
2
2
|
name = "pyloid"
|
3
|
-
version = "0.
|
3
|
+
version = "0.21.0-dev1"
|
4
4
|
description = ""
|
5
5
|
authors = ["aesthetics-of-record <111675679+aesthetics-of-record@users.noreply.github.com>"]
|
6
6
|
readme = "README.md"
|
@@ -10,8 +10,8 @@ packages = [
|
|
10
10
|
|
11
11
|
[tool.poetry.dependencies]
|
12
12
|
python = ">=3.9,<3.14"
|
13
|
-
pyside6 = "^6.8.1"
|
14
|
-
pyinstaller = "^6.
|
13
|
+
pyside6 = "^6.8.2.1"
|
14
|
+
pyinstaller = "^6.12.0"
|
15
15
|
|
16
16
|
|
17
17
|
[build-system]
|
@@ -28,15 +28,18 @@ from .custom.titlebar import CustomTitleBar
|
|
28
28
|
from .js_api.window_api import WindowAPI
|
29
29
|
from PySide6.QtGui import QPixmap, QMovie
|
30
30
|
from PySide6.QtWidgets import QSplashScreen, QLabel
|
31
|
-
from PySide6.QtCore import QSize
|
32
31
|
from typing import TYPE_CHECKING
|
33
|
-
from PySide6.QtWebEngineCore import
|
32
|
+
from PySide6.QtWebEngineCore import (
|
33
|
+
QWebEngineSettings,
|
34
|
+
QWebEngineDesktopMediaRequest,
|
35
|
+
QWebEngineUrlRequestInterceptor,
|
36
|
+
)
|
37
|
+
from .utils import get_production_path, is_production
|
34
38
|
|
35
39
|
if TYPE_CHECKING:
|
36
40
|
from ..pyloid import Pyloid
|
37
41
|
|
38
42
|
|
39
|
-
# 어차피 load 부분에만 쓰이니까 나중에 분리해서 load 위에서 선언하자.
|
40
43
|
class CustomWebPage(QWebEnginePage):
|
41
44
|
def __init__(self, profile=None):
|
42
45
|
super().__init__(profile)
|
@@ -47,11 +50,11 @@ class CustomWebPage(QWebEnginePage):
|
|
47
50
|
self._url_handlers = {} # URL 핸들러 저장을 위한 딕셔너리 추가
|
48
51
|
|
49
52
|
# interceptor ( all url request )
|
50
|
-
self.interceptor = CustomUrlInterceptor()
|
51
|
-
self.profile().setUrlRequestInterceptor(self.interceptor)
|
53
|
+
# self.interceptor = CustomUrlInterceptor()
|
54
|
+
# self.profile().setUrlRequestInterceptor(self.interceptor)
|
52
55
|
|
53
56
|
def _handlePermissionRequest(self, origin: QUrl, feature: QWebEnginePage.Feature):
|
54
|
-
print(origin, feature)
|
57
|
+
# print(origin, feature)
|
55
58
|
|
56
59
|
"""Default permission request handler"""
|
57
60
|
if feature in self._permission_handlers:
|
@@ -68,37 +71,47 @@ class CustomWebPage(QWebEnginePage):
|
|
68
71
|
"""Register a handler for a specific permission"""
|
69
72
|
self._permission_handlers[feature] = handler
|
70
73
|
|
71
|
-
def _handleDesktopMediaRequest(self,
|
72
|
-
print("Desktop media request received:",
|
74
|
+
def _handleDesktopMediaRequest(self, request: QWebEngineDesktopMediaRequest):
|
75
|
+
print("Desktop media request received:", request)
|
76
|
+
|
77
|
+
# 사용 가능한 화면 목록 확인
|
78
|
+
screens_model = request.screensModel()
|
79
|
+
print("\n=== Available Screens ===")
|
80
|
+
for i in range(screens_model.rowCount()):
|
81
|
+
screen_index = screens_model.index(i)
|
82
|
+
screen_name = screens_model.data(screen_index)
|
83
|
+
print(f"Screen {i}: {screen_name}")
|
84
|
+
|
85
|
+
# 사용 가능한 창 목록 확인
|
86
|
+
windows_model = request.windowsModel()
|
87
|
+
print("\n=== Available Windows ===")
|
88
|
+
for i in range(windows_model.rowCount()):
|
89
|
+
window_index = windows_model.index(i)
|
90
|
+
window_name = windows_model.data(window_index)
|
91
|
+
print(f"Window {i}: {window_name}")
|
92
|
+
|
93
|
+
request.selectWindow(windows_model.index(3))
|
73
94
|
|
74
95
|
# interceptor ( navigation request )
|
75
96
|
def acceptNavigationRequest(self, url, navigation_type, is_main_frame):
|
76
97
|
"""네비게이션 요청을 처리하는 메서드"""
|
77
|
-
|
98
|
+
url_string = url.toString()
|
99
|
+
print(f"Navigation Request - URL: {url_string}")
|
78
100
|
print(f"Navigation Type: {navigation_type}")
|
79
101
|
print(f"Is Main Frame: {is_main_frame}")
|
80
102
|
|
81
|
-
#
|
82
|
-
|
83
|
-
|
84
|
-
|
103
|
+
# file:// 프로토콜 처리
|
104
|
+
if url.scheme() == "file":
|
105
|
+
# 파일 경로에서 file:/// 제거
|
106
|
+
file_path = url_string.replace("file:///", "").rstrip("/")
|
85
107
|
|
86
|
-
|
108
|
+
# HTML 파일이 아닌 경우에만 index.html로 리다이렉트
|
109
|
+
if not file_path.endswith(".html"):
|
110
|
+
base_path = os.path.dirname(file_path)
|
111
|
+
self.setUrl(QUrl.fromLocalFile(os.path.join(base_path, "index.html")))
|
112
|
+
return False
|
87
113
|
|
88
|
-
|
89
|
-
"""URL 패턴에 대한 핸들러 등록
|
90
|
-
|
91
|
-
Parameters:
|
92
|
-
-----------
|
93
|
-
pattern : str
|
94
|
-
정규표현식 패턴
|
95
|
-
handler : callable
|
96
|
-
URL을 인자로 받고 bool을 반환해야 함
|
97
|
-
True를 반환하면 네비게이션을 허용, False를 반환하면 차단
|
98
|
-
"""
|
99
|
-
import re
|
100
|
-
|
101
|
-
self._url_handlers[re.compile(pattern)] = handler
|
114
|
+
return True
|
102
115
|
|
103
116
|
|
104
117
|
# interceptor ( all url request )
|
@@ -108,6 +121,50 @@ class CustomUrlInterceptor(QWebEngineUrlRequestInterceptor):
|
|
108
121
|
print(url)
|
109
122
|
|
110
123
|
|
124
|
+
# class CustomInterceptor(QWebEngineUrlRequestInterceptor):
|
125
|
+
# def __init__(self, index_path=None):
|
126
|
+
# super().__init__()
|
127
|
+
# self.index_path = get_production_path()
|
128
|
+
# self.last_path = "/"
|
129
|
+
|
130
|
+
# def interceptRequest(self, info):
|
131
|
+
# url = info.requestUrl()
|
132
|
+
# navigation_type = info.navigationType()
|
133
|
+
|
134
|
+
# print("--------------------------------")
|
135
|
+
|
136
|
+
# if navigation_type == QWebEnginePage.NavigationType.NavigationTypeTyped:
|
137
|
+
# print("NavigationTypeTyped")
|
138
|
+
|
139
|
+
# if navigation_type == QWebEnginePage.NavigationType.NavigationTypeReload:
|
140
|
+
# print("NavigationTypeReload")
|
141
|
+
|
142
|
+
# if navigation_type == QWebEnginePage.NavigationType.NavigationTypeBackForward:
|
143
|
+
# print("NavigationTypeBackForward")
|
144
|
+
|
145
|
+
# if navigation_type == QWebEnginePage.NavigationType.NavigationTypeLinkClicked:
|
146
|
+
# print("NavigationTypeLinkClicked")
|
147
|
+
|
148
|
+
# if navigation_type == QWebEnginePage.NavigationType.NavigationTypeFormSubmitted:
|
149
|
+
# print("NavigationTypeFormSubmitted")
|
150
|
+
|
151
|
+
# if navigation_type == QWebEnginePage.NavigationType.NavigationTypeTyped:
|
152
|
+
# print("NavigationTypeTyped")
|
153
|
+
|
154
|
+
# if navigation_type == QWebEnginePage.NavigationType.NavigationTypeOther:
|
155
|
+
# print("NavigationTypeOther")
|
156
|
+
|
157
|
+
# print(navigation_type.value)
|
158
|
+
|
159
|
+
# print(url)
|
160
|
+
# print(url.scheme())
|
161
|
+
# print(url.host())
|
162
|
+
# print(url.url())
|
163
|
+
# print(self.last_path)
|
164
|
+
|
165
|
+
# self.last_path = url.path()
|
166
|
+
|
167
|
+
|
111
168
|
class CustomWebEngineView(QWebEngineView):
|
112
169
|
def __init__(self, parent: "BrowserWindow" = None):
|
113
170
|
super().__init__(parent._window)
|
@@ -433,6 +490,13 @@ class BrowserWindow:
|
|
433
490
|
# Set F12 shortcut
|
434
491
|
self.set_dev_tools(self.dev_tools)
|
435
492
|
|
493
|
+
# 프로필 가져오기 및 인터셉터 설정
|
494
|
+
profile = self.web_view.page().profile()
|
495
|
+
|
496
|
+
# # 기존 인터셉터가 있다면 제거
|
497
|
+
# if self.interceptor:
|
498
|
+
# profile.setUrlRequestInterceptor(None)
|
499
|
+
|
436
500
|
def _on_load_finished(self, ok):
|
437
501
|
"""Handles the event when the web page finishes loading."""
|
438
502
|
if ok and self.js_apis:
|
@@ -2,27 +2,30 @@ from pyloid.utils import get_platform
|
|
2
2
|
import json
|
3
3
|
from pathlib import Path
|
4
4
|
|
5
|
+
|
5
6
|
def create_spec_from_json(json_path):
|
6
|
-
with open(json_path,
|
7
|
+
with open(json_path, "r", encoding="utf-8") as f:
|
7
8
|
config = json.load(f)
|
8
9
|
|
9
10
|
os_type = get_platform()
|
10
|
-
|
11
|
-
if os_type ==
|
11
|
+
|
12
|
+
if os_type == "macos":
|
12
13
|
spec_content = _create_macos_spec(config)
|
13
|
-
elif os_type ==
|
14
|
+
elif os_type == "linux":
|
14
15
|
spec_content = _create_linux_spec(config)
|
15
16
|
else: # windows
|
16
17
|
spec_content = _create_windows_spec(config)
|
17
|
-
|
18
|
+
|
18
19
|
spec_path = Path(f"build-{os_type}.spec")
|
19
|
-
spec_path.write_text(spec_content, encoding=
|
20
|
-
|
20
|
+
spec_path.write_text(spec_content, encoding="utf-8")
|
21
|
+
|
21
22
|
return str(spec_path)
|
22
23
|
|
24
|
+
|
23
25
|
def _create_windows_spec(config):
|
24
|
-
bundle_type = config.get(
|
25
|
-
|
26
|
+
bundle_type = config.get("bundle", {}).get("windows", "directory")
|
27
|
+
console = config.get("console", False)
|
28
|
+
|
26
29
|
base_spec = f"""# -*- mode: python ; coding: utf-8 -*-
|
27
30
|
|
28
31
|
block_cipher = None
|
@@ -47,8 +50,10 @@ pyz = PYZ(a.pure, a.zipped_data,
|
|
47
50
|
cipher=block_cipher)
|
48
51
|
"""
|
49
52
|
|
50
|
-
if bundle_type ==
|
51
|
-
return
|
53
|
+
if bundle_type == "onefile":
|
54
|
+
return (
|
55
|
+
base_spec
|
56
|
+
+ f"""
|
52
57
|
exe = EXE(
|
53
58
|
pyz,
|
54
59
|
a.scripts,
|
@@ -63,7 +68,7 @@ exe = EXE(
|
|
63
68
|
upx=True,
|
64
69
|
upx_exclude=[],
|
65
70
|
runtime_tmpdir=None,
|
66
|
-
console=
|
71
|
+
console={console},
|
67
72
|
disable_windowed_traceback=False,
|
68
73
|
argv_emulation=False,
|
69
74
|
target_arch=None,
|
@@ -72,8 +77,11 @@ exe = EXE(
|
|
72
77
|
icon='{config.get('icon', 'src-pyloid/icons/icon.ico')}'
|
73
78
|
)
|
74
79
|
"""
|
80
|
+
)
|
75
81
|
else:
|
76
|
-
return
|
82
|
+
return (
|
83
|
+
base_spec
|
84
|
+
+ f"""
|
77
85
|
exe = EXE(
|
78
86
|
pyz,
|
79
87
|
a.scripts,
|
@@ -84,7 +92,7 @@ exe = EXE(
|
|
84
92
|
bootloader_ignore_signals=False,
|
85
93
|
strip=False,
|
86
94
|
upx=True,
|
87
|
-
console=
|
95
|
+
console={console},
|
88
96
|
disable_windowed_traceback=False,
|
89
97
|
argv_emulation=False,
|
90
98
|
target_arch=None,
|
@@ -104,8 +112,11 @@ coll = COLLECT(
|
|
104
112
|
name='{config.get("name", "pyloid-app")}'
|
105
113
|
)
|
106
114
|
"""
|
115
|
+
)
|
116
|
+
|
107
117
|
|
108
118
|
def _create_macos_spec(config):
|
119
|
+
console = config.get("console", False)
|
109
120
|
return f"""# -*- mode: python ; coding: utf-8 -*-
|
110
121
|
|
111
122
|
a = Analysis(
|
@@ -134,7 +145,7 @@ exe = EXE(
|
|
134
145
|
bootloader_ignore_signals=False,
|
135
146
|
strip=False,
|
136
147
|
upx=True,
|
137
|
-
console=
|
148
|
+
console={console},
|
138
149
|
disable_windowed_traceback=False,
|
139
150
|
argv_emulation=False,
|
140
151
|
target_arch=None,
|
@@ -161,9 +172,11 @@ app = BUNDLE(
|
|
161
172
|
)
|
162
173
|
"""
|
163
174
|
|
175
|
+
|
164
176
|
def _create_linux_spec(config):
|
165
|
-
bundle_type = config.get(
|
166
|
-
|
177
|
+
bundle_type = config.get("bundle", {}).get("linux", "directory")
|
178
|
+
console = config.get("console", False)
|
179
|
+
|
167
180
|
base_spec = f"""# -*- mode: python ; coding: utf-8 -*-
|
168
181
|
|
169
182
|
block_cipher = None
|
@@ -188,8 +201,10 @@ pyz = PYZ(a.pure, a.zipped_data,
|
|
188
201
|
cipher=block_cipher)
|
189
202
|
"""
|
190
203
|
|
191
|
-
if bundle_type ==
|
192
|
-
return
|
204
|
+
if bundle_type == "onefile":
|
205
|
+
return (
|
206
|
+
base_spec
|
207
|
+
+ f"""
|
193
208
|
exe = EXE(
|
194
209
|
pyz,
|
195
210
|
a.scripts,
|
@@ -204,7 +219,7 @@ exe = EXE(
|
|
204
219
|
upx=True,
|
205
220
|
upx_exclude=[],
|
206
221
|
runtime_tmpdir=None,
|
207
|
-
console=
|
222
|
+
console={console},
|
208
223
|
disable_windowed_traceback=False,
|
209
224
|
argv_emulation=False,
|
210
225
|
target_arch=None,
|
@@ -213,8 +228,11 @@ exe = EXE(
|
|
213
228
|
icon='{config.get('icon', 'src-pyloid/icons/icon.png')}'
|
214
229
|
)
|
215
230
|
"""
|
231
|
+
)
|
216
232
|
else:
|
217
|
-
return
|
233
|
+
return (
|
234
|
+
base_spec
|
235
|
+
+ f"""
|
218
236
|
exe = EXE(
|
219
237
|
pyz,
|
220
238
|
a.scripts,
|
@@ -225,7 +243,7 @@ exe = EXE(
|
|
225
243
|
bootloader_ignore_signals=False,
|
226
244
|
strip=False,
|
227
245
|
upx=True,
|
228
|
-
console=
|
246
|
+
console={console},
|
229
247
|
disable_windowed_traceback=False,
|
230
248
|
argv_emulation=False,
|
231
249
|
target_arch=None,
|
@@ -244,4 +262,5 @@ coll = COLLECT(
|
|
244
262
|
upx_exclude=[],
|
245
263
|
name='{config.get("name", "pyloid-app")}'
|
246
264
|
)
|
247
|
-
"""
|
265
|
+
"""
|
266
|
+
)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|