diff --git a/itchiodl/game.py b/itchiodl/game.py index e0805c5..54206ad 100644 --- a/itchiodl/game.py +++ b/itchiodl/game.py @@ -3,6 +3,8 @@ import requests import json import os import urllib +import datetime +import shutil import itchiodl.utils @@ -35,9 +37,11 @@ class Game: self.downloads.append(d) def download(self, token, platform): - if os.path.exists(f"{self.publisher_slug}/{self.game_slug}.json"): - print(f"Skipping Game {self.name}") - return + print("Downloading", self.name) + + # if os.path.exists(f"{self.publisher_slug}/{self.game_slug}.json"): + # print(f"Skipping Game {self.name}") + # return self.load_downloads(token) @@ -51,31 +55,79 @@ class Game: if platform is not None and d["traits"] and f"p_{platform}" not in d["traits"]: print(f"Skipping {self.name} for platform {d['traits']}") continue + self.do_download(d, token) - file = itchiodl.utils.clean_path( - d['filename'] or d['display_name'] or d['id']) - path = f"{self.publisher_slug}/{self.game_slug}" - if os.path.exists(f"{path}/{file}"): - print(f"Skipping {path}/{file}") - continue + with open(f"{self.publisher_slug}/{self.game_slug}.json", "w") as f: + json.dump({ + "name": self.name, + "dl_version": 2, + "publisher": self.publisher, + "link": self.link, + "itch_id": self.id, + "game_id": self.game_id, + "itch_data": self.data, + }, f) - # Get UUID - r = requests.post( - f"https://api.itch.io/games/{self.game_id}/download-sessions", - headers={ - "Authorization": token}) - j = r.json() + def do_download(self, d, token): + print(f"Downloading {d['filename']}") - # Download - url = f"https://api.itch.io/uploads/{d['id']}/download?api_key={token}&download_key_id={self.id}&uuid={j['uuid']}" - # response_code = urllib.request.urlopen(url).getcode() - try: - itchiodl.utils.download(url, path, self.name, file) - except itchiodl.utils.NoDownloadError as e: - print("Http response is not a download, skipping") + file = itchiodl.utils.clean_path( + d['filename'] or d['display_name'] or d['id']) + path = itchiodl.utils.clean_path( + f"{self.publisher_slug}/{self.game_slug}") - with open('errors.txt', 'a') as f: - f.write(f""" Cannot download game/asset: {self.game_slug} + if os.path.exists(f"{path}/{file}"): + print(f"File Already Exists! {file}") + if os.path.exists(f"{path}/{file}.md5"): + + with open(f"{path}/{file}.md5", "r") as f: + md5 = f.read().strip() + + if md5 == d["md5_hash"]: + print(f"Skipping {self.name} - {file}") + return + else: + print(f"MD5 Mismatch! {file}") + else: + md5 = itchiodl.utils.md5sum(f"{path}/{file}") + if md5 == d["md5_hash"]: + print(f"Skipping {self.name} - {file}") + + # Create checksum file + with open(f"{path}/{file}.md5", "w") as f: + f.write(d["md5_hash"]) + return + else: # Old Download or corrupted file? + corrupted = False + if corrupted: + os.remove(f"{path}/{file}") + return + + if not os.path.exists(f"{path}/old"): + os.mkdir(f"{path}/old") + + print(f"Moving {file} to old/") + timestamp = datetime.datetime.now().strftime('%Y-%m-%d') + print(timestamp) + shutil.move(f"{path}/{file}", f"{path}/old/{timestamp}-{file}") + + # Get UUID + r = requests.post( + f"https://api.itch.io/games/{self.game_id}/download-sessions", + headers={ + "Authorization": token}) + j = r.json() + + # Download + url = f"https://api.itch.io/uploads/{d['id']}/download?api_key={token}&download_key_id={self.id}&uuid={j['uuid']}" + # response_code = urllib.request.urlopen(url).getcode() + try: + itchiodl.utils.download(url, path, self.name, file) + except itchiodl.utils.NoDownloadError as e: + print("Http response is not a download, skipping") + + with open('errors.txt', 'a') as f: + f.write(f""" Cannot download game/asset: {self.game_slug} Publisher Name: {self.publisher_slug} Path: {path} File: {file} @@ -84,12 +136,12 @@ class Game: This game/asset has been skipped please download manually ---------------------------------------------------------\n """) - continue - except urllib.error.HTTPError as e: - print("This one has broken due to an HTTP error!!") + return + except urllib.error.HTTPError as e: + print("This one has broken due to an HTTP error!!") - with open('errors.txt', 'a') as f: - f.write(f""" Cannot download game/asset: {self.game_slug} + with open('errors.txt', 'a') as f: + f.write(f""" Cannot download game/asset: {self.game_slug} Publisher Name: {self.publisher_slug} Path: {path} File: {file} @@ -99,14 +151,13 @@ class Game: This game/asset has been skipped please download manually ---------------------------------------------------------\n """) - continue + return - with open(f"{self.publisher_slug}/{self.game_slug}.json", "w") as f: - json.dump({ - "name": self.name, - "publisher": self.publisher, - "link": self.link, - "itch_id": self.id, - "game_id": self.game_id, - "itch_data": self.data, - }, f) + # Verify + if itchiodl.utils.md5sum(f"{path}/{file}") != d["md5_hash"]: + print(f"Failed to verify {file}") + return + + # Create checksum file + with open(f"{path}/{file}.md5", "w") as f: + f.write(d["md5_hash"]) diff --git a/itchiodl/utils.py b/itchiodl/utils.py index 1afd543..1918648 100644 --- a/itchiodl/utils.py +++ b/itchiodl/utils.py @@ -2,6 +2,7 @@ import requests import re import os import sys +import hashlib from clint.textui import progress @@ -54,3 +55,12 @@ def clean_path(path): path_clean = re.replace(r'[\<\>\:\"\/\\\|\?\*]', "-", path) return path_clean return path + + +def md5sum(path): + """Returns the md5sum of a file""" + md5 = hashlib.md5() + with open(path, "rb") as f: + for chunk in iter(lambda: f.read(4096), b""): + md5.update(chunk) + return md5.hexdigest() diff --git a/upgrade_tree.sh b/upgrade_tree.sh new file mode 100755 index 0000000..5610dfa --- /dev/null +++ b/upgrade_tree.sh @@ -0,0 +1,5 @@ +#! /bin/sh + +find $1 -maxdepth 3 -mindepth 3 -type f -print0 | while IFS= read -r -d '' f; do + md5sum "$f" | cut -d ' ' -f 1 >> "$f.md5"; +done \ No newline at end of file