browser-select/browser_select.py
2022-04-08 22:45:05 +02:00

186 lines
5.0 KiB
Python
Executable File

#!/bin/python
"""
Browser select script.
Use this as the default browser to allow opening differnt browsers based on
URL patterns.
Controllable via TOML file
"""
import os
import sys
from subprocess import Popen
import re
import pathlib
import appdirs as app_dirs
import toml
HARDCODED_DEFAULT_BROWSER = "chromium"
CONFIG_FILE_NAME = "browser_select.toml"
# pylint: disable=too-few-public-methods
class Browser:
"""
Represents an executable browser
"""
def __init__(self, executable, working_dir=None):
self.exec = executable
self.working_dir = working_dir
def start_browser(self, args):
"""
Start a browser with command line arguments
"""
popen_args = [self.exec, *args]
with Popen(popen_args, cwd=self.working_dir) as proc:
ret_code = proc.poll()
return ret_code
class Site:
"""
Website class that allows to match an url and provides the correct browser
for this website
"""
# pylint: disable=too-many-arguments
def __init__(self, urls, www, protocols, browser, regex=None, name=None):
self.name = "Unnamed Site"
if name is not None:
self.name = name
urls = urls if isinstance(urls, list) else [urls]
protocols = protocols if isinstance(protocols, list) else [protocols]
if regex is None:
self.regexes = []
proto_regex = r'|'.join(protocols)
www_regex = r'(?:www\.|)' if www else ''
for url in urls:
regex = r'^(?:'+proto_regex+r')://'+www_regex+url
self.regexes.append(re.compile(regex))
else:
self.regexes = [re.compile(regex)]
self.browser = browser
def match_url(self, url) -> bool:
"""
Checks if a given url matches the registered patterns for this website
"""
for regex in self.regexes:
if bool(regex.match(url)):
return True
return False
def get_browser(self) -> Browser:
"""
Get the assosciated browser for this website
"""
return self.browser
def get_config():
"""
Return the content of the configuration file.
returns None if nothing is loaded
"""
config_file_path = None
# Check user directory
user_dir = app_dirs.user_config_dir('browser_select', 'shimatta')
user_config_file = os.path.join(user_dir, CONFIG_FILE_NAME)
if os.path.exists(user_config_file):
config_file_path = user_config_file
# Check the location besides the script
if config_file_path is None:
cfg = os.path.join(pathlib.Path(
__file__).parent.resolve(), CONFIG_FILE_NAME)
if os.path.exists(cfg):
config_file_path = cfg
if config_file_path is None:
# Config file not found.
return None
parsed_toml = toml.load(config_file_path)
return parsed_toml
# pylint: disable=too-many-locals # Local variables needed. This is ugly, but I don't care
def parse_config(cfg_dict):
"""
Parse the toml configuration
"""
# Get the browser list
browsers = {}
cfg_browsers = cfg_dict['browsers']
for key, value in cfg_browsers.items():
wdir = value.get('working_dir', None)
browsers[key] = Browser(value['exec'], wdir)
# Get Sites
sites = []
cfg_pattens = cfg_dict['urlpatterns']
for key, value in cfg_pattens.items():
name = value.get('site_name', None)
if name is None:
name = key
protocol = value.get('protocol', ['http', 'https'])
url = value.get('site_url', None)
site_regex = value.get('site_regex', None)
www = value.get('www', True)
site_browser = browsers[value['browser']]
site = Site(url, www, protocol, site_browser,
regex=site_regex, name=name)
sites.append(site)
# Get default browser
try:
default_executable = cfg_dict['general']['default_browser']
except KeyError as _ex:
default_executable = HARDCODED_DEFAULT_BROWSER
default_browser = Browser(default_executable)
return sites, default_browser
def execute_browser():
"""
Main function that checks which browser to use and then executes it
"""
browser_to_execute = Browser(HARDCODED_DEFAULT_BROWSER)
# Try read configuration TOML
try:
cfg = get_config()
sites, default_browser = parse_config(cfg)
browser_to_execute = default_browser
# pylint: disable=broad-except # Catch all errors in config parsing. It has to be correct
except Exception as ex:
print(ex)
if len(sys.argv) > 1:
cmd_args = sys.argv[1:]
url_param = sys.argv[1]
else:
cmd_args = []
url_param = None
if url_param is not None:
for site in sites:
if site.match_url(url_param):
browser_to_execute = site.get_browser()
break
return browser_to_execute.start_browser(cmd_args)
if __name__ == '__main__':
sys.exit(execute_browser())