Git Product home page Git Product logo

audible's People

Contributors

bottydim avatar coffmantaylor avatar davidedpg10 avatar dependabot-preview[bot] avatar dependabot[bot] avatar djdembeck avatar g0ierli avatar humni avatar jsowder avatar mbucari avatar mkb79 avatar nodejsmith avatar oczkoisse avatar rmcrackan avatar seidnerj avatar snowskeleton avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

audible's Issues

Here's the steps I completed.

pip install audible

created a test.py file.

import audible

# for US accounts
client = audible.Client("myemail", "mypassword", local="us")

# specify a api_version on request
# default is api_version="1.0"
# get deprecated version of library
library = client.get("library/books", api_version="0.0", purchaseAfterDate="01/01/1970", sortInAscendingOrder="true")

print(library)

executed that file. with python3.6

python3.6 test.py

the results I got back are.

Answer for CAPTCHA: audible-api: unable to open X server `' @ error/display.c/DisplayImageCommand/410.

I realize I need to register, however I have no idea how to go about doing that. Is there any sample code on how to go about doing that?

How does the BestSellers sort_by option in the APIs work?

Having a hard time understanding how does the BestSellers option in products_sort_by parameter works, for instance in /1.0/catalog/products endpoint. I'm trying to make API calls about the products on audible and sort them by best sellers, yet I'm getting random items in response that are definitely not sorted by best sellers:

client.get("/1.0/catalog/products", num_results=50, page=0, response_groups=['product_attrs'], products_sort_by=['BestSellers'])

Am I doing this wrong or is audible just ignoring the parameter?

Add Audible Marketplace Audible.es Spain

Is your feature request related to a problem? Please describe.
Audible.es | Spain is a new Audible Marketplace. See Audible Help
It is yet not included in the localization.

Describe the solution you'd like
Add
"spain": { "country_code": "es", "domain": "es", "market_place_id": "" },

Captcha Login Fails 'KeyError'

using:
audible 0.6.0
Python 3.10

When trying to login using captcha method, login fails due to an exception 'KeyError'.

I am using a captcha call back but the guess seems to be coming back correctly on ln 376.

In line 388 of login.py ( last line in the section below ) it calls the 'get_next_action_from_soup'

     while check_for_captcha(login_soup):
     ...
     
        inputs = get_inputs_from_soup(login_soup)
        inputs["guess"] = guess
        inputs["use_image_captcha"] = "true"
        inputs["use_audio_captcha"] = "false"
        inputs["showPasswordChecked"] = "false"
        inputs["email"] = username
        inputs["password"] = password

        method, url = get_next_action_from_soup(login_soup)

inside that method it gets an exception on line 126

method = form["method"]

KeyError: method

The form variable contains the following
(<)form action="get" name="ue_backdetect"(>)<input name="ue_back" type="hidden" value="1"/></form>

Replace (<) with < above

I have used the captcha on many occasions in the past with success until now.

Help with search api

hi, do you have scraped some info about the api endpoint for searching the marketplace?
I'm not getting the audible app to work with mitmproxy.

response_callback no longer works properly with the endpoint: https://cde-ta-g7g.amazon.com/FionaCDEServiceEngine/sidecar

Describe the bug
Using the https://cde-ta-g7g.amazon.com/FionaCDEServiceEngine/sidecar worked previously with audible.Client and returned the correct response. Now it returns None. In client.py Client._request() the resp object contains the correct response however the response_callback() function returns None with the resp object, hence this endpoint is unusable.

This is because
in default_response_callback resp.next_request returns None for this endpoint

To Reproduce

auth = audible.Authenticator.from_file("credentials.json")
def get_bookmarks(url, **kwargs):
    with audible.Client(auth=auth) as client:
        library = client.get(
            url,
            **kwargs
        )
        return library

Expected behavior
Returns the clips, notes and bookmarks of a book

Desktop (please complete the following information):
audible==0.8.2
Python 3.10.1

TEST: New device registration method

Need help from users for another method to register a new Audible dummy device!

Please tell me if the code below let you register a new device or if you get any error message!

Expose New Approval Alerting Callback

Great project! Thanks so much for all the hard work. :)

I recently ran into the issue of approval alerting (that amazon recently added) and it was already fixed! Wow.

I wanted to see if you could expose the alert callback similar to OTP, CVF, etc.? That would be much appreciated, thanks!

Can't filter plus catalog books from 'catalog/products'

Hello there,
I started working with this repo a few hours ago because I do like the idea of archiving audiobooks.

This is a plus catalog audiobook so anyone with the subscription can help me with it.
ASIN - 1665074620
Title - What Addicts Know
I am using Google Colab for this as I like to try new things there and then implement the rest on my server.

I have a few questions about the usage but before that, I want to know how to download the audiobooks. I don't care about the format (.aax or .aacx) because I can decode either. Which link do I download?
The following is my code to get the download URL:

body = {
    "supported_drm_types" : [
        "Mpeg",
        "Adrm"
    ],
    "quality" : "High",
    "consumption_type" : "Download"
}
token = client.post("1.0/content/1665074620/licenserequest", body)
print(json.dumps(token, indent=3, sort_keys=True))

OUTPUT:

{
   "content_license": {
      "access_expiry_date": "2024-12-31T12:00:00Z",
      "acr": "CXXXXXX",
      "allowed_users": [
         "amzn1.account.XXXXXXXXXXXXXXXXXXXXXXXXX"
      ],
      "asin": "1665074620",
      "content_metadata": {
         "content_url": {
            "offline_url": "https://dze5l2jxnquy5.cloudfront.net/bk_blak_016548it/28335321/aax/XXXX....XXXX"
         }
      },
      "drm_type": "Adrm",
      "license_id": "XXXXXXXXXXXXXXXXXXXXXXXX",
      "license_response": "y/XXXXXX.....XXXXX",
      "message": "Customer [XXXXXXXXXXXXXXX] has rights to asin [1665074620] for AYCL",
      "refresh_date": "2022-03-18T06:28:07Z",
      "removal_date": "2022-04-27T06:28:07Z",
      "request_id": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
      "requires_ad_supported_playback": false,
      "status_code": "Granted",
      "voucher_id": "cdn:XXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
   },
   "response_groups": [
      "always-returned"
   ]
}

### When I click the offline_url, I get this following error:

Screenshot 2022-02-26 at 1 27 22 AM 2

##

At first I thought that my macBook and the Colab instance have different IP Addresses and thats why I can't download it. Then I tried downloading it directly on the colab instance but it still wouldn't download.

I don't understand what I am doing wrong here. I read the closed thread for downloading files but the first post is from back in 2019 and it doesn't work.

The other question I have is about only getting the Audible Plus Catalog. I see the plan for it is named "Audible-AYCL" which is not included in plans[]. I created a function for this and I got around it but it would be nice if it was updated.

### My whole code:

!mkdir /content/audible
import audible, urllib, cv2, json
from google.colab.patches import cv2_imshow (I am running this in google colab)

DIR_PATH = "/content/audible"

email = "xx"
pasword = "xx"
country = "xx"

def cb(captcha_url):
    
    urllib.request.urlretrieve(captcha_url, "/content/audible/captcha.jpg")
    image = cv2.imread('/content/audible/captcha.jpg')
    cv2_imshow(image)
    print(captcha_url)
    answer = input("Answer for CAPTCHA: ")
    answer = str(answer).strip().lower()
    return answer
    !rm /content/captcha.jpg

auth = audible.Authenticator.from_login(
    email,
    pasword,
    locale = country,
    with_username=False,
    captcha_callback=cb
)
auth.to_file(DIR_PATH+country)

auth = audible.Authenticator.from_file(DIR_PATH+country)
client = audible.Client(auth)

body = {
    "supported_drm_types" : [
        "Mpeg",
        "Adrm"
    ],
    "quality" : "High",
    "consumption_type" : "Download"
}
token = client.post("1.0/content/1665074620/licenserequest", body)

print(json.dumps(token, indent=3, sort_keys=True))

Looking forward to solving this problem. Will update if I find something new.

What are all available "content_type" values?

Not really an issue but more like a question.

One of the fields returned when querying my book library is the "content_type".

I would like to find out what are all the potential values associated with that field.
Based on the content of my own library I see these:

Episode                1
Lecture               15
Newspaper / Magazine   2
Performance           12
Product              601
Radio/TV Program       5
Show                   1
Speech                 6

Do you have such a list or a way to find such a list?

Thanks!

Building an external login URL

I am building an endpoint that will just return the login URL returned from build_oauth_url

Heres the code:

def get_auth_link():
    code_verifier = audible.login.create_code_verifier()

    oauth_url = audible.login.build_oauth_url(
        country_code=COUNTRY_CODE,
        domain=DOMAIN,
        market_place_id=MARKETPLACE_ID,
        code_verifier=code_verifier,
        with_username=False
    )

    return oauth_url

When I use the link, sign in and get the address bar URL to use from_login_external I get this as a return exception:

Exception: {'response': {'error': {'code': 'InvalidValue', 'index': 'tGP0Ha5AGkt8rT5f6GvjpwAAAAAAAAABCoOqqcjUmA7AKfxjSct01Cg_pilnvd6EEVWx2HFy9kOVWSGENsmEtLsb4T6TZHp8zL_c87GaD91q9qFKypHaaxu34HHfFjfv5gRHpfla80sRtMspddIA8e63XKV7tPaiRy3JG-wkH8mu1UgOHYwpgnWjmeKY-gSC9oVhl0e86leJkMF25Lluxz-fBorjbap52nclsr9Ml6FmSkUKVLWdbQ==', 'message': 'One or more provided values are invalid.'}}, 'request_id': 'fcd9fbe1-2432-4af5-bfc1-6cf3d1e42ebb'}

I am using the callback on from_login_external to pass in the URL from my custom endpoint like so:

def audible_login(): 
    #{ id: str, url: str }
    params = request.json

    print(params['url'])

    def auth_link_url_callback(login_url: str):
        print(login_url)
        return params['url']

    auth = audible.Authenticator.from_login_external(COUNTRY_CODE, login_url_callback=auth_link_url_callback)

    auth.to_file(params['id'])

I am posting the URL and via a CURL command for testing:

curl -X POST -H "Content-Type: application/json" -d '{
  "url": "https://www.amazon.com.au/ap/maplanding?openid.assoc_handle=amzn_audible_ios_au&openid.claimed_id=https%3A%2F%2Fwww.amazon.com.au%2Fap%2Fid%2Famzn1.account.AHDJ2REEGR72DEJEMJDUBHMW4PUA&openid.identity=https%3A%2F%2Fwww.amazon.com.au%2Fap%2Fid%2Famzn1.account.AHDJ2REEGR72DEJEMJDUBHMW4PUA&openid.mode=id_res&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.op_endpoint=https%3A%2F%2Fwww.amazon.com.au%2Fap%2Fsignin&openid.response_nonce=2022-01-05T07%3A35%3A16Z-1504074421391324938&openid.return_to=https%3A%2F%2Fwww.amazon.com.au%2Fap%2Fmaplanding&openid.signed=assoc_handle%2Cclaimed_id%2Cidentity%2Cmode%2Cns%2Cop_endpoint%2Cresponse_nonce%2Creturn_to%2Cns.pape%2Cpape.auth_policies%2Cpape.auth_time%2Coa2.authorization_code%2Ccaptcha_verified%2Csigned&openid.ns.pape=http%3A%2F%2Fspecs.openid.net%2Fextensions%2Fpape%2F1.0&openid.pape.auth_policies=http%3A%2F%2Fschemas.openid.net%2Fpape%2Fpolicies%2F2007%2F06%2Fnone&openid.pape.auth_time=2022-01-05T07%3A35%3A16Z&openid.sig=kHOEjSvIPKmMI6r1FfL2SjC6fKeRFFkbwFbXkO6t1zs%3D&serial=&openid.oa2.authorization_code=SRCSCKBUVJDQKPfDDWMZAUSg&openid.ns.oa2=http%3A%2F%2Fwww.amazon.com%2Fap%2Fext%2Foauth%2F2&captcha_verified=1&",
  "id": "1"
}' http://localhost:5000/login_with_url

Am I building up the URL wrong? Any advice would be appreciated.

MyAudible project

I'm working on my new project MyAudible. I have no experience with Django. Everyone is welcome to help me building a good Django app!

Amazon uses Auth Code Flow with PKCE on latest iOS app

I found out today, that Amazon changed the "openid.oa2.response_type" from "token to "code". In result of this, a successfully authorization gives a "authorization_code" instead of a "access_token". In exchange for the authorization code a access token can be requested. But this requires a device registration.

Amazon still accepts "token" request for now. Maybe this can change in the future.

PyCrypto and Windows

Hi!

I was looking to use this package but when I tried to install it Windows throws an ugly error message caused by the pycrypto setup.py. Looking up how to resolve this issue wasn't very helpful as it seems that pycrypto is dead.

I'm sure I can find a workaround but I thought it might be worth making an issue as it's probably not great to be using a corpse of a library as a dependency. If there's not interest in it then fair enough and the issue can just be closed.

Thanks!

Getting "The server has encountered a runtime error" when authenticating

Hi mkb79,
Thanks for the Python library!

I was able to use an older version back in July but it started failing when I tried to use it again today.
So, I downloaded the new version (0.2.1 v 0.1.5), made the necessary code changes and I'm still getting the same error.

Here's an abbreviated version of the body of my request:
{'requested_token_type': ['bearer', 'mac_dms', 'website_cookies', 'store_authentication_cookie'], 'cookies': {'website_cookies': [], 'domain': '.amazon.com'}, 'registration_data': {'domain': 'Device', 'app_version': '3.7', 'device_serial': 'Y9UGDIF8OUUKCUF1CHV8M8YZDREDDFM0WOHGDRQV', 'device_type': 'A2CZJZGLK2JJVM', 'device_name': '%FIRST_NAME%%FIRST_NAME_POSSESSIVE_STRING%%DUPE_STRATEGY_1ST%Audible for iPhone', 'os_version': '12.3.1', 'device_model': 'iPhone', 'app_name': 'Audible'}, 'auth_data': {'access_token': 'Atna|EwICID7AOCk...'}, 'requested_extensions': ['device_info', 'customer_info']}

And the return json associated with the 500 HTTP error:
{'request_id': '1fbad2a3-978b-4319-8497-7099f6bc17b3', 'response': {'error': {'code': 'ServerError', 'index': 'xYLIwBnwW...==', 'message': 'The server has encountered a runtime error.'}}}

What am I doing wrong?
Is it a temporary server outage?

Thanks.

Test login

I‘ve created a new branch. It doesn’t show up a captcha request for 5 logins. But for now captchas seems to be appearing. Maybe I tried to often in very short time.

Can someone test the new branch and try to login (hopefully without a captcha)?!

encryptedPwd

New login page requires this parameter, it gets encrypted using aes128 gcm with jwk rsa. I didn't get the exact code to mimic the process. Can anybody help me to get the encryption part?

Quality is set to `Extreme` even set to `high`

Describe the bug
When i try to download high quality books it fails with:
error: Bad Request (400): 1 validation error detected: Value 'Extreme' at 'quality' failed to satisfy constraint: Member must satisfy enum value set: [High, Normal]

if i set the quality to normal it works. Further, the --ignore-errors is ignored

To Reproduce
Steps to reproduce the behavior:
run audible download --all --aaxc --cover --cover-size 1215 --chapter -y -q high --ignore-errors

Expected behavior
Download the audiobooks

Desktop (please complete the following information):

  • OS: Ubuntu 20.04
  • Version: audible-cli, version 0.2.0

is_valid_email have bug,Pls check it

Describe the bug
If your email address has “-”,It will not be allowed to pass the is_valid_email inspection!
For example:[email protected] it no work!

login.py 222 line
def is_valid_email(obj: str) -> bool:
valid_mail = r"^[a-z0-9]+[._]?[a-z0-9]+[@]\w+[.]\w+$"
if re.match(valid_mail, obj):
return True
return False

It should be changed to:^\w+([-+.]\w+)@\w+([-.]\w+).\w+([-.]\w+)*$

PDF URL

I'm trying to use the pdf_url value from the GET /1.0/library/%{asin} endpoint. It worked before, but currently the value is a cloudfront.net URL. However, the URL is missing the Key-Pair-Id and Policy query parameters, so using the URL results in an error message. Do you know how to get a working URL with these parameters?

Unable to install

I can not install this program as it relies on pycrypto, which is bugged the hell out when ever I try to install it. The issue with pycrypto is well know, and, aparrently, pycrypto has been depricated.

Whispersync for voice?

Hi!

Thanks a lot for the hard work on this!
I also am a big fan of Audible and Kindle.
I tend to buy the Kindle and Audible versions of the same book.

Although, whispersync for voice is not available in my country.
However, the books I buy definitely support Whispersync for voice.

I'm looking for a homemade way to synchronize my Kindle and Audible books.
Would your API be of any help to achieve my goal?

Thanks for your help!

is_finished = None for all titles in library

I am trying to get the "finished" status of all titles in my library. I'm able to log in successfully and retrieve the titles, but the "is_finished" attribute is always set to None. Here is the code snippet I'm using:

auth = audible.FileAuthenticator("audible.save")
print(auth.adp_token)
client = audible.AudibleAPI(auth)
library, _ = client.get("library")

for book in library["items"]:
    print(book['is_finished'])

I'm guessing this is more a problem with the API returning that value but the mobile app must be retrieving it somehow.

Only getting part of the CAPTCHA image

Intead of a typical CAPTCHA image that looks like this:
image
I'm now getting a partial image like this:
image

I haven't change anything to my code. The only difference is that I've upgraded to a Mac Mini M1 (vs an old Mac Mini 2012) which came with Bigsur (vs Catalina).
My old Mac is no longer available for me to test. :-(

"product_page_url" is always None

Hi
I can't seem to get the "product_page_url" out of the request?
I am not sure witch response_group I need to use for this but I am using the following request and not getting anything but "None"

    with audible.Client(auth=auth_US) as client:
        library = client.get(
            "1.0/library",
            num_results=1000,
            response_groups="contributors, media, product_attrs, product_desc, product_extended_attrs, product_plan_details, product_plans, rating, series, origin, relationships, categories, badge_types, category_ladders, is_downloaded, is_finished, is_removable, is_returnable, is_visible, order_details, pdf_url, percent_complete",
            #"contributors,product_desc, product_attrs, media, is_finished, product_extended_attrs, is_playable, is_removable, is_returnable, pdf_url, percent_complete",
            sort_by="-PurchaseDate"
        )

Any help would be amazing thanks.

When downloading AAXC 403 Forbidden

When using the example code to download an AAXC from my library I am now receiving 403 Forbidden response codes. This worked fine before, but has just started this month. I'm able to authenticate, and pull down a fresh library list.

To Reproduce
Steps to reproduce the behavior:

  1. Use the example code from download_books_aaxc.py on line 38.

with httpx.stream("GET", url) as r:

  1. The response comes back as a 403.

Relevant Dependencies:
httpx v0.16.1
audible v0.5.4 (this library)

I have made no changes in the last few months, and it has worked fine until now. Last known working was late April 2021. But after trying it in the last couple days (with no changes) I now get a 403 forbidden. Can't seem to figure out what is different or the reason for the 403. Audible API change?

However, if I take the URL that it's attempting to use it will work just fine in the browser (not logged in and all history/cache/cookies cleared). However it seems to download an aax file not an aaxc file. But nonetheless a file is downloaded- no 403. I've never tried to put the URL in the browser before now so I'm not sure what the expected behavior is.

downloading cover art?

Just started using this API and wondered if there is a way to download the cover art for books too?
There is a value 'image_url' but it seems to be None for every book.
Any help would be awesome thanks.

Audible don't accept access token for API requests

Describe the bug
Unable to log in to au store using the library
Maybe there was a change in the audible API?

To Reproduce
Steps to reproduce the behavior:

import audible
from getpass import getpass
import logging

logging.basicConfig(stream=sys.stderr, level=logging.INFO)

user = input('Username (email): ')
passwd = getpass()
auth = audible.Authenticator.from_login(
	user,
	passwd,
	locale="AU",
	with_username=False,
	captcha_callback=captcha,
)
auth.to_file(auth_file)
client = audible.Client(auth=auth)
library = client.get(
	'library',
	num_results=1000,
	response_groups=','.join([
		'series',
		'product_desc',
		'product_attrs',
	]),
	sort_by='Author',
)

Expected behavior
It should return the library of the logged in user

Logs

INFO:audible.login:Login with Amazon Account.
ERROR:audible.login:Error message: Important Message! To better protect your account, please re-enter your password and then enter the characters as they are shown in the image below.

ERROR:audible.login:Error message: We're sorry. The Web address you entered is not a functioning page on our site
INFO:audible.auth:logged in to Audible as [omitted]
INFO:audible.auth:saved data to file .audible_auth
INFO:audible.auth:set filename .audible_auth as default
INFO:__main__:retrieving library
INFO:audible.auth:bearer auth flow applied to request
Traceback (most recent call last):
  File "/home/$USER/.local/share/virtualenvs/audible-release-tracker-uvQ44N2A/lib/python3.9/site-packages/audible/client.py", line 143, in _request
    resp.raise_for_status()
  File "/home/$USER/.local/share/virtualenvs/audible-release-tracker-uvQ44N2A/lib/python3.9/site-packages/httpx/_models.py", line 1402, in raise_for_status
    raise HTTPStatusError(message, request=request, response=self)
httpx.HTTPStatusError: 400 Client Error: Bad Request for url: https://api.audible.com.au/1.0/library?num_results=1000&response_groups=series%2Cproduct_desc%2Cproduct_attrs&sort_by=Author
For more information check: https://httpstatuses.com/400

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/home/$USER/Projects/audible-release-tracker/script.py", line 184, in <module>
    asyncio.run(main())
  File "/usr/lib/python3.9/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/usr/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
    return future.result()
  File "/home/$USER/Projects/audible-release-tracker/script.py", line 166, in main
    for title,owned in get_owned_series(client).items()
  File "/home/$USER/Projects/audible-release-tracker/script.py", line 64, in get_owned_series
    library = client.get(
  File "/home/$USER/.local/share/virtualenvs/audible-release-tracker-uvQ44N2A/lib/python3.9/site-packages/audible/client.py", line 217, in get
    return self._request("GET", path, params=params, **kwargs)
  File "/home/$USER/.local/share/virtualenvs/audible-release-tracker-uvQ44N2A/lib/python3.9/site-packages/audible/client.py", line 157, in _request
    self._raise_for_status_error(exc.response)
  File "/home/$USER/.local/share/virtualenvs/audible-release-tracker-uvQ44N2A/lib/python3.9/site-packages/audible/client.py", line 104, in _raise_for_status_error
    raise BadRequest(resp, data)
audible.exceptions.BadRequest: Bad Request (400): The specified authorization token does not correspond to a supported domain

Desktop (please complete the following information):

  • OS: Arch Linux
  • Version: audible==0.5.5

Additional context
It was definitely working last month

Constant Captchas

Describe the bug
When I attempt to authenticate, I get constant Captchas. I input the captcha details, but it will not continue

To Reproduce
Steps to reproduce the behavior: Simply running the code below

import audible

auth = audible.Authenticator.from_login(
    "email",
    "pass",
    locale='us'
)

with audible.Client(auth=auth) as client:
    library = client.get(
        "1.0/library",
        num_results=1000,
        response_groups="product_desc, product_attrs",
        sort_by="-PurchaseDate"
    )
    for book in library["items"]:
        print(book)

Desktop (please complete the following information):

  • OS: MacOS Catalina
  • Browser Chrome

CVF code entry broken due to changes to Amazon Login

It seems that Amazon has recently changed its Login Security such that the CVF code usually supplied via email to verify a new login has been replaced with a system that lets the user click a link and either allow or deny the login attempt.

This has broken the CVF flow in the Audible API:

  • The function check_for_cvf no longer fires due to a new HTML layout. A div with id cvf-page-content doesn't exist anymore:
    def check_for_cvf(soup):
    cvf = soup.find("div", id="cvf-page-content")
    return True if cvf else False
  • The code entry system no longer works, I am unsure if the /ap/cvf/verify endpoint is still used in Amazon's new Login flow. The page does some sort of polling and actually supplies the URL it will redirect you to once it detects that authorization has occurred. I am currently tinkering myself to try and figure out a way forward.

Timeout for httpx.

Describe the bug
When fetching the library (calling aget_from_api in models.py::Library), if the library is very large (or transfer is slow), the underlying httpx call can timeout,

Workaround
Replace: resp = await api_client.get("library", params=request_params)
With: resp = await api_client.get("library", params=request_params, timeout=None)

Suggested Solution
Expose a timeout parameter in aget_from_api.
This makes the problem the consumer of the library and avoids the infinite timeout employed by the workaround.

Error when trying to get book download URL

I'm trying to follow the different examples provided to get a book download URL.

I'm successfully authenticating and fetching my library. However, I'm getting a 500 error when trying to get the book download URL as follow:

 license = client.post(
            f"content/{child_asin}/licenserequest",
            body={
                "drm_type": "Adrm",
                "consumption_type": "Download",
                "quality": "Extreme"
            }
        )
content_url = license['content_license']['content_metadata']['content_url']['offline_url']

The error obtained is as follow:
audible.exceptions.UnexpectedError: Internal Server Error (500): Unexpected error while servicing request for ASIN: B07231CR59 and ACR: null.

I tried using the book asin directly and using its child asin. Can you point me in the correct direction?

Code on login

I'm using this code
auth = audible.LoginAuthenticator( username, password, locale=custom_locale, captcha_callback=custom_captcha_callback, )
to login, but it always asks for "Code: " after solving the captcha. What code ist requested here, where can I find it and is there a way to automatically fill it in or prevent asking for it as I want to use it in an automated script (captcha solver service is working already)? I don't have 2FA set up in amazon and I'm using version 0.2.1 installed via pip

Solved: Decrypting frc cookie

I have this java script which encrypts a strigified JSON object.

Amazon apps using this string as the "frc" cookie. My app creates the frc cookie from custom bytes. Amazon still accepts this frc cookie. But I will be prepared for the future and build the frc cookie the same way as Amazon does.

I've tried to rebuild the java script to python

import base64
import hmac
import hashlib
import json
import gzip

from Crypto.Cipher import AES
from Crypto.Util.py3compat import bchr


def check_sig(pw, iv, data, sig):
    key = get_key_from_password(pw, b'HmacSHA256')
    new_sig = hmac.new(key, iv + data, hashlib.sha256).digest()
    new_sig = new_sig[:len(sig)]
    assert sig == new_sig, 'Signature check failed'


def decrypt_frc(pw, iv, data):
    key = get_key_from_password(pw, b"AES/CBC/PKCS7Padding")
    crypter = AES.new(key, AES.MODE_CBC, iv)
    decrypted_data = crypter.decrypt(data)
    return decrypted_data


def split_frc(frc):
    frc += (len(frc) % 4) * '='
    frc = base64.b64decode(frc)

    sig = frc[1:9]
    iv = frc[9:25]
    data = frc[25:]

    return sig, iv, data


def get_key_from_password(pw, salt):
    return hashlib.pbkdf2_hmac('sha1', pw, salt, 1000, 16)


def pkcs7unpad(msg, blocklen):
    assert len(msg) % blocklen == 0

    paddinglen = msg[-1]

    assert paddinglen > 0 and paddinglen <= blocklen, "Incorrect padding - Wrong key"
    assert msg[-paddinglen:] == bchr(paddinglen) * paddinglen, "Incorrect padding - Wrong key"

    return msg[:-paddinglen]


if __name__ == '__main__':
    frc_cookie = ''
    device_serial = ''
    device_serial = device_serial.encode()

    sig, iv, data = split_frc(frc_cookie)
    check_sig(device_serial, iv, data, sig)
    decrypted = decrypt_frc(device_serial, iv, data)
    decrypted = pkcs7unpad(decrypted, 16)
    decompressed = gzip.decompress(decrypted)
    decrypted_data = json.loads(decompressed)

Can someone with JAVA and Python knowledge take a look on my code if I have take a misstake?

state token for library requests

A library response returns a 13-digit numeric state-token in the response headers.

Using this state token in the url query on the next request like /1.0/library?state_token=1234567654321 will return only changes since the state take was given.

If there are no new content, the json response body items list is empty, the total-count header entry is 0 and the state token is in the header is unchanged. If there are changes in the library, a new state token is obtained, which should be used next time.

Marketplaces

Could you please add Australian and Italian marketplaces:

"australia": { "countryCode": "au", "domain": "com.au", "marketPlaceId": "AN7EY7DTAW63G" }, "italy": { "countryCode": "it", "domain": "it", "marketPlaceId": "A2N7FU2W2BU2ZC" },

Thanks!

Login with username

I will add support using username to login to Audible. Can someone with username test this?

Unable to authenticate again

I've just used my python shell to successfully authenticate myself.
audible.LoginAuthenticator("[email protected]", "pw", locale="uk")
After the captcha it returned a LoginAuthenticator object.

I did not save the returned object to a variable, so I'm unable to save it to a file.

Now when I try to authenticate again (so that this time I can then save the auth to a file) it prompts me for a "code", which I think is a 2FA code right?

I have checked my emails, and I've logged into my audible account and I can't seem to find any 2FA notifications, nor options to disable 2FA.

I've got the string repr of the LoginAuthenticator object that was printed out to my console.

Is there any way I can turn this string into the right format and save that to a file, which I can then use to authenticate myself again?

Thanks and nice one for writing this package :)

Internal Server Error in get_license_response

Describe the bug
The subject says it all

To Reproduce
Executing download_books_aaxc.py with a valid German account and a book you own.
Result is
Error: Internal Server Error (500): There was an internal error processing the request
in get_license_response

I have no experience with http via python so at the moment I do not know how to narrow it down but I am willing to help if somebody can point me in the right direction

Expected behavior
Eventually a downloaded book but at the moment I am more interested in the voucher file

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: Linux (Ubuntu 16.04 but heavily upgraded)
  • Python 3.9.6
  • Current git version of Audible

错误提示

我在对接注册设备的时候提示{"response":{"error":{"code":"InvalidValue","index":"RYuYsd_4VoiVF34wpxzEJAAAAAAAAAABv_ARlqvxrJ-jPM4mLFcoeH3O84pv6xnbo-wcRzJIxyyhPjBCuewweBAyzdvpHH8pNWKTMsS-INu_7O68uG5-zO2zLPuh4pw3hCpbGWbU0U2E69sXj2DW1Wg23I_GGku1y0pmefIWzfmLwdMkXSDjzkO7OzK3JzmjmcegCPIihpnSNbodgAtiE06b6cfjDnEcaPoTICxuYcXvy1zOOuXsSAYHULgBTO_XXnJHGw==","message":"One or more provided values are invalid."}},"request_id":"67dde610-45d1-4cef-9c3f-fd4f2f58ddf3"},
请问怎么处理

OTP prompt for 2FA in JupyterLab

Thanks for creating this package. I'm trying to login over JupyterLab and, although I do get the OTP via text message, the cell throws a "Login failed. Please check the log" error message. That is, the "OTP Code: " prompt does not show up for me in JupyterLab. Is there a workaround or something else I could do instead? Thanks.

Convert books downloaded with licenserequest

Books downloaded with

license, _ = client.post(
   "content/{asin}/licenserequest",
    body={
        "drm_type": "Adrm",
        "consumption_type": "Download",
        "quality":"Extreme"
    }
)
content_url = license['content_license']['content_metadata']['content_url']['offline_url']

can’t converted with ffmpeg -activation_bytes ... at this moment.

Read here

Audible uses a new aaxc format when downloading via audible app on android/iOS or the api. But with this client you can get the response of a licenserequest. Example shorten on many places with ... :

{
    "content_license": {
        "acr": "CR!...",
        "asin": "B07DDKJH33",
        "content_metadata": {
            "content_url": {
                "offline_url": "https://dyrrggeck87jc.cloudfront.net/.../bk_adko_003749ade_lc_128_44100_2.aax?voucherId=cdn:...&Policy=...&Signature=...&Key-Pair-Id=..."
            }
        },
        "drm_type": "Adrm",
        "license_response": "...==",
        "message": "Eligibility details:[GrantRightsReason [reasonCode=MEMBERSHIP, reason=No need to verify active offline license when request is not for offline consumption. OWNERSHIP-user does not have expected ownership rights over the parent title asin. OWNERSHIP-title does not qualify for long title child part ownership or customer does not own child part. OWNERSHIP-user has ownership rights. GEO_RIGHTS-user has geo-rights[DE] over the title[B07DDKJH33] in marketplaceId[AN7V1F1VY261K]. TITLE_ATTRIBUTES-title does not have rodizio plan association. GEO_RIGHTS-user has geo-rights[DE] over the title[B07DDKJH33] in marketplaceId[AN7V1F1VY261K]. No need to verify active offline license when request is not for offline consumption. BENEFIT-user has valid Radio benefit associated[RadioStub]. TITLE_ATTRIBUTES-title does not have radio plan association. Client Asin Mapping validation skipped since client id is null. AAA Client with id: ApolloEnv:AudibleApiExternalRouterService/EU/Prod, does not have access to asin: B07DDKJH33. Client does not have plans that support asin benefits.]]. Licensing details:[ADRM license granted]",
        "request_id": "...",
        "status_code": "Granted",
        "voucher_id": "cdn:..."
    },
    "response_groups": [
        "always-returned"
    ]
}

Maybe someone has the know-how to use this informations to decode the new aaxc format.

Meanwhile you can grab the audible web page for the download urls. You can use cookies to authenticate like so:

import audible
import requests

auth = audible.FileAuthenticator(...)
cookies = auth.login_cookies

r = requests.get("https://www.audible.com/...", cookies=cookies)

Edit 2022-01-11:
Since ffmpeg 4.4 decryption of aaxc files should be build in. You have to use ffmpeg with the --audible_iv and --audible_key options and the correct iv/key pair from the decrypted licenserequest response!

Auth error 'list index out of range' for fr market place

I tried to authenticate in the following:

import audible

auth = audible.Authenticator.from_login(
    USERNAME,
    PASSWORD,
    locale='fr',
    with_username=False
)

After entering the captcha, validating 2SV, I press enter and get:

Answer for CAPTCHA: pr3ybz
Approval alert detected! Amazon sends you a mail.
Please press ENTER when you approve the notification.
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
<ipython-input-10-c44ab5a00348> in <module>
      5     PASSWORD,
      6     locale=COUNTRY_CODE,
----> 7     with_username=False
      8 )

~/anaconda3/lib/python3.7/site-packages/audible/auth.py in from_login(cls, username, password, locale, serial, with_username, register, captcha_callback, otp_callback, cvf_callback, approval_callback)
    363             otp_callback=otp_callback,
    364             cvf_callback=cvf_callback,
--> 365             approval_callback=approval_callback)
    366 
    367         logger.info(f"logged in to Audible as {username}")

~/anaconda3/lib/python3.7/site-packages/audible/auth.py in re_login(self, username, password, serial, with_username, captcha_callback, otp_callback, cvf_callback, approval_callback)
    592             otp_callback=otp_callback,
    593             cvf_callback=cvf_callback,
--> 594             approval_callback=approval_callback)
    595 
    596         serial = login_device.pop("serial")

~/anaconda3/lib/python3.7/site-packages/audible/login.py in login(username, password, country_code, domain, market_place_id, serial, with_username, captcha_callback, otp_callback, cvf_callback, approval_callback)
    403             default_approval_alert_callback()
    404 
--> 405         url = login_soup.find_all("a", class_="a-link-normal")[1]["href"]
    406 
    407         login_resp = session.get(url)

IndexError: list index out of range

CVF page has changed

Heads up: a user of Libation got a CVF approval page without div id resend-approval-alert. Look for one of these also:

form id="resend-approval-form" method="post" action="/ap/cvf/approval/resend"

a id="resend-approval-link" class="a-link-normal" href="#"

Titles saved with "empty" filenames when using JP marketplace

Describe the bug
When downloading from the JP marketplace, only ascii characters in the title of the book are used in the filename.
For example, this results in a title named "ぼぎわんが、来る"
to be empty, named only as "-AAX_22_64.aaxc"
This makes it difficult to use the --all option, as all the files are named the same.

audible library list however, displays the book titles properly.

To Reproduce
audible download --all
or
audible download -a ASIN

Australia problems authorizing new device fails

I'm having problems getting this to work in the Australia Marketpace. Not sure if its just me or everyone.
I am able to log in, but authorizing a new device returns an error. Other regions are working fine.

resp = httpx.post(f"https://api.amazon.{domain}/auth/register", json=body)

Get error 400 BAD REQUEST from:

Exception: {'response': {'error': {'code': 'InvalidToken', 'index': 'cXZ_xxxx_z95BIfA==', 'message': 'One or more tokens are invalid.'}}, 'request_id': '81d134e1-c0f9-4a83-8dce-xxxx'}

I verified that a device isn't created at:
https://www.amazon.com.au/hz/mycd/digital-console/devicedetails?deviceFamily=AUDIBLE_APP

But able to log in and register a device from the android app.

Trying to figure out a way to debug.. Was wondering if there is another Amazon API call that we can call to check that the session was established? Anyway, happy to provide more details or help debug if I can.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.