Comments (34)
Which version you are using? You can try v0.5.2 which prevent CAPTCHAs in most cases.
Your error sounds like a wrong password, username or a selected marketplace where you don’t have a account. If all is correct and you have v0.5.2 already installed please try to authenticate with v0.5.0.
from audible.
If you have at least v0.5.1 you can try to login
import audible
auth = audible.Authenticator.from_login_external("us")
...
Then you will get a login link and copy them to your browser. Login. When you get a error page that page not found copy the url from address bar and insert them to the input field.
from audible.
I inserted the URL into the input field, but nothing happens after I insert it.
from audible.
Do you have a openid.oa2.access_token
key/value pair in the url given after a successful login?
from audible.
Yes, I believe I do. I get the error page which is as expected, and I copy that URL
from audible.
Can you try this code?!
import audible
auth = audible.Authenticator.from_login_external(
'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)
from audible.
And please take a look on the provided url link after login.
from audible.
Yeah, I copied this code, and I did the amazon authentication, and then I pasted the URL into the terminal, however, the program doesn't commence. I press enter, and nothing happens. I'm not sure if the URL is too long. I would show a screen recording of myself doing it, but of course it has sensitive information.
How are you doing it? Do you just paste the URL? Thank you so much for your time
from audible.
from urllib.parse import parse_qs
import httpx
def extract_token_from_url(url: httpx.URL) -> str:
"""Extracts the access token from url query after login."""
parsed_url = parse_qs(url.query.decode())
return parsed_url["openid.oa2.access_token"][0]
url = "INSERT THE COPIED LINK HERE"
url = httpx.URL(url)
token = extract_token_from_url(url)
Please try this with your link and check if you got an token!
from audible.
Hint:
The returned link after login is valid for 60 minutes. So you don’t need to login every time you execute your script. Simply copy the link in the input field if you are in time.
from audible.
If created a script. Can you test this please:
from datetime import datetime, timedelta
from urllib.parse import parse_qs
import audible
import httpx
def do_extra_stuff_with_url(rurl):
response_url = httpx.URL(rurl)
parsed_url = parse_qs(response_url.query.decode())
if not "openid.oa2.access_token" in parsed_url:
print("No access token found in url")
print("The provided url contains the following query:")
print(parsed_url)
return
access_token = parsed_url["openid.oa2.access_token"][0]
print(f"Following access token found:\n{access_token}\n")
auth_time = parsed_url["openid.pape.auth_time"][0]
auth_time = datetime.strptime(auth_time, "%Y-%m-%dT%H:%M:%SZ")
expires = (auth_time + timedelta(seconds=3600)).timestamp()
expires_dt = datetime.fromtimestamp(expires)
if expires_dt > datetime.utcnow():
print("Token expires in:")
print(expires_dt - datetime.utcnow())
else:
print("Access token is expired. Please login again.")
def login_url_callback(url: str) -> str:
print("Please copy the following url and insert it in a webbrowser of "
"your choice:")
print("\n" + url + "\n")
print("Now you have to login with your Amazon credentials. After submit "
"your username and password you have to do this a second time "
"and solving a captcha before sending the login form.\n")
print("After login, your browser will show you a error page (not found). "
"Do not worry about this. It has to be like this. Please copy the "
"url from the address bar in your browser now.\n")
rurl = input("Please insert the copied url (after login):\n")
do_extra_stuff_with_url(rurl)
return rurl
auth = audible.Authenticator.from_login_external(
'us',
login_url_callback=login_url_callback
)
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)
from audible.
from urllib.parse import parse_qs import httpx def extract_token_from_url(url: httpx.URL) -> str: """Extracts the access token from url query after login.""" parsed_url = parse_qs(url.query.decode()) return parsed_url["openid.oa2.access_token"][0] url = "INSERT THE COPIED LINK HERE" url = httpx.URL(url) token = extract_token_from_url(url)
Please try this with your link and check if you got an token!
I ran this, and I do get a token.
I ran your script, and I think the problem lies with this line
rurl = input("Please insert the copied url (after login):\n")
I insert the copied url, but nothing happens. I type enter, and nothing happens. So it appears to be a problem with the input. I copied my URL in the place of the input, and it passed. However, I get the following error.
Token expires in:
0:54:48.997241
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/audible/client.py", line 143, in _request
resp.raise_for_status()
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/httpx/_models.py", line 1103, in raise_for_status
raise HTTPStatusError(message, request=request, response=self)
httpx.HTTPStatusError: 403 Client Error: Forbidden for url: https://api.audible.com/1.0/library?num_results=1000&response_groups=product_desc%2C+product_attrs&sort_by=-PurchaseDate
For more information check: https://httpstatuses.com/403
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "test.py", line 59, in <module>
sort_by="-PurchaseDate"
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/audible/client.py", line 217, in get
return self._request("GET", path, params=params, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/audible/client.py", line 157, in _request
self._raise_for_status_error(exc.response)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/audible/client.py", line 106, in _raise_for_status_error
raise Unauthorized(resp, data)
audible.exceptions.Unauthorized: Forbidden (403): Request could not be authenticated
Any advice? Really appreciate your time
from audible.
Okay, if you have a valid access token you can do the following:
import audible
auth = audible.Authenticator()
auth.locale = "us"
auth.access_token = "YOUR ACCESS TOKEN"
auth.register_device()
auth.to_file("FILENAME FOR AUTH_FILE")
This saves an auth file to given location. You don‘t need to login again. With a device registration you use another form of authentication. Only run this to load the file:
import audible
auth = audible.Authenticator.from_file("FILENAME")
client = ...
from audible.
I‘ve an idea with this line of code:
rurl = input("Please insert the copied url (after login):\n")
The field expected the input in a new line. Can you replace the line above with these:
rurl = input("Please insert the copied url (after login):")
from audible.
Mac OS uses \r\n
instead of \n
for a newline.
from audible.
The input line didn't work either unfortunately. What I ended up doing is taking the url from the error page, and setting rurl equal to that url, but that seems to only work once. Any other ways to do it besides just the input thing?
Also, does this package allow me to download .aax files? If not, is there a way I can use the authentication returned from this api to access audible.com to webscrape it?
from audible.
Your issue sounds really strange. I doesn’t hear about any issues like this.
You only can try to obtain the access token the way you do. And then instantiate the Authenticator like above and set locale and access_token. After that, register a device and save the credentials. After that you don’t have to worry about this step anymore.
My package can‘t download the aax
file for you. But it can give you the download link. Or you can use audible-cli which can download aax files using the command line.
from audible.
My package can‘t download the
aax
file for you. But it can give you the download link. Or you can use audible-cli which can download aax files using the command line.
How can I get the download link using your api?
You only can try to obtain the access token the way you do. And then instantiate the Authenticator like above and set locale and access_token. After that, register a device and save the credentials. After that you don’t have to worry about this step anymore.
Interesting, I will try that and circle back. I'll try and see if its any problems with my settings in my terminal or whatever that's giving the issues. I'll update you on that
from audible.
Here you can find an example for downloading aax files. This example doesn’t care about available codecs. This can result in a download link which doesn’t work.
Hint:
Audible Plus books can‘t be downloaded in aax format. They use an advanced sort of encryption. If you want such books you have to download them in aaxc format.
from audible.
Will definitely check this out. But i really don't know why the input isn't working. theoretically, I should just input the URL and press enter, but my terminal isn't letting me.
A problem with the URL i've experienced is that it is only valid for about 5 minutes. I can run the api a few times, and then afterwards, it keeps telling me that the request cannot be authorized.
0:57:27.128982
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/audible/client.py", line 143, in _request
resp.raise_for_status()
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/httpx/_models.py", line 1103, in raise_for_status
raise HTTPStatusError(message, request=request, response=self)
httpx.HTTPStatusError: 403 Client Error: Forbidden for url: https://api.audible.com/1.0/library?num_results=1000&response_groups=product_desc%2C+product_attrs&sort_by=-PurchaseDate
For more information check: https://httpstatuses.com/403
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "test.py", line 59, in <module>
sort_by="-PurchaseDate"
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/audible/client.py", line 217, in get
return self._request("GET", path, params=params, **kwargs)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/audible/client.py", line 157, in _request
self._raise_for_status_error(exc.response)
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/audible/client.py", line 106, in _raise_for_status_error
raise Unauthorized(resp, data)
audible.exceptions.Unauthorized: Forbidden (403): Request could not be authenticated
I could store the access code in a file and such, but I don't want to have to store user passwords. So getting the URL thing to work would be really great.
Here you can find an example for downloading aax files. This example doesn’t care about available codecs. This can result in a download link which doesn’t work.
How can I figure out the available codecs? It worked for a few of my personal books, but not with some others.
Again, I appreciate you helping me out!
from audible.
Maybe the issue with the url input and the constant CAPTCHA are the same. The input field will not be properly submitted I think. To verify that please try this:
import audible
def login_url_callback(url: str) -> str:
print("Please copy the following url and insert it in a webbrowser of "
"your choice:")
print("\n" + url + "\n")
print("Now you have to login with your Amazon credentials. After submit "
"your username and password you have to do this a second time "
"and solving a captcha before sending the login form.\n")
print("After login, your browser will show you a error page (not found). "
"Do not worry about this. It has to be like this. Please copy the "
"url from the address bar in your browser now.\n")
rurl = input("Please insert the copied url (after login):\n")
print(f"You are entered the following: {rurl}")
return rurl
auth = audible.Authenticator.from_login_external(
'us',
login_url_callback=login_url_callback
)
This will print out the entered url. Please check if the copied url match the printed url. If they don’t match you can install click (pip install click). And then replace input("Please insert the copied url (after login):\n")
with click.prompt("Please insert the copied url (after login):\n")
.
I strongly recommended that you don’t login to often in short time. You could be need to change your password or other things. So best way is to register a device once and reuse the given credentials after registration. This credentials will never expire until you deregister your device.
The available codecs will be displayed in the api response when getting the library. Each item (book) contains a available_codecs
key which holds the allowed codecs. If available_codecs
is None please make sure that the response_groups
param contains at least product_desc
and product_attrs
.
from audible.
Right. So the problem lies with the input line. I copy the url and I paste it into the input, and it doesn't allow me to enter. Also, I've found that the link is only valid for a minute or two, so I am able to access the api's and such. However, after a minute or two passes, then I have to re-login. Why is this the case?
from audible.
That’s really strange. My tests with access token are month ago. My access tokens from login where valid for 60 minutes. Maybe Amazon changed something.
So I would suggest you to register a device immediately after login and save the registration data to file.
Have you try to make use of click.prompt
?
from audible.
Yes, I tried click.prompt()
, and it was the same behavior.
I think saving the registration data to a file is a good idea. However, that means that I'd need to use the user's password, which I do not think is safe to store on the database I am making, which is why I am a bit concerned about the longevity of the link.
This is what I am running
from datetime import datetime, timedelta
from urllib.parse import parse_qs
import audible
import click
import httpx
def do_extra_stuff_with_url(rurl):
response_url = httpx.URL(rurl)
parsed_url = parse_qs(response_url.query.decode())
if not "openid.oa2.access_token" in parsed_url:
print("No access token found in url")
print("The provided url contains the following query:")
print(parsed_url)
return
access_token = parsed_url["openid.oa2.access_token"][0]
print(f"Following access token found:\n{access_token}\n")
auth_time = parsed_url["openid.pape.auth_time"][0]
auth_time = datetime.strptime(auth_time, "%Y-%m-%dT%H:%M:%SZ")
expires = (auth_time + timedelta(seconds=3600)).timestamp()
expires_dt = datetime.fromtimestamp(expires)
if expires_dt > datetime.utcnow():
print("Token expires in:")
print(expires_dt - datetime.utcnow())
else:
print("Access token is expired. Please login again.")
def login_url_callback(url: str) -> str:
print("Please copy the following url and insert it in a webbrowser of "
"your choice:")
print("\n" + url + "\n")
print("Now you have to login with your Amazon credentials. After submit "
"your username and password you have to do this a second time "
"and solving a captcha before sending the login form.\n")
print("After login, your browser will show you a error page (not found). "
"Do not worry about this. It has to be like this. Please copy the "
"url from the address bar in your browser now.\n")
rurl = click.prompt("insert url")
do_extra_stuff_with_url(rurl)
return rurl
auth = audible.Authenticator.from_login_external(
'us',
login_url_callback=login_url_callback
)
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)
and after 2-3 minutes, or so I get the access denied error
from audible.
To register a device simply add
auth.register_device()
auth.to_file("FILENAME")
# if you want to encrypt the auth file
auth.to_file(
"FILENAME",
password="YOUR SUPER STRONG PASSWORD",
encryption="json"
)
after auth = audible.Authenticator.from_login_external(...)
.
And to load the file auth = audible.Authenticator.from_file("FILENAME", password="YOUR PW")
The auth file doesn’t store your Amazon password but other critical data. So encrypting your auth file is recommended if other persons can access your PC.
from audible.
Here you can read some information about load and save auth files.
from audible.
Ahh ok this is perfect I think. I was under the assumption that I needed the amazon password for the auth.to_file()
call, but I guess I don't, which is great. If I don't register the device, can I use the authentication file forever? Or do I need to register the device to make the authentication file valid indefinitely?
I really appreciate your time answering my questions.
from audible.
You can save the auth file after a login too. This would save your access token. But you say that your token expires after some minutes. So saving and reusing the session after login is useless in your case.
My test for months results in a token lifetime for 60 minutes. So I reused this auth file in that time. After expiration I had to login again. Device registration (like the iOS and Android Audible App does) make this all obsolete.
from audible.
Maybe this could be your issue with input fields. Can you verify that?
from audible.
I close this issue now. If there is any progress I will reopen the issue.
from audible.
Yeah, I was using VS code's terminal, then switched to my Mac's proper terminal, and it didn't solve the issue.
I think registering the device is the best way to go now. Can I register more than one account on one device?
Thank you very much for your time assisting me.
from audible.
You can register multiple devices for one account. And you can have multiple accounts each with his own auth file.
from audible.
If you have books on multiple marketplaces you only need to register once.
from audible.
Maybe I have a solution for your issue with insert the url in terminal after a successful login. As you can read here this could be a Mac OS related problem. A solution is to enter the stty -icanon
command before executing your script or you try to import the readline module in your script.
from audible.
Related Issues (20)
- 错误提示 HOT 19
- Quality is set to `Extreme` even set to `high` HOT 1
- TEST: New device registration method HOT 4
- Extract Audible Bookmark Notes HOT 3
- Issue getting activation bytes from auth server HOT 9
- Switch to poetry, implement CI+CD, remove Python version <3.8
- Lift upper version restriction on `httpx`. HOT 3
- Is there any way to get a list of books in a series? HOT 1
- Amazon authentication code not handled properly HOT 2
- I need some help with metadata HOT 2
- Audible brazil HOT 11
- Captcha Login Fails 'KeyError' HOT 17
- OTP prompt for 2FA in JupyterLab HOT 4
- Building an external login URL HOT 9
- encryptedPwd HOT 5
- How does the BestSellers sort_by option in the APIs work? HOT 3
- Where does the file get stored with to_file() HOT 5
- Can't filter plus catalog books from 'catalog/products' HOT 9
- state token for library requests HOT 2
- response_callback no longer works properly with the endpoint: https://cde-ta-g7g.amazon.com/FionaCDEServiceEngine/sidecar HOT 5
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from audible.