From 7dde7f8459c95680c38b48f80c17b492985b64b0 Mon Sep 17 00:00:00 2001 From: Eddy Hintze Date: Mon, 20 Jan 2020 10:26:48 -0500 Subject: [PATCH] Fixed #5 & Fixed #9. Added --keys support for downloading a single bundle --- CHANGELOG.md | 7 ++++ README.md | 3 +- humblebundle_downloader/_version.py | 2 +- humblebundle_downloader/cli.py | 7 ++++ humblebundle_downloader/download_library.py | 42 ++++++++++++--------- 5 files changed, 41 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aaadd31..f895de7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Change log + +### 0.1.0 +- Filename saved is now the original name of the file +- key used in cache is different due to changing the file name (this may result in duplicate downloads if you have run the older version) +- Support for downloading a single Bundle/Purchase by using the flag `-k` or `--key` and getting the key from the url of a purchase + + ### 0.0.8 - gen-cookies now works with SSO feature and 2FA logins - Added `--include` & `--exclude` cli args to filter file types diff --git a/README.md b/README.md index deb4a9a..b78dd8d 100644 --- a/README.md +++ b/README.md @@ -44,10 +44,11 @@ Use the following command to download your Humble Bundle Library: `hbd download --cookie-file hbd-cookies.txt --library-path "Downloaded Library" --progress` This directory structure will be used: -`Downloaded Library/Bundle Name/Bundle Item.ext` +`Downloaded Library/Purchase Name/Item Name/downloaded_file.ext` ## Notes * Inside your library folder a file named `.cache.json` is saved and keeps track of the files that have been downloaded. This way running the download command again pointing to the same directory will only download new or updated files. * Use `--help` with all `hbd` commands to see available options * Find supported platforms for the `--platform` flag by visiting your Humble Bundle Library and look under the **Platform** dropdown +* Download select bundles by using the `-k` or `--keys` flag. Find these keys by going to your *Purchases* section, click on a products and there should be a `downloads?key=XXXX` in the url. diff --git a/humblebundle_downloader/_version.py b/humblebundle_downloader/_version.py index 9123cf0..b794fd4 100644 --- a/humblebundle_downloader/_version.py +++ b/humblebundle_downloader/_version.py @@ -1 +1 @@ -__version__ = '0.0.8' +__version__ = '0.1.0' diff --git a/humblebundle_downloader/cli.py b/humblebundle_downloader/cli.py index da63ed8..16f5bc9 100644 --- a/humblebundle_downloader/cli.py +++ b/humblebundle_downloader/cli.py @@ -71,6 +71,12 @@ def cli(): type=str, nargs='*', help="Only download files with these extensions. Ex: -i pdf mobi", ) + parser_download.add_argument( + '-k', '--keys', + type=str, nargs='*', + help=("The purchase download key. Find in the url on the " + "products/bundle download page. Can set multiple"), + ) cli_args = parser.parse_args() @@ -87,4 +93,5 @@ def cli(): ext_include=cli_args.include, ext_exclude=cli_args.exclude, platform_include=cli_args.platform, + purchase_keys=cli_args.keys, ) diff --git a/humblebundle_downloader/download_library.py b/humblebundle_downloader/download_library.py index c15a44a..eaa05b9 100644 --- a/humblebundle_downloader/download_library.py +++ b/humblebundle_downloader/download_library.py @@ -18,7 +18,8 @@ def _clean_name(dirty_str): def download_library(cookie_path, library_path, progress_bar=False, - ext_include=None, ext_exclude=None, platform_include=None): + ext_include=None, ext_exclude=None, platform_include=None, + purchase_keys=None): if ext_include is None: ext_include = [] ext_include = list(map(str.lower, ext_include)) @@ -44,14 +45,16 @@ def download_library(cookie_path, library_path, progress_bar=False, except FileNotFoundError: cache_data = {} - library_r = requests.get('https://www.humblebundle.com/home/library', - headers={'cookie': account_cookies}) - logger.debug("Library request: " + str(library_r)) - library_page = parsel.Selector(text=library_r.text) - orders_json = json.loads(library_page.css('#user-home-json-data') - .xpath('string()').extract_first()) + if not purchase_keys: + library_r = requests.get('https://www.humblebundle.com/home/library', + headers={'cookie': account_cookies}) + logger.debug("Library request: " + str(library_r)) + library_page = parsel.Selector(text=library_r.text) + orders_json = json.loads(library_page.css('#user-home-json-data') + .xpath('string()').extract_first()) + purchase_keys = orders_json['gamekeys'] - for order_id in orders_json['gamekeys']: + for order_id in purchase_keys: order_url = 'https://www.humblebundle.com/api/v1/order/{order_id}?all_tpkds=true'.format(order_id=order_id) # noqa: E501 order_r = requests.get(order_url, headers={'cookie': account_cookies}) @@ -88,15 +91,16 @@ def download_library(cookie_path, library_path, progress_bar=False, + "/" + item_title) continue - ext = url.split('?')[0].split('.')[-1] - file_title = item_title + "." + ext + url_filename = url.split('?')[0].split('/')[-1] + cache_file_key = order_id + ':' + url_filename + ext = url_filename.split('.')[-1] # Only get the file types we care about if ((ext_include and ext.lower() not in ext_include) or (ext_exclude and ext.lower() in ext_exclude)): - logger.info("Skipping the file " + file_title) + logger.info("Skipping the file " + url_filename) continue - filename = os.path.join(item_folder, file_title) + filename = os.path.join(item_folder, url_filename) item_r = requests.get(url, stream=True) logger.debug("Item request: {item_r}, Url: {url}" .format(item_r=item_r, url=url)) @@ -108,10 +112,11 @@ def download_library(cookie_path, library_path, progress_bar=False, 'url_etag': item_r.headers['ETag'][1:-1], 'url_crc': item_r.headers['X-HW-Cache-CRC'], } - if file_info != cache_data.get(filename, {}): + if file_info != cache_data.get(cache_file_key, {}): if not progress_bar: - logger.info("Downloading: {file_title}" - .format(file_title=file_title)) + logger.info("Downloading: {item_title}/{url_filename}" + .format(item_title=item_title, + url_filename=url_filename)) with open(filename, 'wb') as outfile: total_length = item_r.headers.get('content-length') @@ -126,8 +131,9 @@ def download_library(cookie_path, library_path, progress_bar=False, pb_width = 50 done = int(pb_width * dl / total_length) if progress_bar: - print("Downloading: {file_title}: {percent}% [{filler}{space}]" # noqa E501 - .format(file_title=file_title, + print("Downloading: {item_title}/{url_filename}: {percent}% [{filler}{space}]" # noqa E501 + .format(item_title=item_title, + url_filename=url_filename, percent=int(done * (100 / pb_width)), # noqa E501 filler='=' * done, space=' ' * (pb_width - done), # noqa E501 @@ -138,7 +144,7 @@ def download_library(cookie_path, library_path, progress_bar=False, # is on its own line print() - cache_data[filename] = file_info + cache_data[cache_file_key] = file_info # Update cache file with newest data so if the script # quits it can keep track of the progress with open(cache_file, 'w') as outfile: