Skip to content

Commit 34ac751

Browse files
committed
added support for other chromium-based browsers
1 parent 0e00853 commit 34ac751

File tree

11 files changed

+124
-25
lines changed

11 files changed

+124
-25
lines changed

autofill/autofill.py

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,29 @@
1-
import argparse
21
import os
32

3+
import click
4+
5+
from src.constants import browsers
46
from src.driver import AutofillDriver
57
from src.utils import TEXT_BOLD, TEXT_END
68

79
# https://stackoverflow.com/questions/12492810/python-how-can-i-make-the-ansi-escape-codes-to-work-also-in-windows
810
os.system("") # enables ansi escape characters in terminal
911

10-
command_line_argument_parser = argparse.ArgumentParser(description="MPC Autofill")
11-
command_line_argument_parser.add_argument("--skipsetup", action="store_true", default=False, help="Skip Setup")
12-
command_line_args = command_line_argument_parser.parse_args()
13-
1412

15-
def main():
13+
@click.command()
14+
@click.option(
15+
"--skipsetup", default=False, help="Skip project setup to continue editing an existing MPC project.", is_flag=True
16+
)
17+
@click.option(
18+
"-b",
19+
"--browser",
20+
default="chrome",
21+
type=click.Choice(sorted(browsers.keys()), case_sensitive=False),
22+
help="Web browser to automate.",
23+
)
24+
def main(skipsetup, browser):
1625
try:
17-
AutofillDriver().execute(command_line_args.skipsetup)
26+
AutofillDriver(driver_callable=browsers[browser]).execute(skipsetup)
1827
except Exception as e:
1928
print(f"An uncaught exception occurred: {TEXT_BOLD}{e}{TEXT_END}")
2029
input("Press Enter to exit.")

autofill/readme.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ Some notes on how editing an existing project with `--skipsetup` works:
3333
* Any slots which have already been filled will not be refilled,
3434
* If an image is now allocated to more slots, the tool will fill the unfilled slots with the image from the first filled slot for that image.
3535

36+
## Specifying Browser
37+
By default, the tool will configure a driver for Google Chrome. The three major Chromium-based browsers are supported (Chrome, Edge, and Brave), and you can specify which browser should be used to configure the driver with the `--browser` command line argument.
38+
3639
## Developer Guide
3740
### Running the Source Code
3841
From the base repo directory:

autofill/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
attrs
2+
click
23
colorama
34
coverage
45
defusedxml

