#! /usr/bin/env python3 import sys from re import match from subprocess import Popen from typing import Any from typing import Callable from typing import List from typing import Iterable from typing import NamedTuple from urllib.parse import urlparse class Intent(NamedTuple): """Intent contains a url requested to be opened""" url: str # referrer isn't possible to be captured at this time referrer: str class BrowserRule(NamedTuple): """BrowserRule is matches a url and launches it in a browser""" match_func: Callable[[Intent], bool] command: str args: List[str] = [] def matched(self, intent: Intent) -> bool: """Checks if the intent matches the rule using match_func""" return self.match_func(intent) def launch(self, intent: Intent) -> None: """Launch the command""" with Popen(["nohup", self.command, *self.args, intent.url], shell=False): pass def maybe_launch(self, intent: Intent) -> bool: """Launch URL in a browser if it matches the rules""" if self.matched(intent): self.launch(intent) return True return False # Matching functions and factories MatchFunc = Callable[[Intent], bool] def match_regex(rules: List[str]) -> MatchFunc: """Returns a function to handle urls and match them using regex""" def match_func(intent: Intent) -> bool: return any(match(rule, intent.url) for rule in rules) return match_func def match_host_regex(rules: List[str]) -> MatchFunc: """Returns a function to handle urls and match them using regex""" def match_func(intent: Intent) -> bool: url = urlparse(intent.url) if not url.hostname: return False return any(match(rule, url.hostname) for rule in rules) return match_func def match_hostname(hostnames: List[str]) -> MatchFunc: """Returns a matching function that parses URLs and checks their hosts""" def match_func(intent: Intent) -> bool: url = urlparse(intent.url) for hostname in hostnames: if url.hostname == hostname: return True return False return match_func def any_match(rules: Iterable[MatchFunc]) -> MatchFunc: """Returns a functino that will check against any match rules Equivalent to using `any(...)`""" def match_func(intent: Intent) -> bool: return any(r(intent) for r in rules) return match_func def default(_: Any) -> bool: """Always returns True""" return True def noop(_: Any) -> bool: """Always returns False""" return False browser_rules = [ # Self-hosted sites BrowserRule( match_host_regex([ r".*\.iamthefij\.com$", r".*\.thefij\.rocks$", r".*\.thefij$", ]), "firefox", ), # Work domains BrowserRule( any_match(( match_hostname([ "app.signalfx.com", "lever.co", "work.grubhub.com", "y", "yelp.rimeto.io", "yelp.slack.com", "yelplove.appspot.com", ]), match_host_regex([ r".*\.lifesize\.com$", r".*\.myworkday\.com$", r".*\.salesforce\.com$", r".*\.yelpcorp\.com$", ]), )), "chromium-browser" ), # Other, generally Googly things BrowserRule( any_match(( match_hostname([ "google.com", "youtube.com", ]), match_host_regex([ r".*\.google\.com$", r".*\.youtube\.com$", ]), )), "chromium-browser", ), # Fall back to firefox as the default BrowserRule( default, "firefox", ), # Sample browsers # Firefox new tab BrowserRule( noop, "firefox", ), # Firefox new window BrowserRule( noop, "firefox", ["--new-window"], ), # Firefox private window BrowserRule( noop, "firefox", ["--private-window"], ), # Chromium new tab BrowserRule( noop, "chromium-browser", ), # Chromium new window BrowserRule( noop, "chromium-browser", ["--new-window"], ), # Chromium incongnito BrowserRule( noop, "chromium-browser", ["--incognito"], ), ] def open_url(url: str, referrer=None) -> bool: """Open a given url based on rule set""" intent = Intent(url, referrer) return any(rule.maybe_launch(intent) for rule in browser_rules) def main(urls: List[str]): """Recieves list of urls and opens them each with provided rule sets""" failed_urls: List[str] = [] for url in urls: if not open_url(url): failed_urls.append(url) if failed_urls: raise ValueError(f"No rules present for {failed_urls}. Add a default rule") if __name__ == "__main__": main(sys.argv[1:])