# coding=utf-8 import os import platform import logging import requests import json import hashlib import stat from whichcraft import which from dogpile.cache import make_region region = make_region().configure('dogpile.cache.memory') class BinaryNotFound(Exception): pass @region.cache_on_arguments() def md5(fname): hash_md5 = hashlib.md5() with open(fname, "rb") as f: for chunk in iter(lambda: f.read(4096), b""): hash_md5.update(chunk) return hash_md5.hexdigest() @region.cache_on_arguments() def get_binaries_from_json(): try: binaries_json_file = os.path.realpath(os.path.join(os.path.dirname(__file__), 'binaries.json')) with open(binaries_json_file) as json_file: binaries_json = json.load(json_file) except OSError: logging.exception('BAZARR cannot access binaries.json') return [] else: return binaries_json def get_binary(name): installed_exe = which(name) if installed_exe and os.path.isfile(installed_exe): logging.debug(f'BAZARR returning this binary: {installed_exe}') return installed_exe else: logging.debug('BAZARR binary not found in path, searching for it...') binaries_dir = os.path.realpath(os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'bin')) system = platform.system() machine = platform.machine() dir_name = name # deals with exceptions if platform.system() == "Windows": # Windows machine = "i386" name = "%s.exe" % name elif platform.system() == "Darwin": # MacOSX system = 'MacOSX' if name in ['ffprobe', 'ffprobe.exe']: dir_name = 'ffmpeg' exe_dir = os.path.abspath(os.path.join(binaries_dir, system, machine, dir_name)) exe = os.path.abspath(os.path.join(exe_dir, name)) binaries_json = get_binaries_from_json() binary = next((item for item in binaries_json if item['system'] == system and item['machine'] == machine and item['directory'] == dir_name and item['name'] == name), None) if not binary: logging.debug('BAZARR binary not found in binaries.json') raise BinaryNotFound else: logging.debug(f'BAZARR found this in binaries.json: {binary}') if os.path.isfile(exe) and md5(exe) == binary['checksum']: logging.debug(f'BAZARR returning this existing and up-to-date binary: {exe}') return exe else: try: logging.debug(f'BAZARR creating directory tree for {exe_dir}') os.makedirs(exe_dir, exist_ok=True) logging.debug(f'BAZARR downloading {name} from {binary["url"]}') r = requests.get(binary['url']) logging.debug(f'BAZARR saving {name} to {exe_dir}') with open(exe, 'wb') as f: f.write(r.content) if system != 'Windows': logging.debug(f'BAZARR adding execute permission on {exe}') st = os.stat(exe) os.chmod(exe, st.st_mode | stat.S_IEXEC) except Exception: logging.exception(f'BAZARR unable to download {name} to {exe_dir}') raise BinaryNotFound else: logging.debug(f'BAZARR returning this new binary: {exe}') return exe