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 ADDED
@@ -0,0 +1,6 @@
1
+ """
2
+ gformbot — A general-purpose Google Form auto-filler CLI.
3
+ """
4
+
5
+ __version__ = "0.1.0"
6
+ __author__ = "yogeshkrishna"
gformbot/__main__.py ADDED
@@ -0,0 +1,3 @@
1
+ """Allow `python -m gformbot` invocation."""
2
+ from gformbot.cli import main
3
+ main()
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)