Skip to content

Instantly share code, notes, and snippets.

@AntonDumov
Created April 19, 2021 10:25
Show Gist options
  • Save AntonDumov/29f0c0088ba32569b7c1ed8fb8609251 to your computer and use it in GitHub Desktop.
Save AntonDumov/29f0c0088ba32569b7c1ed8fb8609251 to your computer and use it in GitHub Desktop.
Elite Dangerous Downloader.
# ELite Dangerous Downloader
#
# Get download manifest with Microsoft Network Monitor
# and put it in MANIFEST_URL
# Put download directory path to DOWNLOAD_DIR
#
# Original code here: https://pastebin.com/zbgS25x4
import gzip
import hashlib
import io
import os
import sys
import urllib.request, urllib.parse, urllib.error
from xml.etree import ElementTree
MANIFEST_URL = "http://cdn.zaonce.net/elitedangerous/win/manifests/Win64_4_0_0_20_Alpha+%282021.04.16.264080%29.xml.gz"
DOWNLOAD_DIR = "C:\\Users\\Admin\\AppData\\Local\\Frontier_Developments\\Products\\PUBLIC_TEST_SERVER_64"
PRODUCT_FOLDER = "\\".join(DOWNLOAD_DIR.split('\\')[-2:])
def generateDirectories(path):
dir = os.path.dirname(path)
if not os.path.isdir(dir):
os.makedirs(dir)
def getPatchManifest(manifestURL):
compressedManifest = io.BytesIO(urllib.request.urlopen(manifestURL).read())
with gzip.open(compressedManifest, 'rb') as f:
decompressedManifest = f.read().decode('utf-8')
with open('temp.xml', 'w', encoding='utf-8') as f:
f.write(decompressedManifest)
parsedManifest = ElementTree.fromstring(decompressedManifest)
return parsedManifest
def alreadyHaveAsset(downloadPath, assetHash):
if os.path.isfile(downloadPath):
# Asset exists on disk, but need to check version
sha1 = hashlib.sha1()
sha1.update(open(downloadPath, "rb").read())
localHash = sha1.hexdigest()
return localHash == assetHash
else:
# Asset doesn't exist on disk
return False
def reportFileProgress(blockNumber, blockSize, fileSize):
blockSize /= 1048576.0 # Bytes -> Megabytes
fileSize /= 1048576.0 # Bytes -> Megabytes
currentSize = blockNumber * blockSize
percentComplete = min(100.0 * currentSize/fileSize, 100.00)
print("\r\t%.2f MB / %.2f MB (%.2f%%)" % (currentSize, fileSize, percentComplete), end=' ')
def downloadAssets(manifest, downloadDir):
assetCount = len(manifest)
# Get assets
for assetNumber, asset in enumerate(manifest):
assetURL = asset.find("Download").text
assetSize = float(asset.find("Size").text) / 1048576.0 # Bytes -> Megabytes
assetHash = asset.find("Hash").text
assetRelPath = asset.find("Path").text
downloadPath = os.path.join(downloadDir, assetRelPath)
generateDirectories(downloadPath)
if alreadyHaveAsset(downloadPath, assetHash):
print("Skipping file %d of %d: %s" % (assetNumber+1, assetCount, assetRelPath))
else:
print("Downloading file %d of %d: %s" % (assetNumber+1, assetCount, assetRelPath))
urllib.request.urlretrieve(assetURL, downloadPath, reportFileProgress)
print()
def getInstallPathFromRegistry():
import winreg
edInstallKey = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, "SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\{696F8871-C91D-4CB1-825D-36BE18065575}_is1")
installDir = winreg.QueryValueEx(edInstallKey, "InstallLocation")[0]
downloadDir = os.path.join(installDir, PRODUCT_FOLDER)
return downloadDir
if __name__ == "__main__":
# TODO: Automatically determine manifest URL
manifestURL = MANIFEST_URL
downloadDir = DOWNLOAD_DIR
if not os.path.isdir(downloadDir) and sys.platform == "win32":
print("downloadDir (%s) does not exist. Trying to auto-detect via Windows registry..." % downloadDir)
downloadDir = getInstallPathFromRegistry()
if os.path.isdir(downloadDir):
print("Downloading client files to %s" % downloadDir)
manifest = getPatchManifest(manifestURL)
downloadAssets(manifest, downloadDir)
else:
print("downloadDir (%s) does not exist. Make sure downloadDir is correct and that you've started the download in the official launcher at least once." % downloadDir)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment