Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
This repository was archived by the owner on Apr 3, 2021. It is now read-only.
/audible.crPublic archive

Interface for Audible's internal API

License

NotificationsYou must be signed in to change notification settings

omarroth/audible.cr

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

38 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Seemkb79/Audible for an actively maintained library in Python.

Interface for internal Audible API.

Other Implementations

See alsoAudiobookHub for a list of handy resources for managing audiobooks.

Installation

  1. Add the dependency to yourshard.yml:
dependencies:audible:github:omarroth/audible.cr
  1. Runshards install

Usage

require"audible"client=Audible::Client.new("EMAIL","PASSWORD",locale:"us")puts client.get("/1.0/library").body# => {"items":[{"asin":"B002V0QUOC"...

Sessions can be saved usingto_json andfrom_json, like so:

require"audible"client=Audible::Client.new("EMAIL","PASSWORD",locale:"us")File.write("session.json", client.to_json)# Sometime later...client=Audible::Client.from_json(File.read("session.json"))

Logging in currently requires answering a CAPTCHA. By default a user prompt will be provided usingreadline, which looks like:

https://opfcaptcha-prod.s3.amazonaws.com/...Answer for CAPTCHA:

A custom callback can be provided (for example submitting the CAPTCHA to an external service), like so:

require"audible"client=Audible::Client.new("EMAIL","PASSWORD",locale:"us")do |captcha_url|# Do some things with the captcha_url ..."My answer for CAPTCHA"end

If 2FA is enabled for the given account a prompt will be provided usingreadline, which looks like:

OTP Code:

A custom callback can be provided like so:

defcustom_otp_callback# Do some things to get OTP code...return"My OTP code"endclient=Audible::Client.new("USERNAME","PASSWORD",locale:"us",otp_callback:->custom_otp_callback)# Or directly as proc:client=Audible::Client.new("USERNAME","PASSWORD",locale:"us",otp_callback:->{return"My OTP code" })

Locales

This API supports 5 countries natively:

  • USA (locale: "us")
  • Germany (locale: "de")
  • United Kingdom (locale: "uk")
  • France (locale: "fr")
  • Canada (locale: "ca")

Authentication

Clients are authenticated using OpenID. Once a client has successfully authenticated with Amazon, they are given an access token and refresh token for authenticating with Audible.

Clients authenticate with Audible using cookies from Amazon and the given access token to/auth/register. Clients are given an RSA private key and adp_token used for signing subsequent requests.

For requests to the Audible API, requests need to be signed using the provided key and adp_token. Request signing is fairly straight-forward and uses a signed SHA256 digest. Headers look like:

x-adp-alg: SHA256withRSA:1.0x-adp-signature: AAAAAAAA...:2019-02-16T00:00:01.000000000Z,x-adp-token: {enc:...}

TheAudible::Client will refresh theaccess_token and other necessary keys when necessary.

As reference for other implementations, a clientmust store cookies from a successful Amazon login and a workingaccess_token in order to renewrefresh_token,adp_token, etc from/auth/register.

Anaccess_token can be renewed by making a request to/auth/token.access_tokens are valid for 1 hour.

Documentation:

There is currently no publicly available documentation about the Audible API. There is a node client (audible-api) that has some endpoints documented, but does not provide information on authentication.

Luckily the Audible API is partially self-documenting, however the parameter names need to be known. Error responses will look like:

{"message":"1 validation error detected: Value 'some_random_string123' at 'numResults' failed to satisfy constraint: Member must satisfy regular expression pattern: ^\\d+$"}

Few endpoints have been fully documented, as a large amount of functionality is not testable from the app or functionality is unknown. Most calls need to be authenticated.

For%s substitutions the value is unknown or can be inferred from the endpoint./1.0/catalog/products/%s for example requires anasin, as in/1.0/catalog/products/B002V02KPU.

Each bullet below refers to a parameter for the request with the specified method and URL.

Responses will often provide very little info withoutresponse_groups specified. Multiple response groups can be specified, for example:/1.0/catalog/products/B002V02KPU?response_groups=product_plan_details,media,review_attrs. When providing an invalid response group, the server will return an error response but will not provide information on available response groups.

