import os import sys import hashlib import requests import urllib.parse from urllib.request import urlretrieve def get_file_list(url): url = "https://apidgp-gameplayer.games.dmm.com" + url print("Retrieving file list from " + url) result = requests.get(url) result.raise_for_status() data = result.json()["data"] return data["domain"], data["file_list"] def get_file_hash(file_path): if not os.path.exists(file_path): return None with open(file_path, "rb") as f: file_hash = hashlib.md5() while chunk := f.read(8192): file_hash.update(chunk) return file_hash.hexdigest() def update_game(game_path, files_url, files_param): print("Updating game") server_url, server_files = get_file_list(files_url) server_file_dict = {file["local_path"]: file for file in server_files} local_files = [os.path.join(dp, f).replace("\\", "/") for dp, dn, filenames in os.walk(game_path) for f in filenames] local_file_dict = {"/" + os.path.relpath(r, game_path).replace("\\", "/"): {"abs_path":r, "hash":""} for r in local_files} files_to_download = [] files_to_delete = [] for server_file_key in server_file_dict.keys(): server_file = server_file_dict[server_file_key] if server_file_key in local_file_dict: local_file = local_file_dict[server_file_key] if server_file["force_delete_flg"]: files_to_delete.append(local_file["abs_path"]) else: local_file["hash"] = get_file_hash(local_file["abs_path"]) if server_file["check_hash_flg"] and local_file["hash"] == server_file["hash"]: continue download_url = urllib.parse.urljoin(server_url, server_file["path"]) + files_param download_path = game_path.replace("\\", "/") + server_file_key files_to_download.append({"url":download_url, "path":download_path}) else: download_url = urllib.parse.urljoin(server_url, server_file["path"]) + files_param download_path = game_path.replace("\\", "/") + server_file_key files_to_download.append({"url":download_url, "path":download_path}) print("Files to download:", len(files_to_download)) count = len(files_to_download) if count > 0: index = 0 max_len = 0 def show(j, downloaded, total_size): nonlocal max_len x = int(40*j/count) string = "Downloading: [{}{}] {}/{} ({}/{})".format("#"*x, "."*(40-x), j, count, min(downloaded,total_size), total_size) max_len = max(len(string), max_len) print(string.ljust(max_len, ' '), end='\r', file=sys.stdout, flush=True) retries = 3 show(0, 0, 0) while index < len(files_to_download): try: file = files_to_download[index] url, path = file["url"], file["path"] response = requests.get(url, timeout=10, stream=True) total_size = int(response.headers.get("content-length", 0)) block_size = 1024 * 1024 downloaded = 0 os.makedirs(os.path.dirname(path), exist_ok=True) with open(path, 'wb') as out_file: for data in response.iter_content(block_size): out_file.write(data) downloaded += len(data) show(index + 1, downloaded, total_size) index += 1 retries = 3 except Exception as e: print(e, "retrying") retries -= 1 if retries == 0: print(f'Retry for file {file["url"]} failed 3 times') return False print("\n", flush=True, file=sys.stdout) # #files_to_delete is unused until fully tested # for file in files_to_delete: # os.remove(file) return True