diff --git a/README.mdown b/README.mdown
index f5fbcf5..47599d9 100644
--- a/README.mdown
+++ b/README.mdown
@@ -27,7 +27,7 @@ Follow the installation instructions for your `platform`:
- [Windows](#windows-installation)
- [Linux](#linux-installation)
-On first run, the `addons.yaml` file will be created in your ESO live directory.
+On first run, the `addons.text` file will be created in your ESO live directory.
It will look similar to the following:
```yaml
diff --git a/banana.py b/banana.py
new file mode 100644
index 0000000..954db9f
--- /dev/null
+++ b/banana.py
@@ -0,0 +1,316 @@
+from argparse import ArgumentParser
+from distutils.dir_util import copy_tree
+from packaging import version
+from pathlib import Path
+from platform import system
+from shutil import rmtree, copytree, copyfileobj
+from tempfile import TemporaryDirectory, NamedTemporaryFile
+from zipfile import ZipFile
+from urllib.request import Request, urlopen
+import logging
+import re
+
+HEADERS = {
+ "User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:48.0) Gecko/20100101 Firefox/48.0"
+}
+
+
+def live_to_esoui(*, path: Path, esoui_uris: list):
+ live_name, live_version, live_path = live_parse(path)
+
+ if not live_path:
+ return
+
+ esoui_name, esoui_version, esoui_uri = None, None, None
+
+ for _name, _version, _uri in esoui_uris:
+ if _name in live_name:
+ esoui_name, esoui_version, esoui_uri = _name, _version, _uri
+ break
+
+ if live_name in _name:
+ esoui_name, esoui_version, esoui_uri = _name, _version, _uri
+ break
+
+ if not esoui_name:
+ rmtree(live_path)
+ logging.info(f"{live_name} addon removed from: {live_path}")
+ return
+
+ if esoui_version == live_version:
+ logging.info(f"{live_name} is already up to date.")
+ return
+
+ request = Request(esoui_uri, headers=HEADERS)
+ response = urlopen(request)
+ temp_zip = NamedTemporaryFile()
+ copyfileobj(response, temp_zip)
+ temp_dir = TemporaryDirectory()
+ temp_path = Path(temp_dir.name)
+ zip_file = ZipFile(temp_zip)
+ zip_file.extractall(temp_path)
+
+ rmtree(live_path)
+
+ for each in temp_path.iterdir():
+ copytree(each, live_path)
+
+ logging.info(
+ f"{live_name} updated from {live_version} to {esoui_version} at {live_path}"
+ )
+
+
+def esoui_to_live(*, esoui_uris: list, live_path: Path):
+ for addon_name, addon_version, esoui_dowload_uri in esoui_uris:
+ match = None
+
+ for each in live_path.iterdir():
+ if addon_name in each.name:
+ match = each
+ break
+
+ if each.name in addon_name:
+ match = each
+ break
+
+ if match:
+ logging.debug(f"{addon_name} already installed.")
+ continue
+
+ request = Request(esoui_dowload_uri, headers=HEADERS)
+ response = urlopen(request)
+ temp_zip = NamedTemporaryFile()
+ copyfileobj(response, temp_zip)
+ temp_dir = TemporaryDirectory()
+ temp_path = Path(temp_dir.name)
+ zip_file = ZipFile(temp_zip)
+ zip_file.extractall(temp_path)
+
+ for each in temp_path.iterdir():
+ live_dest = live_path.joinpath(each.name)
+
+ if live_dest.exists():
+ continue
+
+ copytree(each, live_dest)
+
+ logging.info(f"{addon_name} installed {addon_version} at {live_dest}")
+
+
+esoui_prefix = re.compile("https://www.esoui.com/downloads/info[0-9]+\-")
+esoui_version_html = re.compile('
Version:\s+[^<]+')
+esoui_version_split = re.compile('
Version:\s+')
+esoui_download = re.compile('https://cdn.esoui.com/downloads/file[^"]*')
+live_version = re.compile("##\s+Version:\s+.*")
+live_version_split = re.compile("##\s+Version:\s+")
+
+
+def esoui_parse(url: str):
+ addon_name = esoui_prefix.split(url)[1]
+ addon_name = addon_name.split(".html")[0]
+
+ request = Request(url, headers=HEADERS)
+ response = urlopen(request)
+ response_text = response.read().decode("unicode_escape")
+ version_line = esoui_version_html.search(response_text).group(0)
+ _version = esoui_version_split.split(version_line)[1]
+ _version = version.parse(_version)
+
+ esoui_page_url = url.replace("info", "download").replace(".html", "")
+
+ request = Request(esoui_page_url, headers=HEADERS)
+ response = urlopen(request)
+ response_text = response.read().decode("unicode_escape")
+ esoui_dowload_uri = esoui_download.search(response_text).group(0)
+ head_request = Request(esoui_dowload_uri, method="HEAD", headers=HEADERS)
+ response = urlopen(head_request)
+ response_text = response.read().decode("unicode_escape")
+
+ return addon_name, _version, esoui_dowload_uri
+
+
+def live_parse(path: Path):
+ if not path.is_dir():
+ logging.error(f"unexpected file object {path}, ignoring")
+ return
+
+ meta_file = path.joinpath(f"{path.stem}.txt")
+
+ if not meta_file.exists():
+ for meta_file in path.glob("*.txt"):
+ if not meta_file.stem in path.stem:
+ continue
+
+ try:
+ with meta_file.open("r") as file_open:
+ meta_data = file_open.read()
+ except UnicodeDecodeError:
+ with meta_file.open("r", encoding="latin-1") as file_open:
+ meta_data = file_open.read()
+
+ addon_name = meta_file.stem
+ result = live_version.search(meta_data)
+
+ if result:
+ _version = result.group(0)
+ _version = live_version_split.split(_version)[1]
+ _version = version.parse(_version)
+ else:
+ _version = version.parse("0")
+
+ return addon_name, _version, path
+
+
+config_template = """https://www.esoui.com/downloads/info7-LibAddonMenu.html
+https://www.esoui.com/downloads/info1245-TamrielTradeCentre.html
+https://www.esoui.com/downloads/info1146-LibCustomMenu.html
+"""
+
+
+def config_new(path: Path):
+ path.touch(exist_ok=True)
+
+ with path.open("w") as file_open:
+ file_open.write(config_template)
+
+
+def periodical_script():
+ parser = ArgumentParser(
+ description="Visit https://www.esoui.com/ to search for addons and their dependencies URLs. Edit addons.text in the ESO live path and add the URL for each addon for installation. "
+ )
+ parser.add_argument("-v", "--verbose", action="count", help="verbose logging")
+ parser.add_argument("-l", "--log", action="store_true")
+ parser.add_argument("-p", "--eso_live_path")
+ args = parser.parse_args()
+
+ if args.eso_live_path:
+ args.eso_live_path = Path(args.eso_live_path)
+ else:
+ if system() == "Windows":
+ args.eso_live_path = Path.home().joinpath(
+ "Documents\Elder Scrolls Online\live"
+ )
+ else:
+ args.eso_live_path = Path.home().joinpath(
+ ".steam/steam/steamapps/compatdata/306130/pfx/drive_c/users/steamuser/Documents/Elder Scrolls Online/live/"
+ )
+
+ if args.verbose:
+ level = logging.DEBUG
+ format = "%(asctime)s %(filename)s:%(lineno)d %(message)s"
+ else:
+ level = logging.INFO
+ format = "%(asctime)s %(message)s"
+
+ if args.log:
+ logging.basicConfig(
+ level=level,
+ format=format,
+ filename=args.eso_live_path.joinpath("banana.log"),
+ )
+ else:
+ logging.basicConfig(
+ level=level,
+ format=format,
+ )
+
+ logging.info(args)
+
+ config_path = Path(args.eso_live_path).joinpath("addons.text")
+
+ if not config_path.exists():
+ config_new(config_path)
+ logging.info(f'addons list created at "{config_path}"')
+
+ with config_path.open("r") as file_open:
+ config_current = file_open.readlines()
+
+ config_current = filter(None, config_current)
+ live_path = args.eso_live_path.joinpath("AddOns")
+ live_path.mkdir(parents=True, exist_ok=True)
+ esoui_uris = list()
+
+ for url in config_current:
+ esoui = esoui_parse(url)
+ esoui_uris.append(esoui)
+
+ for child in live_path.iterdir():
+ live_to_esoui(path=child, esoui_uris=esoui_uris)
+
+ esoui_to_live(esoui_uris=esoui_uris, live_path=live_path)
+ ttc_update(live_path=live_path)
+
+
+def ttc():
+ parser = ArgumentParser(description="Tamriel Trade Centre price table updater.")
+ parser.add_argument("-v", "--verbose", action="count", help="verbose logging")
+ parser.add_argument("-l", "--log", action="store_true")
+ parser.add_argument("-p", "--eso_live_path")
+ args = parser.parse_args()
+
+ if args.eso_live_path:
+ args.eso_live_path = Path(args.eso_live_path)
+ else:
+ if system() == "Windows":
+ args.eso_live_path = Path.home().joinpath(
+ "Documents\Elder Scrolls Online\live"
+ )
+ else:
+ args.eso_live_path = Path.home().joinpath(
+ ".steam/steam/steamapps/compatdata/306130/pfx/drive_c/users/steamuser/Documents/Elder Scrolls Online/live/"
+ )
+
+ if args.verbose:
+ level = logging.DEBUG
+ format = "%(asctime)s %(filename)s:%(lineno)d %(message)s"
+ else:
+ level = logging.INFO
+ format = "%(asctime)s %(message)s"
+
+ if args.log:
+ logging.basicConfig(
+ level=level,
+ format=format,
+ filename=args.eso_live_path.joinpath("banana.log"),
+ )
+ else:
+ logging.basicConfig(
+ level=level,
+ format=format,
+ )
+
+ logging.info(args)
+
+ live_path = Path(args.eso_live_path).joinpath("AddOns")
+
+ if not live_path.is_dir():
+ logging.error(f"eso_live_path_invalid_dir {live_path}")
+ return
+
+ ttc_update(live_path=live_path)
+
+
+price_table_uri = "https://us.tamrieltradecentre.com/download/PriceTable"
+price_table_name = "TamrielTradeCentre"
+
+
+def ttc_update(live_path: Path):
+ request = Request(price_table_uri, headers=HEADERS)
+ response = urlopen(request)
+ temp_zip = NamedTemporaryFile()
+ copyfileobj(response, temp_zip)
+ temp_dir = TemporaryDirectory()
+ temp_path = Path(temp_dir.name)
+ zip_file = ZipFile(temp_zip)
+ zip_file.extractall(temp_path)
+
+ live_tamriel_trade_centre = live_path.joinpath("TamrielTradeCentre")
+ copy_tree(str(temp_path.absolute()), str(live_tamriel_trade_centre.absolute()))
+
+ logging.info(
+ f"tamriel trade centre price table updated: {live_tamriel_trade_centre}"
+ )
+
+
+if __name__ == "__main__":
+ periodical_script()