POST /1.0/orders

  • B asin : String
  • B audiblecreditapplied : String

Example request body:

{"asin":"B002V1CB2Q","audiblecreditapplied":"false"}
  • audiblecreditapplied: [true, false]

audiblecreditapplied will specify whether to use available credits or default payment method.

GET /0.0/library/books

Deprecated: Use/1.0/library

  • purchaseAfterDate: mm/dd/yyyy
  • sortByColumn: [SHORT_TITLE, strTitle, DOWNLOAD_STATUS, RUNNING_TIME, sortPublishDate, SHORT_AUTHOR, sortPurchDate, DATE_AVAILABLE]
  • sortInAscendingOrder: [true, false]

GET /1.0/library

  • num_results: \d+ (max: 1000)
  • page: \d+
  • purchased_after:RFC3339 (e.g.2000-01-01T00:00:00Z)
  • response_groups: [badge_types, category_ladders, claim_code_url, contributors, is_downloaded, is_returnable, media, origin_asin, pdf_url, percent_complete, price, product_attrs, product_desc, product_extended_attrs, product_plan_details, product_plans, provided_review, rating, relationships, review_attrs, reviews, sample, series, sku]
  • sort_by: [-Author, -Length, -Narrator, -PurchaseDate, -Title, Author, Length, Narrator, PurchaseDate, Title]

GET /1.0/library/%{asin}

  • response_groups: [badge_types, category_ladders, claim_code_url, contributors, is_downloaded, is_returnable, media, origin_asin, pdf_url, percent_complete, price, product_attrs, product_desc, product_extended_attrs, product_plan_details, product_plans, provided_review, rating, relationships, review_attrs, reviews, sample, series, sku]

POST(?) /1.0/library/item

  • asin:

POST(?) /1.0/library/item/%s/%s

GET /1.0/wishlist

  • num_results: \d+ (max: 50)
  • page: \d+
  • response_groups: [contributors, media, price, product_attrs, product_desc, product_extended_attrs, product_plan_details, product_plans, rating, sample, sku]
  • sort_by: [-Author, -DateAdded, -Price, -Rating, -Title, Author, DateAdded, Price, Rating, Title]

POST /1.0/wishlist

  • B asin : String

Example request body:

{"asin":"B002V02KPU"}

Returns 201 and aLocation to the resource.

DELETE /1.0/wishlist/%{asin}

Returns 204 and removes the item from the wishlist using the givenasin.

GET /1.0/badges/progress

  • locale: en_US
  • response_groups: brag_message
  • store: Audible

GET /1.0/badges/metadata

  • locale: en_US
  • response_groups: all_levels_metadata

GET /1.0/account/information

  • response_groups: [delinquency_status, customer_benefits, subscription_details_payment_instrument, plan_summary, subscription_details]
  • source: [Enterprise, RodizioFreeBasic, AyceRomance, AllYouCanEat, AmazonEnglish, ComplimentaryOriginalMemberBenefit, Radio, SpecialBenefit, Rodizio]

POST(?) /1.0/library/collections/%s/channels/%s

  • customer_id:
  • marketplace:

POST(?) /1.0/library/collections/%s/products/%s

  • channel_id:

GET /1.0/catalog/categories

  • categories_num_levels: \d+ (greater than or equal to 1)
  • ids: \d+(,\d+)*
  • root: [InstitutionsHpMarketing, ChannelsConfigurator, AEReadster, ShortsPrime, ExploreBy, RodizioBuckets, EditorsPicks, ClientContent, RodizioGenres, AmazonEnglishProducts, ShortsSandbox, Genres, Curated, ShortsIntroOutroRemoval, Shorts, RodizioEpisodesAndSeries, ShortsCurated]

