unifi-firmware-download/unifi-firmware-download.py
2023-11-21 16:54:31 +01:00

143 lines
4.7 KiB
Python

#!/usr/bin/env python
import logging
import os
import json
import requests
def load_json(filename):
logging.info(f"reading json file {filename}")
try:
with open(filename) as f:
data = json.load(f)
return data
except:
logging.exception(f"could not read file {filename}")
return None
def write_json(filename, data):
logging.info(f"writing json file {filename}")
try:
with open(filename, "w") as f:
json.dump(data, f)
except:
logging.exception(f"could not write file {filename}")
def load_firmware_meta(path):
try:
firmware_meta = load_json(os.path.join(path, "firmware_meta.json"))
if firmware_meta is None:
return []
return firmware_meta.get('cached_firmwares', [])
except:
logging.exception(f"could load firmware meta")
return []
return firmware_meta
def write_firmware_meta(path, data):
try:
firmware_meta = {
'cached_firmwares': data
}
write_json(os.path.join(path, "firmware_meta.json"), firmware_meta)
except:
logging.exception(f"could write firmware meta")
def online_firmware_check():
try:
resp = requests.get("https://fw-update.ubnt.com/api/firmware-newest",
params={"filter": ["eq~~product~~unifi-firmware", "eq~~channel~~release"]})
data = resp.json()
return data.get("_embedded").get("firmware", [])
except:
logging.exception(f"could load firmware updates")
return []
def online_firmware_download(url, filename):
try:
path = os.path.dirname(filename)
os.makedirs(path, exist_ok=True)
response = requests.get(url, stream=True)
with open(filename, mode="wb") as file:
for chunk in response.iter_content(chunk_size=10 * 1024):
file.write(chunk)
except:
logging.exception(f"could not download firmware {url}")
return False
else:
return True
def main(args):
firmware_meta = load_firmware_meta(args.firmware_dir)
firmware_latest = online_firmware_check()
# loop over the all available firmware
# if found in 'meta', just add device to ther list
# we assume, the firmware is already downloaded
# if not found in 'meta', add ne item and download firmware
for firmware in firmware_latest:
firmware_platform = firmware.get('platform')
firmware_version = [
str(firmware.get('version_major')),
str(firmware.get('version_minor')),
str(firmware.get('version_patch')),
str(firmware.get('version_build')),
]
firmware_version = ".".join(firmware_version)
if args.platform is not None:
if firmware_platform not in args.platform:
continue
logging.info(f"processing firmware {firmware_platform}/{firmware_version}")
found = None
for meta in firmware_meta:
# compare some values
if meta.get('version') != firmware_version:
continue
if meta.get('md5') != firmware.get('md5'):
continue
if meta.get('size') != firmware.get('file_size'):
continue
# if all values match, we got our item
found = meta
break
# just add device to the list
if found is not None:
if firmware.get('platform') not in found.get('devices'):
found['devices'].append(firmware.get('platform'))
continue
firmware_url = firmware.get('_links', {}).get('data', {}).get('href', {})
if firmware_url is None:
logging.error(f"unalbe to get firmware path for {firmware_platform}/{firmware_version}")
continue
found = {
'md5': firmware.get('md5'),
'version': firmware_version,
'size': firmware.get('file_size'),
'path': os.path.join(firmware.get('platform'), firmware_version,firmware_url.split("/")[-1]),
'devices': [firmware.get('platform')]
}
if online_firmware_download(firmware_url, os.path.join(args.firmware_dir, found['path'])):
firmware_meta.append(found)
write_firmware_meta(args.firmware_dir, firmware_meta)
if __name__ == "__main__":
format = "%(asctime)s: %(message)s"
logging.basicConfig(format=format, level=logging.DEBUG, datefmt="%H:%M:%S")
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-f", "--firmware-dir", type=str, required=True, help="directory with firmwares")
parser.add_argument("-p","--platform", action='append', help='platform list to download', required=False)
args = parser.parse_args()
main(args)