autofill/src/constants.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,16 @@
3737
"""
3838

3939

40+
import os
4041
from enum import Enum
42+
from typing import Callable
43+
44+
from selenium.webdriver.remote.webdriver import WebDriver
45+
46+
import src.webdrivers as wd
47+
48+
# Disable logging messages for webdriver_manager
49+
os.environ["WDM_LOG_LEVEL"] = "0"
4150

4251

4352
class States(str, Enum):
@@ -85,6 +94,15 @@ class CardTags(str, Enum):
8594
query = "query"
8695

8796

97+
browsers: dict[str, Callable[[bool], WebDriver]] = {
98+
"chrome": wd.get_chrome_driver,
99+
"brave": wd.get_brave_driver,
100+
# "firefox": wd.get_firefox_driver, # TODO: this driver is a bit buggy with the rest of the code - test thoroughly
101+
"edge": wd.get_edge_driver,
102+
# "opera": wd.get_opera_driver, # TODO: this driver is a bit buggy with the rest of the code - test thoroughly
103+
}
104+
105+
88106
class GoogleScriptsAPIs(str, Enum):
89107
image_name = "https://script.google.com/macros/s/AKfycbw90rkocSdppkEuyVdsTuZNslrhd5zNT3XMgfucNMM1JjhLl-Q/exec"
90108
image_content = (

autofill/src/driver.py

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,18 @@
1-
import os
21
import textwrap
32
import time
43
from concurrent.futures import ThreadPoolExecutor
54
from contextlib import contextmanager
6-
from typing import Any, Optional
5+
from typing import Any, Callable, Optional
76

87
import attr
98
import enlighten
109
from selenium import webdriver
1110
from selenium.common import exceptions as sl_exc
1211
from selenium.common.exceptions import NoAlertPresentException, NoSuchElementException
13-
from selenium.webdriver.chrome.options import Options
14-
from selenium.webdriver.chrome.service import Service
1512
from selenium.webdriver.common.by import By
13+
from selenium.webdriver.remote.webdriver import WebDriver
1614
from selenium.webdriver.support.expected_conditions import invisibility_of_element
1715
from selenium.webdriver.support.ui import Select, WebDriverWait
18-
from webdriver_manager.chrome import ChromeDriverManager
1916

2017
from src.constants import THREADS, States
2118
from src.order import CardImage, CardImageCollection, CardOrder
@@ -26,14 +23,13 @@
2623
alert_handler,
2724
time_to_hours_minutes_seconds,
2825
)
29-
30-
# Disable logging messages for webdriver_manager
31-
os.environ["WDM_LOG_LEVEL"] = "0"
26+
from src.webdrivers import get_chrome_driver
3227

3328

3429
@attr.s
3530
class AutofillDriver:
3631
driver: webdriver.Chrome = attr.ib(default=None) # delay initialisation until XML is selected and parsed
32+
driver_callable: Callable[[bool], WebDriver] = attr.ib(default=get_chrome_driver)
3733
headless: bool = attr.ib(default=False)
3834
starting_url: str = attr.ib(
3935
init=False,
@@ -50,20 +46,14 @@ class AutofillDriver:
5046
# region initialisation
5147
def initialise_driver(self) -> None:
5248
try:
53-
chrome_options = Options()
54-
chrome_options.add_argument("--log-level=3")
55-
if self.headless:
56-
chrome_options.add_argument("--headless")
57-
chrome_options.add_experimental_option("excludeSwitches", ["enable-logging"])
58-
chrome_options.add_experimental_option("detach", True)
59-
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=chrome_options)
49+
driver = self.driver_callable(self.headless)
6050
driver.set_window_size(1200, 900)
6151
driver.implicitly_wait(5)
62-
driver.set_network_conditions(offline=False, latency=5, throughput=5 * 125000)
52+
print(f"Successfully initialised {TEXT_BOLD}{driver.name}{TEXT_END} driver.")
6353
except ValueError as e:
6454
raise Exception(
65-
f"An error occurred while attempting to configure Chrome webdriver. Please make sure you have "
66-
f"installed Chrome and that it is up to date: {e}"
55+
f"An error occurred while attempting to configure the webdriver for {self.driver.name}. "
56+
f"Please make sure you have installed {self.driver.name} and that it is up to date: {e}"
6757
)
6858

6959
self.driver = driver

autofill/src/webdrivers/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
from .brave import get_brave_driver
2+
from .chrome import get_chrome_driver
3+
from .edge import get_edge_driver
4+
from .firefox import get_firefox_driver
5+
from .opera import get_opera_driver

autofill/src/webdrivers/brave.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from selenium.webdriver import Chrome
2+
from selenium.webdriver.chrome.options import Options
3+
from selenium.webdriver.chrome.service import Service
4+
from webdriver_manager.chrome import ChromeDriverManager, ChromeType
5+
6+
7+
def get_brave_driver(headless: bool = False) -> Chrome:
8+
options = Options()
9+
options.add_argument("--log-level=3")
10+
if headless:
11+
options.add_argument("--headless")
12+
options.add_experimental_option("excludeSwitches", ["enable-logging"])
13+
options.add_experimental_option("detach", True)
14+
driver = Chrome(service=Service(ChromeDriverManager(chrome_type=ChromeType.BRAVE).install()), options=options)
15+
driver.set_network_conditions(offline=False, latency=5, throughput=5 * 125000)
16+
return driver

autofill/src/webdrivers/chrome.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from selenium.webdriver import Chrome
2+
from selenium.webdriver.chrome.options import Options
3+
from selenium.webdriver.chrome.service import Service
4+
from webdriver_manager.chrome import ChromeDriverManager
5+
6+
7+
def get_chrome_driver(headless: bool = False) -> Chrome:
8+
options = Options()
9+
options.add_argument("--log-level=3")
10+
if headless:
11+
options.add_argument("--headless")
12+
options.add_experimental_option("excludeSwitches", ["enable-logging"])
13+
options.add_experimental_option("detach", True)
14+
driver = Chrome(service=Service(ChromeDriverManager().install()), options=options)
15+
driver.set_network_conditions(offline=False, latency=5, throughput=5 * 125000)
16+
return driver

autofill/src/webdrivers/edge.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from selenium.webdriver import Edge
2+
from selenium.webdriver.edge.options import Options
3+
from selenium.webdriver.edge.service import Service
4+
from webdriver_manager.microsoft import EdgeChromiumDriverManager
5+
6+
7+
def get_edge_driver(headless: bool = False) -> Edge:
8+
options = Options()
9+
options.add_argument("--log-level=3")
10+
if headless:
11+
options.add_argument("--headless")
12+
options.add_experimental_option("excludeSwitches", ["enable-logging"])
13+
options.add_experimental_option("detach", True)
14+
driver = Edge(service=Service(EdgeChromiumDriverManager().install()), options=options)
15+
driver.set_network_conditions(offline=False, latency=5, throughput=5 * 125000)
16+
return driver

autofill/src/webdrivers/firefox.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from selenium.webdriver import Firefox
2+
from selenium.webdriver.firefox.options import Options
3+
from selenium.webdriver.firefox.service import Service
4+
from webdriver_manager.firefox import GeckoDriverManager
5+
6+
7+
def get_firefox_driver(headless: bool = False) -> Firefox:
8+
options = Options()
9+
options.add_argument("--log-level=3")
10+
if headless:
11+
options.add_argument("--headless")
12+
driver = Firefox(service=Service(GeckoDriverManager().install()), options=options)
13+
return driver

autofill/src/webdrivers/opera.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from selenium.webdriver import Opera
2+
from selenium.webdriver.opera.options import Options
3+
from webdriver_manager.opera import OperaDriverManager
4+
5+
6+
def get_opera_driver(headless: bool = False) -> Opera:
7+
options = Options()
8+
options.add_argument("--log-level=3")
9+
if headless:
10+
options.add_argument("--headless")
11+
driver = Opera(executable_path=OperaDriverManager().install(), options=options)
12+
return driver

0 commit comments

Comments
 (0)