GET /1.0/catalog/categories/%{category_id}

  • image_dpi: \d+
  • image_sizes:
  • image_variants:
  • products_in_plan_timestamp:
  • products_not_in_plan_timestamp:
  • products_num_results: \d+
  • products_plan: [Enterprise, RodizioFreeBasic, AyceRomance, AllYouCanEat, AmazonEnglish, ComplimentaryOriginalMemberBenefit, Radio, SpecialBenefit, Rodizio]
  • products_sort_by: [-ReleaseDate, ContentLevel, -Title, AmazonEnglish, AvgRating, BestSellers, -RuntimeLength, ReleaseDate, ProductSiteLaunchDate, -ContentLevel, Title, Relevance, RuntimeLength]
  • reviews_num_results: \d+
  • reviews_sort_by: [MostHelpful, MostRecent]

POST /1.0/content/%{asin}/licenserequest

  • B consumption_type: [Streaming, Offline, Download]
  • B drm_type: [Hls, PlayReady, Hds, Adrm]
  • B quality: [High, Normal, Extreme, Low]
  • B num_active_offline_licenses: \d+ (max: 10)

Example request body:

{"drm_type":"Adrm","consumption_type":"Download","quality":"Extreme"}

For a succesful request, returns JSON body withcontent_url.

GET /1.0/annotations/lastpositions

  • asins: asin (comma-separated), e.g. ?asins=B01LWUJKQ7,B01LWUJKQ7,B01LWUJKQ7

GET /1.0/content/%{asin}/metadata

  • acr:

GET /1.0/customer/information

  • response_groups: [migration_details, subscription_details_rodizio, subscription_details_premium, customer_segment, subscription_details_channels]

GET /1.0/customer/status

  • response_groups: [benefits_status, member_giving_status, prime_benefits_status, prospect_benefits_status]

GET /1.0/customer/freetrial/eligibility

GET /1.0/library/collections

  • customer_id:
  • marketplace:

POST(?) /1.0/library/collections

  • collection_type:

GET /1.0/library/collections/%s

  • customer_id:
  • marketplace:
  • page_size:
  • continuation_token:

GET /1.0/library/collections/%s/products

  • customer_id:
  • marketplace:
  • page_size:
  • continuation_token:
  • image_sizes:

GET /1.0/stats/aggregates

  • daily_listening_interval_duration: ([012]?[0-9])|(30) (0 to 30, inclusive)
  • daily_listening_interval_start_date: YYYY-MM-DD (e.g.2019-06-16)
  • locale: en_US
  • monthly_listening_interval_duration: 0?[0-9]|1[012] (0 to 12, inclusive)
  • monthly_listening_interval_start_date: YYYY-MM (e.g.2019-02)
  • response_groups: [total_listening_stats]
  • store: [AudibleForInstitutions, Audible, AmazonEnglish, Rodizio]

GET /1.0/stats/status/finished

  • asin: asin

POST(?) /1.0/stats/status/finished

  • start_date:
  • status:
  • continuation_token:

GET /1.0/pages/%s

%s: ios-app-home

  • locale: en-US
  • reviews_num_results:
  • reviews_sort_by:
  • response_groups: [media, product_plans, view, product_attrs, contributors, product_desc, sample]

GET /1.0/catalog/products/%{asin}

  • image_dpi:
  • image_sizes:
  • response_groups: [contributors, media, product_attrs, product_desc, product_extended_attrs, product_plan_details, product_plans, rating, review_attrs, reviews, sample, sku]
  • reviews_num_results: \d+ (max: 10)
  • reviews_sort_by: [MostHelpful, MostRecent]

GET /1.0/catalog/products/%{asin}/reviews

  • sort_by: [MostHelpful, MostRecent]
  • num_results: \d+ (max: 50)
  • page: \d+

GET /1.0/catalog/products

  • author:
  • browse_type:
  • category_id: \d+(,\d+)*
  • disjunctive_category_ids:
  • image_dpi: \d+
  • image_sizes:
  • in_plan_timestamp:
  • keywords:
  • narrator:
  • not_in_plan_timestamp:
  • num_most_recent:
  • num_results: \d+ (max: 50)
  • page: \d+
  • plan: [Enterprise, RodizioFreeBasic, AyceRomance, AllYouCanEat, AmazonEnglish, ComplimentaryOriginalMemberBenefit, Radio, SpecialBenefit, Rodizio]
  • products_since_timestamp:
  • products_sort_by: [-ReleaseDate, ContentLevel, -Title, AmazonEnglish, AvgRating, BestSellers, -RuntimeLength, ReleaseDate, ProductSiteLaunchDate, -ContentLevel, Title, Relevance, RuntimeLength]
  • publisher:
  • response_groups: [contributors, media, price, product_attrs, product_desc, product_extended_attrs, product_plan_detail, product_plans, rating, review_attrs, reviews, sample, sku]
  • reviews_num_results: \d+ (max: 10)
  • reviews_sort_by: [MostHelpful, MostRecent]
  • title:

