diff --git a/Readme.md b/Readme.md index 68e711f..7d31503 100644 --- a/Readme.md +++ b/Readme.md @@ -37,8 +37,24 @@ itch-download -vf # skips downloads above a certain size in megabytes, supports decimals itch-download -sas 50.0 -# verifies downloads and creates an additional .md5 file for each download -itch-download -v +# Disables file verification entirely, files with the same name are assumed to be the same file +itch-download --no-verify + +# Disables writing supplementary .md5 files, existing files will still be hashed against their download hashes +# Does nothing if --no-verify is specified +itch-download --no-verify-file + +# Downloads all free titles from the specified publisher +# Argument should be formatted 'https://{publisher}.itch.io' +itch-download --download-publisher + +# Checks if title is owned, then downloads all files for it +# Argument should be formatted 'https://{publisher}.itch.io/{title}/' +itch-download --download-game + +# For the --download-game argument, skips the check to see if the title is currently owned +# In practice this free files only +itch-download --skip-library-load ``` ## Add All Games in a bundle to your library diff --git a/itchiodl/downloader/__main__.py b/itchiodl/downloader/__main__.py index 34668d1..b278628 100644 --- a/itchiodl/downloader/__main__.py +++ b/itchiodl/downloader/__main__.py @@ -29,12 +29,21 @@ def main(): ) parser.add_argument( - "--verify", + "--no-verify", type=bool, default=False, const=True, nargs='?', - help="Verifies each file downloaded and produces a supplementary checksum file" + help="Disables file verification entirely, files with the same name are assumed to be the same file" + ) + + parser.add_argument( + "--no-verify-file", + type=bool, + default=False, + const=True, + nargs='?', + help="Disables writing md5 hashes to a supplementary file, does nothing if --no-verify is specified" ) parser.add_argument( @@ -62,7 +71,16 @@ def main(): parser.add_argument( "--download-game", type=str, - help="Download a specific game, should be in the format publisher.itch.io/game", + help="Download a specific game, should be in the format 'https://%publisher%.itch.io/%game-title%'", + ) + + parser.add_argument( + "--skip-library-load", + type=bool, + default=False, + const=True, + nargs='?', + help="For the --download-game argument only, skips caching and checking the user library for an existing key" ) args = parser.parse_args() @@ -81,18 +99,20 @@ def main(): if args.download_publisher: lib.load_games(args.download_publisher) elif args.download_game: - lib.load_owned_games() - for game in lib.games: - if game.link == args.download_game: - lib.games = [game] - break - if len(lib) > 1: - print("Game Is Not In Library, Checking for Free Downloads") - lib.games = [] + if not args.skip_library_load: + lib.load_owned_games() + for game in lib.games: + if game.link == args.download_game: + lib.games = [game] + break + if len(lib) > 1: + print("Game Is Not In Library, Checking for Free Downloads") + lib.games = [] + matches = re.match(r"https://(.+)\.itch\.io/(.+)", args.download_game) + lib.load_game(matches.group(1), matches.group(2)) + else: matches = re.match(r"https://(.+)\.itch\.io/(.+)", args.download_game) lib.load_game(matches.group(1), matches.group(2)) - - else: lib.load_owned_games() diff --git a/itchiodl/game.py b/itchiodl/game.py index 6485f46..81e50ef 100644 --- a/itchiodl/game.py +++ b/itchiodl/game.py @@ -15,26 +15,37 @@ class Game: """Representation of a game download""" def __init__(self, data): + self.id = False + self.game_id = None self.args = sys.argv[1:] if '-vf' or '--verbose-folders' in self.args: self.verbose = True else: self.verbose = False - if '--verify' in self.args: - self.verify = True + + if '--no-verify-file' in self.args: + self.verify_file = False else: + self.verify_file = True + + if '--no-verify ' in self.args: self.verify = False + else: + self.verify = True + if '-sas' in self.args: self.skipping_large_entries = True self.skipping_above_size_MB = float(self.args[(self.args.index('-sas')+1)]) - self.skipping_above_size_B = self.skipping_above_size_MB * 1000000 + self.skipping_above_size_B = abs(self.skipping_above_size_MB * 1000000) elif '--skip-above-size' in self.args: self.skipping_large_entries = True self.skipping_above_size_MB = float(self.args[(self.args.index('--skip-above-size')+1)]) - self.skipping_above_size_B = self.skipping_above_size_MB * 1000000 + self.skipping_above_size_B = abs(self.skipping_above_size_MB * 1000000) else: self.skipping_above_size = False + self.data = data["game"] + if self.verbose: self.name = itchiodl.utils.clean_path(self.data["title"]) self.publisher = self.data.get("user").get("display_name") @@ -70,15 +81,12 @@ class Game: ) j = r.json() for d in j["uploads"]: - try: - if not self.skipping_large_entries: - self.downloads.append(d) - elif self.skipping_above_size_B > d.get("size"): - self.downloads.append(d) - else: - print("!Skipping Large Item!") - except: - print("There was an Error") + if not self.skipping_large_entries: + self.downloads.append(d) + elif self.skipping_above_size_B > d.get("size"): + self.downloads.append(d) + else: + print(f"Skipping Large Item: {d.get('filename')}") def download(self, token, platform): """Download a singular file""" @@ -114,48 +122,42 @@ class Game: def do_download(self, d, token): """Download a single file, checking for existing files""" - print(f"Downloading {d['filename']}") + print(f"Downloading `{d['filename']}`") file = itchiodl.utils.clean_path(d["filename"] or d["display_name"] or d["id"]) path = self.destination_path - if os.path.exists(f"{path}/{file}"): - print(f"File Already Exists! {file}") if self.verify: + print(f"! `{file}` Already Exists!") 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}") + print(f"MD5 Hash Matches {self.name} - `{file}`, Skipping") return print(f"MD5 Mismatch! {file}") - else: md5 = itchiodl.utils.md5sum(f"{path}/{file}") if md5 == d["md5_hash"]: - print(f"Skipping {self.name} - {file}") - + print(f"MD5 Matches {self.name} - `{file}`, Skipping") # Create checksum file - with open(f"{path}/{file}.md5", "w") as f: - f.write(d["md5_hash"]) + if self.verify_file: + with open(f"{path}/{file}.md5", "w") as f: + f.write(d["md5_hash"]) return # 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}") + 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}") else: - print(f"Skipping {self.name} - {file}") - return + print(f"File Already Exists! Skipping") # Get UUID r = requests.post( @@ -217,6 +219,7 @@ class Game: 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"]) + # Create checksum file + if self.verify_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 1bd307c..f700730 100644 --- a/itchiodl/utils.py +++ b/itchiodl/utils.py @@ -1,8 +1,6 @@ import re -import sys import hashlib import requests -import os class NoDownloadError(Exception):