| | |
| | | import audible |
| | | import json |
| | | import time |
| | | import os |
| | | from audible.aescipher import decrypt_voucher_from_licenserequest |
| | | from audible.activation_bytes import ( |
| | | extract_activation_bytes, |
| | |
| | | _metadata = {} |
| | | |
| | | |
| | | def get_auth_files(): |
| | | ''' |
| | | Gets the auth files for audible and activation bytes |
| | | |
| | | Returns: |
| | | audible auth, activation bytes |
| | | ''' |
| | | |
| | | with open('./audible_auth_', 'r') as f: |
| | | auth_data = json.load(f) |
| | | audible_auth = audible.Authenticator.from_dict(auth_data) |
| | | act_bytes = fetch_activation_sign_auth(auth=audible_auth) |
| | | act_bytes = extract_activation_bytes(act_bytes) |
| | | return audible_auth, act_bytes |
| | | |
| | | |
| | | def get_args(): |
| | | ''' |
| | | Parses the args for runtime |
| | |
| | | Ret: |
| | | str: The url to download the file from |
| | | ''' |
| | | # print(licenserequest) |
| | | if 'Denied' in licenserequest{'content_license']['status'}: |
| | | raise Exception("License request was denied. For ") |
| | | return licenserequest['content_license']['content_metadata'][ |
| | | 'content_url']['offline_url'] |
| | | |
| | |
| | | f.write(dl.content) |
| | | |
| | | |
| | | def download_books(asin: str) -> None: |
| | | def download_book(asin: str) -> None: |
| | | ''' |
| | | Download the book and hand it off to the converter |
| | | |
| | |
| | | asin (str): The amazon number of the book being downloaded |
| | | ''' |
| | | lr = get_license_request(asin) |
| | | print(ab) |
| | | get_content(asin, get_content_url(lr)) |
| | | # see if we already downloaded the file |
| | | if os.path.exists(f"/tmp/{asin}.aax"): |
| | | print(f"{asin} already downloaded, skipping download.") |
| | | else: |
| | | get_content(asin, get_content_url(lr)) |
| | | decrypted_voucher = decrypt_voucher_from_licenserequest(_audible_auth, lr) |
| | | key_iv = { |
| | | 'key': decrypted_voucher['key'], |
| | |
| | | aaxConvert.convert_aax(f"/tmp/{asin}.aax", _actbytes, key_iv) |
| | | |
| | | |
| | | def list_missing_books(): |
| | | audible_books = get_audible_books() |
| | | missing_books = [] |
| | | library_ids = get_library_ids() |
| | | for id in library_ids: |
| | | bookshelf_books = get_bookshelf_books(id) |
| | | for book in audible_books: |
| | | if book['content_type'] == 'Product': |
| | | search = search_local_books(book, bookshelf_books) |
| | | if search: |
| | | missing_books.append(f"{book['title']}: {book['asin']}") |
| | | return missing_books |
| | | |
| | | |
| | | def main(): |
| | | args = get_args() |
| | | asin_manual = args.asin |
| | | audible_books = get_audible_books() |
| | | if asin_manual is not None: |
| | | download_books(asin_manual) |
| | | download_book(asin_manual) |
| | | else: |
| | | library_ids = get_library_ids() |
| | | for id in library_ids: |
| | | bookshelf_books = get_bookshelf_books(id) |
| | | for book in audible_books: |
| | | if book['content_type'] == 'Product': |
| | | search = search_local_books(book, bookshelf_books) |
| | | if search: |
| | | print(f"{book['title']}, {book['asin']}") |
| | | download_books(book['asin']) |
| | | time.sleep(20) |
| | | missing_books = list_missing_books() |
| | | print(missing_books) |
| | | answer = input("Would you like to download the missing books? (y/n)\n") |
| | | if answer.lower() == 'y': |
| | | for book in missing_books: |
| | | download_book(book.split(": ")[1]) |
| | | time.sleep(20) |
| | | |
| | | |
| | | if __name__ == "__main__": |