gformbot 0.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.
- gformbot/__init__.py +6 -0
- gformbot/__main__.py +3 -0
- gformbot/browser.py +165 -0
- gformbot/cli.py +800 -0
- gformbot/config.py +192 -0
- gformbot/filler.py +227 -0
- gformbot/generator.py +187 -0
- gformbot/inspector.py +227 -0
- gformbot/logger.py +34 -0
- gformbot-0.1.0.dist-info/METADATA +230 -0
- gformbot-0.1.0.dist-info/RECORD +15 -0
- gformbot-0.1.0.dist-info/WHEEL +5 -0
- gformbot-0.1.0.dist-info/entry_points.txt +2 -0
- gformbot-0.1.0.dist-info/licenses/LICENSE +180 -0
- gformbot-0.1.0.dist-info/top_level.txt +1 -0
gformbot/__init__.py
ADDED
gformbot/__main__.py
ADDED
gformbot/browser.py
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Browser driver factory.
|
|
3
|
+
|
|
4
|
+
Priority:
|
|
5
|
+
1. User-requested browser (via --browser flag or wizard prompt).
|
|
6
|
+
2. Auto-detect system default browser.
|
|
7
|
+
3. Graceful fallback to headless Chromium.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from __future__ import annotations
|
|
11
|
+
|
|
12
|
+
import platform
|
|
13
|
+
import shutil
|
|
14
|
+
import subprocess
|
|
15
|
+
import sys
|
|
16
|
+
import winreg
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Literal
|
|
19
|
+
|
|
20
|
+
BrowserName = Literal["chrome", "firefox", "edge", "auto", "headless"]
|
|
21
|
+
|
|
22
|
+
_WINDOWS = sys.platform == "win32"
|
|
23
|
+
_MACOS = sys.platform == "darwin"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# ---------------------------------------------------------------------------
|
|
27
|
+
# Default-browser detection
|
|
28
|
+
# ---------------------------------------------------------------------------
|
|
29
|
+
|
|
30
|
+
def _default_browser_windows() -> BrowserName:
|
|
31
|
+
"""Read the Windows registry to figure out the default browser."""
|
|
32
|
+
try:
|
|
33
|
+
key = winreg.OpenKey(
|
|
34
|
+
winreg.HKEY_CURRENT_USER,
|
|
35
|
+
r"Software\Microsoft\Windows\Shell\Associations\UrlAssociations\https\UserChoice",
|
|
36
|
+
)
|
|
37
|
+
prog_id, _ = winreg.QueryValueEx(key, "ProgId")
|
|
38
|
+
winreg.CloseKey(key)
|
|
39
|
+
prog_id = prog_id.lower()
|
|
40
|
+
if "firefox" in prog_id:
|
|
41
|
+
return "firefox"
|
|
42
|
+
if "edge" in prog_id:
|
|
43
|
+
return "edge"
|
|
44
|
+
if "chrome" in prog_id:
|
|
45
|
+
return "chrome"
|
|
46
|
+
except Exception:
|
|
47
|
+
pass
|
|
48
|
+
return "chrome" # sensible default
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _default_browser_macos() -> BrowserName:
|
|
52
|
+
try:
|
|
53
|
+
result = subprocess.run(
|
|
54
|
+
["defaults", "read", "com.apple.LaunchServices/com.apple.launchservices.secure",
|
|
55
|
+
"LSHandlers"],
|
|
56
|
+
capture_output=True, text=True, timeout=5,
|
|
57
|
+
)
|
|
58
|
+
out = result.stdout.lower()
|
|
59
|
+
if "firefox" in out:
|
|
60
|
+
return "firefox"
|
|
61
|
+
if "microsoft edge" in out or "msedge" in out:
|
|
62
|
+
return "edge"
|
|
63
|
+
except Exception:
|
|
64
|
+
pass
|
|
65
|
+
return "chrome"
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _default_browser_linux() -> BrowserName:
|
|
69
|
+
try:
|
|
70
|
+
result = subprocess.run(
|
|
71
|
+
["xdg-settings", "get", "default-web-browser"],
|
|
72
|
+
capture_output=True, text=True, timeout=5,
|
|
73
|
+
)
|
|
74
|
+
val = result.stdout.lower()
|
|
75
|
+
if "firefox" in val:
|
|
76
|
+
return "firefox"
|
|
77
|
+
if "chromium" in val:
|
|
78
|
+
return "chrome"
|
|
79
|
+
if "microsoft-edge" in val or "msedge" in val:
|
|
80
|
+
return "edge"
|
|
81
|
+
except Exception:
|
|
82
|
+
pass
|
|
83
|
+
# Try which
|
|
84
|
+
for name in ("google-chrome", "chromium-browser", "chromium", "firefox"):
|
|
85
|
+
if shutil.which(name):
|
|
86
|
+
return "chrome" if "chrome" in name or "chromium" in name else "firefox"
|
|
87
|
+
return "chrome"
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def detect_default_browser() -> BrowserName:
|
|
91
|
+
if _WINDOWS:
|
|
92
|
+
return _default_browser_windows()
|
|
93
|
+
if _MACOS:
|
|
94
|
+
return _default_browser_macos()
|
|
95
|
+
return _default_browser_linux()
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
# ---------------------------------------------------------------------------
|
|
99
|
+
# Driver factory
|
|
100
|
+
# ---------------------------------------------------------------------------
|
|
101
|
+
|
|
102
|
+
def get_driver(browser: BrowserName = "auto", headless: bool = False):
|
|
103
|
+
"""
|
|
104
|
+
Return a configured Selenium WebDriver.
|
|
105
|
+
|
|
106
|
+
Parameters
|
|
107
|
+
----------
|
|
108
|
+
browser : "auto" | "chrome" | "firefox" | "edge" | "headless"
|
|
109
|
+
headless : Force headless mode even if browser is named.
|
|
110
|
+
"""
|
|
111
|
+
from selenium import webdriver # imported here so the module loads without selenium
|
|
112
|
+
|
|
113
|
+
if browser == "headless":
|
|
114
|
+
headless = True
|
|
115
|
+
browser = "chrome"
|
|
116
|
+
|
|
117
|
+
if browser == "auto":
|
|
118
|
+
browser = detect_default_browser()
|
|
119
|
+
|
|
120
|
+
if browser == "firefox":
|
|
121
|
+
return _firefox_driver(headless)
|
|
122
|
+
if browser == "edge":
|
|
123
|
+
return _edge_driver(headless)
|
|
124
|
+
|
|
125
|
+
# Default / chrome
|
|
126
|
+
return _chrome_driver(headless)
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def _chrome_driver(headless: bool):
|
|
130
|
+
from selenium import webdriver
|
|
131
|
+
from selenium.webdriver.chrome.options import Options
|
|
132
|
+
|
|
133
|
+
opts = Options()
|
|
134
|
+
opts.add_argument("--incognito")
|
|
135
|
+
opts.add_argument("--start-maximized")
|
|
136
|
+
opts.add_argument("--disable-notifications")
|
|
137
|
+
opts.add_experimental_option("excludeSwitches", ["enable-logging"])
|
|
138
|
+
if headless:
|
|
139
|
+
opts.add_argument("--headless=new")
|
|
140
|
+
opts.add_argument("--window-size=1920,1080")
|
|
141
|
+
return webdriver.Chrome(options=opts)
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _firefox_driver(headless: bool):
|
|
145
|
+
from selenium import webdriver
|
|
146
|
+
from selenium.webdriver.firefox.options import Options
|
|
147
|
+
|
|
148
|
+
opts = Options()
|
|
149
|
+
if headless:
|
|
150
|
+
opts.add_argument("--headless")
|
|
151
|
+
return webdriver.Firefox(options=opts)
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def _edge_driver(headless: bool):
|
|
155
|
+
from selenium import webdriver
|
|
156
|
+
from selenium.webdriver.edge.options import Options
|
|
157
|
+
|
|
158
|
+
opts = Options()
|
|
159
|
+
opts.add_argument("--inprivate")
|
|
160
|
+
opts.add_argument("--start-maximized")
|
|
161
|
+
opts.add_argument("--disable-notifications")
|
|
162
|
+
if headless:
|
|
163
|
+
opts.add_argument("--headless=new")
|
|
164
|
+
opts.add_argument("--window-size=1920,1080")
|
|
165
|
+
return webdriver.Edge(options=opts)
|