GET /1.0/recommendations

  • category_image_variants:
  • image_dpi:
  • image_sizes:
  • in_plan_timestamp:
  • language:
  • not_in_plan_timestamp:
  • num_results: \d+ (max: 50)
  • plan: [Enterprise, RodizioFreeBasic, AyceRomance, AllYouCanEat, AmazonEnglish, ComplimentaryOriginalMemberBenefit, Radio, SpecialBenefit, Rodizio]
  • response_groups: [contributors, media, price, product_attrs, product_desc, product_extended_attrs, product_plan_details, product_plans, rating, sample, sku]
  • reviews_num_results: \d+ (max: 10)
  • reviews_sort_by: [MostHelpful, MostRecent]

GET /1.0/catalog/products/%{asin}/sims

  • category_image_variants:
  • image_dpi:
  • image_sizes:
  • in_plan_timestamp:
  • language:
  • not_in_plan_timestamp:
  • num_results: \d+ (max: 50)
  • plan: [Enterprise, RodizioFreeBasic, AyceRomance, AllYouCanEat, AmazonEnglish, ComplimentaryOriginalMemberBenefit, Radio, SpecialBenefit, Rodizio]
  • response_groups: [contributors, media, price, product_attrs, product_desc, product_extended_attrs, product_plans, rating, review_attrs, reviews, sample, sku]
  • reviews_num_results: \d+ (max: 10)
  • reviews_sort_by: [MostHelpful, MostRecent]
  • similarity_type: [InTheSameSeries, ByTheSameNarrator, RawSimilarities, ByTheSameAuthor, NextInSameSeries]

Downloading

For multipart books, it's necessary to use thechild_asin provided withresponse_groups=relationships in order to download each part.

require"audible"client=Audible::Client.new("EMAIL","PASSWORD")# Request .aax file in given qualitybody= {consumption_type:"Download",drm_type:"Adrm",quality:"Extreme",}.to_jsoncontent_url=JSON.parse(client.post("/1.0/content/B002V0QUOC/licenserequest",body: body).body)["content_license"]["content_metadata"]["content_url"]["offline_url"].as_s# => https://dyrrggeck87jc.cloudfr...# `content_url` can then be downloaded using any tool

Note:content_url is now provided in.aaxc format, which ffmpeg doesnot currently support, seemkb79/Audible#3. For now you can use the following to get files in.aax format:

require"audible"asin="some_asin"codec="some_codec"# Desired quality from /1.0/library/{asin}?response_groups=product_attrs,relationshipsclient=Audible::Client.from_json(File.read("session.json"))request=HTTP::Request.new("GET","/FionaCDEServiceEngine/FSDownloadContent?type=AUDI&currentTransportMethod=WIFI&key=#{asin}&codec=#{codec}")request= client.sign_request(request)tld=Audible::LOCALES[client.locale]["AUDIBLE_API"].to_s.split("api.audible.")[1]content_url=HTTP::Client.new(URI.parse("https://cde-ta-g7g.amazon.com")).exec(request)  .headers["Location"].gsub("https://cds.audible.com","https://cds.audible.#{tld}")# => https://cds.audible.com/download...# `content_url` can then be downloaded using any tool

Assuming you have your activation bytes, you can convert .aax into another format with the following:

$ ffmpeg -activation_bytes 1CEB00DA -i test.aax -vn -c:a copy output.mp4

Contributing

  1. Fork it (https://github.com/omarroth/audible.cr/fork)
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create a new Pull Request

Contributors

About

Interface for Audible's internal API

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages


[8]ページ先頭

©2009-2025 Movatter.jp