banana/banana.py

321 lines
9.7 KiB
Python

from argparse import ArgumentParser
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
from urllib.parse import quote
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('<div\s+id="version">Version:\s+[^<]+')
esoui_version_split = re.compile('<div\s+id="version">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_data = response.read()
# writworthy has some garbage characters on it's page
response_text = response_data[:110000].decode("unicode_escape")
version_line = esoui_version_html.search(response_text).group(0)
version = esoui_version_split.split(version_line)[1]
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)
esoui_dowload_uri = esoui_dowload_uri.split("?")[0]
esoui_dowload_uri = esoui_dowload_uri.split("https://")[1]
esoui_dowload_uri = quote(esoui_dowload_uri)
esoui_dowload_uri = f"https://{esoui_dowload_uri}"
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)
version = "0"
if result:
version = result.group(0)
version = live_version_split.split(version)[1]
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")
copytree(temp_path, live_tamriel_trade_centre, dirs_exist_ok=True)
logging.info(
f"tamriel trade centre price table updated: {live_tamriel_trade_centre}"
)
if __name__ == "__main__":
periodical_script()