GithubHelp home page GithubHelp logo

amazon-music's Introduction

AmazonMusic

AmazonMusic is an open source Python 2/3 library, providing access to Amazon Music/Prime Music's streaming service. It enables new applications to be written that use Amazon's service.

This is similar to other projects for other streaming services. For example, for Spotify use librespot and python-librespot - based on Spotify's libspotify. Unfortunately, Amazon don't offer an Amazon Music SDK, and this seems to be the first attempt to reverse engineer one.

Example usage

from amazonmusic import AmazonMusic
import os

am = AmazonMusic(credentials=['[email protected]', 'xyzzy'])

station = am.create_station('A2UW0MECRAWILL')
print('Playing station {0}...'.format(station.name))

for t in station.tracks:
  print('Playing {0} by {1} from {2} [{3}]...'.format(t.name, t.artist, t.album, t.albumArtist))
  os.system('cvlc --play-and-exit "{0}"'.format(t.getUrl()))

Note: hardcoding your Amazon credentials is a bad idea! AmazonMusic can be passed a lambda function that returns a two-element list. This will be called if a sign-in is necessary and can be used to prompt the user for their credentials. For example:

from getpass import getpass

# Make Python 2 work like Python 3
try: input = raw_input
except NameError: pass

# Prompt the user for the credentials, when needed
am = AmazonMusic(credentials = lambda: [input('Email: '), getpass('Amazon password: ')])

Dependencies

The Requests and Beautiful Soup libraries are required beyond the standard Python libraries. These can be usually be installed using your standard package manager or pip:

Operating environment Python version Packages
Debian, Ubuntu 2 python-requests, python-bs4
Debian, Ubuntu 3 python3-requests, python3-bs4
cygwin 2 python2-requests, python2-bs4
cygwin 3 python3-requests, python3-bs4
pip (e.g. OS X Homebrew) 2 & 3 requests, beautifulsoup4

Features

  • Play album by ASIN
  • Play station by ASIN
  • Play playlist by ASIN
  • Library access - saved albums
  • Supports Amazon Music with Prime subscriptions, with multiple regions [needs testing]
  • Supports Python 2 & Python 3

Roadmap

Short term:

  • Searching [in progress]
  • Library access - saved playlists
  • Browse recommendations
  • Browse stations

Medium term:

  • Ensure full Amazon Music Unlimited subscriptions are supported
  • Better handling of a captcha during authentication

Possible long term:

  • Better examples (full Amazon Music client?)
  • Manage library (e.g. create playlists)
  • Play tracks without an external player (such as cvlc)

Never:

  • Features that facilitate piracy (such as track downloading): the library is to allow streaming only

If you would like to contribute to development, or understand how the library - or Amazon Music - works, see DEVELOPMENT for more information.

Examples

Several examples are included. To run them:

  1. Enure your working directory contains the amazonmusic.py library
  2. Set PYTHONPATH and run them in Python:
PYTHONPATH=. python examples/play-album.py
PYTHONPATH=. python examples/play-station.py
PYTHONPATH=. python examples/play-playlist.py
PYTHONPATH=. python examples/my-library.py

Default ASINs for albums, stations and playlists are defaulted within the examples, but alternatives can be provided as a command line argument. The search.py example can be used to find alternatives (although the raw JSON needs to be manually parsed at the moment):

PYTHONPATH=. python examples/search.py Adele 25
[...]
      {
        "document": {
          "__type": "com.amazon.music.platform.model#CatalogAlbum",
          "artFull": {
            "URL": "https://m.media-amazon.com/images/I/A170tH1apiL._AA500.jpg",
            "__type": "com.amazon.music.platform.model#ArtURL",
            "artUrl": "https://m.media-amazon.com/images/I/A170tH1apiL._AA500.jpg"
          },
          "artistAsin": "B001EEJMYG",
          "artistName": "Adele",
          "asin": "B0170UQ0OC",
          "isMusicSubscription": "true",
          "originalReleaseDate": 1447977600.0,
          "primaryGenre": "Pop",
          "primeStatus": "PRIME",
          "title": "25",
          "trackCount": 11
        }
      },
PYTHONPATH=. python examples/play-album.py B0170UQ0OC

Background

I have a long term plan to build an integrated smart home with voice assistant (possibly using the likes of spaCy, Snowboy, openHAB, Mopidy and respeaker-avs). As an Amazon Prime subscriber, I get access to Prime Music - which just about covers my streaming audio needs. Unfortunately, Alexa Voice Service only allows people actively working with Amazon on commercial products under NDA to access Amazon Music.

Switching to Spotify will cost money. Commercialising the integrating smart home solution might be an even longer term plan, but I don't want to predicate access on that. Reverse engineering Amazon Music - or getting Amazon to provide an API - so that it can be added to projects like Mopidy seems like the best way forward.

License

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this library except in compliance with the License. You may obtain a copy of the License in the LICENSE file.

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

Attribution to Andrew Flegg is welcome, but not required.

Contributors

amazon-music's People

Contributors

jaffa 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  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

amazon-music's Issues

PlayAlbum Example not working

play-album.py B0170UQ0OC
Email: my-email-here
Amazon password:
Traceback (most recent call last):
  File "/home/pi/amazon-music-master/play-album.py", line 32, in <module>
    album = am.get_album(asin)
  File "/home/pi/amazon-music-master/amazonmusic.py", line 265, in get_album
    )['albumList'][0]
IndexError: list index out of range

Any idea what is happening here?

Not working

Getting an error when trying to login:

Traceback (most recent call last):
File "examples/my-library.py", line 26, in
am = AmazonMusic(credentials = lambda: [input('Email: '), getpass('Amazon password: ')])
File "/home/destiny/Scripts/amazon-music-config-fix-2020-07/amazonmusic.py", line 107, in init
raise Exception("Unable to find appConfig in {}".format(r.content))
Exception: Unable to find appConfig in b'\n<!doctype html><script>var aPageStart = (new Date()).getTime();</script> \n\n<title dir="ltr"> Amazon\n</title>\n\n<script>\n(function(f,h,Q,A){function G(a){v&&v.tag&&v.tag(q(":","aui",a))}function x(a,b){v&&v.count&&v.count("aui:"+a,0===b?0:b||(v.count("aui:"+a)||0)+1)}function l(a){try{return a.test(navigator.userAgent)}catch(b){return!1}}function y(a,b,c){a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent&&a.attachEvent("on"+b,c)}function q(a,b,c,e){b=b&&c?b+a+c:b||c;return e?q(a,b,e):b}function H(a,b,c){try{Object.defineProperty(a,b,{value:c,writable:!1})}catch(e){a[b]=c}return c}function ta(a,b){var c=a.length,\ne=c,g=function(){e--||(R.push(b),S||(setTimeout(T,0),S=!0))};for(g();c--;)ca[a[c]]?g():(B[a[c]]=B[a[c]]||[]).push(g)}function ua(a,b,c,e,g){var d=h.createElement(a?"script":"link");y(d,"error",e);g&&y(d,"load",g);a?(d.type="text/javascript",d.async=!0,c&&/AUIClients|images[/]I/.test(b)&&d.setAttribute("crossorigin","anonymous"),d.src=b):(d.rel="stylesheet",d.href=b);h.getElementsByTagName("head")[0].appendChild(d)}function da(a,b){function c(c,e){function g(){ua(b,c,h,function(b){!I&&h?(h=!1,x("resource_retry"),\ng()):(x("resource_error"),a.log("Asset failed to load: "+c,I?"WARN":A));b&&b.stopPropagation?b.stopPropagation():f.event&&(f.event.cancelBubble=!0)},e)}if(ea[c])return!1;ea[c]=!0;x("resource_count");var h=!0;return!g()}if(b){var e=0,g=0;c.andConfirm=function(a,b){return c(a,function(){e++;b&&b.apply(this,arguments)})};c.confirm=function(){g++};c.getCsriCounters=function(){return{reqs:e,full:g}}}return c}function va(a,b,c){for(var e={name:a,guard:function(c){return b.guardFatal(a,c)},logError:function(c,\nd,e){b.logError(c,d,e,a)}},g=[],d=0;d<c.length;d++)J.hasOwnProperty(c[d])&&(g[d]=U.hasOwnProperty(c[d])?Uc[d]:J[c[d]]);return g}function C(a,b,c,e,g){return function(d,h){function m(){var a=null;e?a=h:"function"===typeof h&&(p.start=D(),a=h.apply(f,va(d,k,l)),p.end=D());if(b){J[d]=a;a=d;for(ca[a]=!0;(B[a]||[]).length;)B[a].shift()();delete B[a]}p.done=!0}var k=g||this;"function"===typeof d&&(h=d,d=A);b&&(d=d?d.replace(fa,""):"NONAME",V.hasOwnProperty(d)&&k.error(q(", reregistered by ",\nq(" by ",d+" already registered",V[d]),k.attribution),d),V[d]=k.attribution);for(var l=[],n=0;n<a.length;n++)l[n]=a[n].replace(fa,"");var p=ga[d||"anon"+ ++wa]={depend:l,registered:D(),namespace:k.namespace};c?m():ta(l,k.guardFatal(d,m));return{decorate:function(a){U[d]=k.guardFatal(d,a)}}}}function ha(a){return function(){var b=Array.prototype.slice.call(arguments);return{execute:C(b,!1,a,!1,this),register:C(b,!0,a,!1,this)}}}function W(a,b){return function(c,e){e||(e=c,c=A);var g=this.attribution;\nreturn function(){z.push(b||{attribution:g,name:c,logLevel:a});var d=e.apply(this,arguments);z.pop();return d}}}function K(a,b){this.load={js:da(this,!0),css:da(this)};H(this,"namespace",b);H(this,"attribution",a)}function ia(){h.body?p.trigger("a-bodyBegin"):setTimeout(ia,20)}function E(a,b){a.className=X(a,b)+" "+b}function X(a,b){return(" "+a.className+" ").split(" "+b+" ").join(" ").replace(/^ | $/g,"")}function ja(a){try{return a()}catch(b){return!1}}function L(){if(M){var a={w:f.innerWidth||\nm.clientWidth,h:f.innerHeight||m.clientHeight};5<Math.abs(a.w-Y.w)||50<a.h-Y.h?(Y=a,N=4,(a=k.mobile||k.tablet?450<a.w&&a.w>a.h:1250<=a.w)?E(m,"a-ws"):m.className=X(m,"a-ws")):0<N&&(N--,ka=setTimeout(L,16))}}function xa(a){(M=a===A?!M:!!a)&&L()}function ya(){return M}function r(a,b){return"sw:"+(b||"")+":"+a+":"}function la(){ma.forEach(function(a){G(a)})}function n(a){ma.push(a)}function na(a,b,c,e){if(c){b=l(/Chrome/i)&&!l(/Edge/i)&&!l(/OPR/i)&&!a.capabilities.isAmazonApp&&!l(new RegExp(Z+"bwv"+\nZ+"b"));var g=r(e,"browser"),d=r(e,"prod_mshop"),f=r(e,"beta_mshop");!a.capabilities.isAmazonApp&&c.browser&&b&&(n(g+"supported"),c.browser.action(g,e));!b&&c.browser&&n(g+"unsupported");c.prodMshop&&n(d+"unsupported");c.betaMshop&&n(f+"unsupported")}}"use strict";var O=Q.now=Q.now||function(){return+new Q},D=function(a){return a&&a.now?a.now.bind(a):O}(f.performance),za=D(),t=f.AmazonUIPageJS||f.P;if(t&&t.when&&t.register)throw Error("A copy of P has already been loaded on this page.");var v=f.ue;\nG();G("aui_build_date:3.19.8-2020-08-04");var R=[],S=!1,T;T=function(){for(var a=setTimeout(T,0),b=O();R.length;)if(R.shift()(),50<O()-b)return;clearTimeout(a);S=!1};var ca={},B={},ea={},I=!1;y(f,"beforeunload",function(){I=!0;setTimeout(function(){I=!1},1E4)});var fa=/^prv:/,V={},J={},U={},ga={},wa=0,Z=String.fromCharCode(92),F,z=[],oa=f.onerror;f.onerror=function(a,b,c,e,g){g&&"object"===typeof g||(g=Error(a,b,c),g.columnNumber=e,g.stack=b||c||e?q(Z,g.message,"at "+q(":",b,c,e)):A);var d=z.pop()||\n{};g.attribution=q(":",g.attribution||d.attribution,d.name);g.logLevel=d.logLevel;g.attribution&&console&&console.log&&console.log([g.logLevel||"ERROR",a,"thrown by",g.attribution].join(" "));z=[];oa&&(d=[].slice.call(arguments),d[4]=g,oa.apply(f,d))};K.prototype={logError:function(a,b,c,e){b={message:b,logLevel:c||"ERROR",attribution:q(":",this.attribution,e)};if(f.ueLogError)return f.ueLogError(a||b,a?b:null),!0;console&&console.error&&(console.log(b),console.error(a));return!1},error:function(a,\nb,c,e){a=Error(q(":",e,a,c));a.attribution=q(":",this.attribution,b);throw a;},guardError:W(),guardFatal:W("FATAL"),guardCurrent:function(a){var b=z[z.length-1];return b?W(b.logLevel,b).call(this,a):a},log:function(a,b,c){return this.logError(null,a,b,c)},declare:C([],!0,!0,!0),register:C([],!0),execute:C([]),AUI_BUILD_DATE:"3.19.8-2020-08-04",when:ha(),now:ha(!0),trigger:function(a,b,c){var e=O();this.declare(a,{data:b,pageElapsedTime:e-(f.aPageStart||NaN),triggerTime:e});c&&c.instrument&&F.when("prv:a-logTrigger").execute(function(b){b(a)})},\nhandleTriggers:function(){this.log("handleTriggers deprecated")},attributeErrors:function(a){return new K(a)},namespace:function(a,b){return new K(a,b)}};var p=H(f,"AmazonUIPageJS",new K);F=p.namespace("PageJS","AmazonUI");F.declare("prv:p-debug",ga);p.declare("p-recorder-events",[]);p.declare("p-recorder-stop",function(){});H(f,"P",p);ia();if(h.addEventListener){var pa;h.addEventListener("DOMContentLoaded",pa=function(){p.trigger("a-domready");h.removeEventListener("DOMContentLoaded",pa,!1)},!1)}var m=\nh.documentElement,aa=function(){var a=["O","ms","Moz","Webkit"],b=h.createElement("div");return{testGradients:function(){b.style.cssText="background-image:-webkit-gradient(linear,left top,right bottom,from(#1E4),to(white));background-image:-webkit-linear-gradient(left top,#1E4,white);background-image:linear-gradient(left top,#1E4,white);";return~b.style.backgroundImage.indexOf("gradient")},test:function(c){var e=c.charAt(0).toUpperCase()+c.substr(1);c=(a.join(e+" ")+e+" "+c).split(" ");for(e=c.length;e--;)if(""===\nb.style[c[e]])return!0;return!1},testTransform3d:function(){var a=!1;f.matchMedia&&(a=f.matchMedia("(-webkit-transform-3d)").matches);return a}}}(),t=m.className,qa=/(^| )a-mobile( |$)/.test(t),ra=/(^| )a-tablet( |$)/.test(t),k={audio:function(){return!!h.createElement("audio").canPlayType},video:function(){return!!h.createElement("video").canPlayType},canvas:function(){return!!h.createElement("canvas").getContext},svg:function(){return!!h.createElementNS&&!!h.createElementNS("http://www.w3.org/2000/svg",\n"svg").createSVGRect},offline:function(){return navigator.hasOwnProperty&&navigator.hasOwnProperty("onLine")&&navigator.onLine},dragDrop:function(){return"draggable"in h.createElement("span")},geolocation:function(){return!!navigator.geolocation},history:function(){return!(!f.history||!f.history.pushState)},webworker:function(){return!!f.Worker},autofocus:function(){return"autofocus"in h.createElement("input")},inputPlaceholder:function(){return"placeholder"in h.createElement("input")},textareaPlaceholder:function(){return"placeholder"in\nh.createElement("textarea")},localStorage:function(){return"localStorage"in f&&null!==f.localStorage},orientation:function(){return"orientation"in f},touch:function(){return"ontouchend"in h},gradients:function(){return aa.testGradients()},hires:function(){var a=f.devicePixelRatio&&1.5<=f.devicePixelRatio||f.matchMedia&&f.matchMedia("(min-resolution:144dpi)").matches;x("hiRes"+(qa?"Mobile":ra?"Tablet":"Desktop"),a?1:0);return a},transform3d:function(){return aa.testTransform3d()},touchScrolling:function(){return l(/Windowshop|android|OS ([5-9]|[1-9][0-9]+)([0-9]{1,2})+ like Mac OS X|Chrome|Silk|Firefox|Trident.+?; Touch/i)},\nios:function(){return l(/OS [1-9][0-9]*([0-9])+ like Mac OS X/i)&&!l(/trident|Edge/i)},android:function(){return l(/android.([1-9]|[L-Z])/i)&&!l(/trident|Edge/i)},mobile:function(){return qa},tablet:function(){return ra},rtl:function(){return"rtl"===m.dir}},u;for(u in k)k.hasOwnProperty(u)&&(k[u]=ja(k[u]));for(var ba="textShadow textStroke boxShadow borderRadius borderImage opacity transform transition".split(" "),P=0;P<ba.length;P++)k[ba[P]]=ja(function(){return aa.test(ba[P])});var M=!0,ka=0,\nY={w:0,h:0},N=4;L();y(f,"resize",function(){clearTimeout(ka);N=4;L()});var sa={getItem:function(a){try{return f.localStorage.getItem(a)}catch(b){}},setItem:function(a,b){try{return f.localStorage.setItem(a,b)}catch(c){}}};m.className=X(m,"a-no-js");E(m,"a-js");!l(/OS 1-8+ like Mac OS X/i)||f.navigator.standalone||l(/safari/i)||E(m,"a-ember");t=[];for(u in k)k.hasOwnProperty(u)&&k[u]&&t.push("a-"+u.replace(/([A-Z])/g,function(a){return"-"+a.toLowerCase()}));E(m,t.join(" "));m.setAttribute("data-aui-build-date",\n"3.19.8-2020-08-04");p.register("p-detect",function(){return{capabilities:k,localStorage:k.localStorage&&sa,toggleResponsiveGrid:xa,responsiveGridEnabled:ya}});l(/UCBrowser/i)||k.localStorage&&E(m,sa.getItem("a-font-class"));p.declare("a-event-revised-handling",!1);var w;try{w=navigator.serviceWorker}catch(a){G("sw:nav_err")}w&&(y(w,"message",function(a){a&&a.data&&x(a.data.k,a.data.v)}),w.controller&&w.controller.postMessage("MSG-RDY"));var ma=[];(function(a){var b=a.reg,c=a.unreg;w&&w.getRegistrations?\n(F.when("A","a-util").execute(function(a,b){na(a,b,c,"unregister")}),y(f,"load",function(){F.when("A","a-util").execute(function(a,c){na(a,c,b,"register");la()})})):(b&&(b.browser&&n(r("register","browser")+"unsupported"),b.prodMshop&&n(r("register","prod_mshop")+"unsupported"),b.betaMshop&&n(r("register","beta_mshop")+"unsupported")),c&&(c.browser&&n(r("unregister","browser")+"unsupported"),c.prodMshop&&n(r("unregister","prod_mshop")+"unsupported"),c.betaMshop&&n(r("unregister","beta_mshop")+"unsupported")),\nla())})({reg:{},unreg:{}});p.declare("a-fix-event-off",!1);x("pagejs:pkgExecTime",D()-za)})(window,document,Date);\n (window.AmazonUIPageJS ? AmazonUIPageJS : P).load.js('https://images-na.ssl-images-amazon.com/images/I/61-6nKPKyWL._RC|11-BZEJ8lnL.js,61GQ9IdK7HL.js,21Of0-9HPCL.js,012FVc3131L.js,119KAWlHU6L.js,51CF7BmbF2L.js,11AHlQhPRjL.js,016iHgpF74L.js,11aNYFFS5hL.js,116tgw9TSaL.js,211-p4GRUCL.js,01PoLXBDXWL.js,6131jEFdnAL.js,41FEs0XB89L.js,11BOgvnnntL.js,31UWuPgtTtL.js,01rpauTep4L.js,01iyxuSGj4L.js,01l8233efsL.js_.js?AUIClients/AmazonUI\');\n</script>\n\n <style>\n .chimera-body-container {\n width: 27em !important;\n margin-left: auto;\n margin-right: auto;\n }\n </style>\n\n

<script type="a-state" data-a-state="{"key":"a-wlab-states"}">{}</script>
\n\n\n\n\n \n\n\n
\n \n \n \n \n\n \n \n \n \n \n\n \n \n \n \n \n\n \n \n
\n\n
\n
\n\n\n\n

JavaScript Is Disabled

This site requires JavaScript to function correctly. Please enable JavaScript on your browser to continue.
\n
\n
\n
To continue, approve the notification sent to:
\n
\n\n
\n
Email address
\n
s*****@gmail.com\n
\n\n
\n\n
\n\n\n\n<input type='hidden' name='csrfToken' value='gaBl0cILhj2F32SlzoowpGj2FOmsCSUj3D' />\n
\n<style>\n\n .a-no-js .transaction-approval-js-enabled {\n display: none;\n }\n\n</style>\n\n\n
\n\n\n\nDidn't receive it?\n\n
\n\n\n\n<input type='hidden' name='csrfToken' value='gaBl0cILhj2F32SlzoowpGj2FOmsCSUj3D' />
\n\n\n
\n
\n\n
\n<style>\n\n .a-no-js .transaction-approval-js-enabled {\n display: none;\n }\n\n</style>\n\n\n\n
\nDid you already respond?\n\n
\n
Need help? Please contact Customer Service.
\n<script>\n 'use strict';\n\n P.when('A', 'ready').execute(function(A) {\n var $ = A.$;\n\n // Do polling every 5 seconds, this can be changed later if needed\n $('#pollingForm').ready(function() {\n setTimeout(polling, 5000);\n });\n\n function polling() {\n A.ajax($('#pollingForm').attr('action'), {\n method: 'GET',\n params: $('#pollingForm').serializeArray(),\n success: handlePollingResponse,\n error: handlePollingError\n });\n }\n\n function handlePollingResponse(response) {\n $('#channelDetails').html($(response).find('#updatedChannelDetails').html());\n var transactionApprovalStatus = $(response).find("input[name='transactionApprovalStatus']").val();\n\n switch (transactionApprovalStatus) {\n case 'TransactionPending':\n setTimeout(polling, 5000);\n break;\n\n case 'TransactionResponded':\n case 'TransactionExpired':\n $('#resend-transaction-approval').hide();\n setTimeout(polling, 5000);\n break;\n\n case 'TransactionCompleted':\n case 'TransactionCompletionTimeout':\n window.location.replace(decodeURIComponent(getQueryParameters(window.location.href)['openid.return_to']));\n break;\n\n default:\n window.location.reload();\n }\n }\n\n function getQueryParameters(url) {\n var paramPairs = {};\n var parameters = url.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m, key, value) {\n paramPairs[key] = value;\n });\n\n return paramPairs;\n }\n\n function handlePollingError() {\n window.location.reload();\n }\n });\n\n</script>\n<script>\n P.when('A', 'ready').execute(function(A) {\n var $ = A.$;\n\n $('#resend-approval-link').click(function() {\n $('#resend-approval-form').submit();\n });\n });\n</script>\n\n<script>\n P.when('A', 'ready').register('resendApprovalLinksTimer', function(A) {\n function updateTime(timeleft, updateMsg) {\n var resultMsg = updateMsg.split('+timeleft+');\n var endResult = resultMsg[0].split('"').join('') +timeleft+ resultMsg[1].split('"').join('');\n A.$('#timer').html(endResult);\n }\n\n function onComplete(completeMsg) {\n A.$('#timer').html(completeMsg);\n A.$("#resend-approval-link").removeClass("transaction-approval-link-disabled");\n }\n\n function Timer(time, updateMsg, completeMsg) {\n var start = Date.now();\n var interval = setInterval(function() {\n var currTime = Date.now();\n var timePassed = currTime - start;\n var timeRemaining = time - timePassed;\n\n if (timeRemaining <= 0) {\n clearInterval(interval);\n onComplete(completeMsg);\n } else {\n updateTime(Math.floor(timeRemaining / 1000), updateMsg);\n }\n }, 100);\n }\n\n function createTimer(timeInMillis, updateMsg, completeMsg) {\n return new Timer(timeInMillis, updateMsg, completeMsg);\n }\n\n return {\n createTimer: createTimer\n };\n });\n</script>\n\n<script>\n P.when('A', 'resendApprovalLinksTimer', 'ready').execute(function(A, resendApprovalLinksTimer) {\n if (true) {\n resendApprovalLinksTimer.createTimer(1599054941426 - Date.now(), 'Notification sent. This may take a minute to arrive. If needed, you may request a new notification in " +timeleft+ " second(s).', 'You may now request an additional notification, if needed.');\n A.$("#resend-approval-link").addClass("transaction-approval-link-disabled");\n }\n });\n</script>\n\n<style>\n\n .transaction-approval-word-break {\n word-break: break-word;\n }\n\n .transaction-approval-link-disabled {\n pointer-events: none;\n opacity: 0.5;\n }\n\n</style>\n
\n\n\n\n\n<style>\n .auth-footer-separator {\n display: inline-block;\n width: 20px;\n }\n</style>\n\n
\n\n\n
'

error in AmazonMusic initialization

re.sub(r'^[^{]*',` '', re.sub(r';$', '', line))

on line 107 of amazonmusic.py returns absolutely nothing.
I believe this is the only thing causing problems. I was wondering if anyone could shed some light on the situation.

Error opening album if originalReleaseDate is of unexpected type

If you try to open ASIN B07NP1QCDC, you'll get the following error in line 551:

TypeError: unsupported operand type(s) for /: 'NoneType' and 'int'

Line 551 is: self.releaseDate = data['originalReleaseDate'] / 1000

Obviously the value of originalReleaseDate cannot be divided due to an illegal type.

I am not a python expert, otherwise I would fix it myself. But it seems to be an easily to solve issue.

BTW: commenting the line out works, but then there is no originalReleaseDate at all, of course.

IndexError: list index out of range

Traceback (most recent call last):
File "play-album.py", line 32, in
album = am.get_album(asin)
File "C:\Users\estgiug\Desktop\amazon-music-master\amazonmusic.py", line 248, in get_album
self.call(
IndexError: list index out of range

Import playlists/tracks into Amazon Music?

Is such feature implemented already or is it in roadmap?
I mean import of song names from CSV or other text format and automatic building of playlist in Amazon Library.

Windows has no HOME environment variable

i would suggest to use a local file indead of home as fallback.

cookie_path = cookies or '{}/.amazonmusic-cookies.dat'.format(os.environ['HOME'])

would look like this:

local = os.path.dirname(os.path.realpath(__file__))
cookie_path = cookies or '{}/.amazonmusic-cookies.dat'.format(os.environ.get('HOME',  local))

Support downloading tracks I've bought?

I'm trying to find a way to basically have a cron that downloads all of the music that I've bought on Amazon to my NAS. Can this expose API to give a URL to download files that I've purchased?

raise Exception("Unable to find appConfig in {}".format(r.content))

Traceback (most recent call last):
File "play-playlist.py", line 27, in
am = AmazonMusic(credentials = lambda: [input('Email: '), getpass('Amazon password: ')])
File "C:\Users\estgiug\Desktop\amazon-music-master\amazonmusic.py", line 111, in init
raise Exception("Unable to find appConfig in {}".format(r.content))
Exception: Unable to find appConfig in b'\n<!doctype html>\n\n\n <title>Libreria musicale di Amazon</title>\n <style type="text/css">\n body {\n background-color: white;\n background-image: none;\n filter: none;\n overflow: scroll;\n font: 16px/1.5 "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n text-rendering: optimizeLegibility;\n color: #7c8289;\n letter-spacing: .5px;\n }\n\n #contentContainer {\n padding:10px;\n margin-top:80px;\n text-align: center;\n }\n\n .playerIconHeadphonesError {\n margin-top: 2rem;\n font-size: 14rem;\n }\n\n .mainErrorText {\n font-size: 1.5rem;\n margin-top: 3rem;\n }\n\n .secondaryText {\n font-size: 1.5rem;\n margin-top: 1rem;\n }\n\n .secondaryText {\n font-size: 1rem;\n }\n\n .mainErrorText, .secondaryText {\n color: #000;\n margin-bottom: 0.5rem;\n display: block;\n }\n\n .amazonMusicLogo {\n background-image: url("https://m.media-amazon.com/images/G/01/digital/music/player/web/AmazonMusicLogoPurple.svg");\n background-repeat: no-repeat;\n height: 100px;\n width: 325px;\n margin: 0px auto;\n }\n\n a {\n color: rgba(253,124,2,1);\n }\n </style>\n\n\n

\n Stiamo riscontrando un errore.\n \n Ci scusiamo. Il servizio sar\xc3\xa0 disponibile presto.\n \n Indietro\n
\n
\n \n
\n
\n
\n
\n \n
\n\n'

Unable to find appConfig

For some reasons, there is this error raised by

if app_config is None:
                raise Exception(
                    "Unable to find appConfig in {}".format(r.content))

Having trouble playing album

Hi,

Thank you for putting this library together. I'm really excited to try to use it.

I was able to use the sample search.py to look up a particular artist album. That worked great. Then I used the returned album_id as an argument to play-album.py

PYTHONPATH=. python examples/play-album.py B00UP0VOF0

It fails with this error message (I tried different album Ids with the same result):

Traceback (most recent call last):
File "examples/play-album.py", line 32, in
album = am.get_album(asin)
File "/home/trevor/amazon-music/amazonmusic.py", line 236, in get_album
)['albumList'][0]
IndexError: list index out of range

I'm an Amazon prime customer, in Canada, if it helps. I'm running on Ubuntu 16.04, using python 2.

Thank you!

Unable to authenticate for users outside US

The login points to music.amazon.com for authentication however, me as a user from India, my music is not accessible from amazon.com instead it's accessible on amazon.in

Should do something to dynamically point to the correct endpoint for every country or else allow user to manually choose login api endpoint

Feature: AmazonMusic.tracks -> list all songs

I'm working on it, but it isn't really easy. There are two types of "get-stream-url" - queries. i had to implement both. but i don't know if it works. somebody should test it on my fork when i pushed it...

Trouble with VLC launch

New to Python, but not home automation. Would love to use this...but I need some help...

My setup is:
-Running Win 7-32 bit.
-Python 3.7 installed per default install; environment variable added to path.
-Installed via a CMD window "pip install requests" & also "pip install beatifulsoup4 " <=verified good install.
-Added VLC to my path <=so it can work from any path

After modifying the "play-station.py" file on line number 37 to be:
os.system("vlc --play-and-stop '%s'" % t.stream_url) <= removed "c" on "cvlc", and kept VLC window
from :
os.system("cvlc --play-and-exit '%s'" % t.stream_url) <= cvlc is for Linux...right?

I get the following error message from VLC:
Your input can't be opened:
VLC is unable to open the MRL ''https://d29r7idq0wxsaz.cloudfront.net/DigitalMusicDeliveryService/HPS.m3u8?m=m'. Check the log for details.

So, recapping...From a command prompt window, the script prompts me from my Amazon email, and also password. That part works, and then it gives me the following out put (which looks like it is working):

Art: https://images-na.ssl-images-amazon.com/images/G/01/Gotham/Genre_Stations_U
K/PS0001_eudmvd_UKClassicSoul.jpg
Playing station Classic Soul...
Playing September by Earth Wind & Fire from Greatest Hits [Earth Wind & Fire]...

So, what is wrong with the music stream amazon is sending to my VLC player?

From my VLC log file:

main debug: resyncing on (null)'https://d29r7idq0wxsiz.cloudfront.net/DigitalMusicDeliveryService/HPS.m3u8
main debug: (null)'https://d29r7idq0wxsiz.cloudfront.net/DigitalMusicDeliveryService/HPS.m3u8 is at 0
main debug: creating new input thread
main debug: Creating an input for '(null)'https://d29r7idq0wxsiz.cloudfront.net/DigitalMusicDeliveryService/HPS.m3u8'
main debug: requesting art for new input thread
main debug: using timeshift granularity of 50 MiB
main debug: using timeshift path: C:\Users\Smarty\AppData\Local\Temp
main debug: 'https://d29r7idq0wxsiz.cloudfront.net/DigitalMusicDeliveryService/HPS.m3u8?m=m' gives access 'https' demux any' path d29r7idq0wxsiz.cloudfront.net/DigitalMusicDeliveryService/HPS.m3u8?m=m'
main debug: creating demux: access=''https' demux='any' location='d29r7idq0wxsiz.cloudfront.net/DigitalMusicDeliveryService/HPS.m3u8?m=m' file='\d29r7idq0wxsiz.cloudfront.net\DigitalMusicDeliveryService\HPS.m3u8'
main debug: looking for access_demux module matching "'https": 15 candidates
main debug: no access_demux modules matched
main debug: creating access: 'https://d29r7idq0wxsiz.cloudfront.net/DigitalMusicDeliveryService/HPS.m3u8?m=m
main debug: (path: \d29r7idq0wxsiz.cloudfront.net\DigitalMusicDeliveryService\HPS.m3u8)
main debug: looking for access

Raspberry Jukebox playing Amazon music

Hi @Jaffa ,

maybe you have heared about this great DIY project by @MiczFlor
https://github.com/MiczFlor/RPi-Jukebox-RFID
It's a great jukebox that uses RFID cards to trigger either locally stored audio files or streams music from spotify.
I would love to see it playing music from amazon too. I think your project could be the key to this.
Unfortunately I don't have (enough) coding skill to somehow get this rolling...
Do you have ideas how these two great projects could be merged and benefit from each other?
Is this even possible (technically) to use your code "embedded" in a bigger project?

Cannot get past captcha

Is there any additional information I can provide? Any suggestions?

Exception: Unable to handle captcha: [<source data-refresh-url="/ap/captcha?appAction=SIGNIN&amp;captchaType=audio" id="mp3-file"

No longer working?

@Jaffa

Does this solution still work? I installed the requred libraries: Requests and Beautiful Soup on Python 2.7 and used the most basic script (code below). However, I keep getting the below errors when executing. Is there anything more that I have to do to get it to work correctly? I have an amazon unlimited account in United States. PS: I need to do this under Python 2.7. Hopefully this project hasn't been abandoned.

Traceback (most recent call last):
File "c:/Users/Michael/OneDrive/Dev/Projects/Python/test-amazonmusic.py", line 12, in
am = AmazonMusic(credentials=['amazonusername', 'password'])
File "c:\Users\Michael\OneDrive\Dev\Projects\Python\amazonmusic.py", line 107, in init
app_config = json.loads(re.sub(r'^[^{]*', '', re.sub(r';$', '', line)))
File "C:\Users\Michael\AppData\Local\Programs\Python\python27\lib\json_init_.py", line 339, in loads
return _default_decoder.decode(s)
File "C:\Users\Michael\AppData\Local\Programs\Python\python27\lib\json\decoder.py", line 364, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "C:\Users\Michael\AppData\Local\Programs\Python\python27\lib\json\decoder.py", line 382, in raw_decode
raise ValueError("No JSON object could be decoded")
ValueError: No JSON object could be decoded

from amazonmusic import AmazonMusic
import os

am = AmazonMusic(credentials=[myamazonemailaddress', 'mypassword'])

station = am.create_station('MICHAEL JACKSON')
print('Playing station {0}...'.format(station.name))

for t in station.tracks:
    print('Playing {0} by {1} from {2} [{3}]...'.format(t.name, t.artist, t.album, t.albumArtist))
    os.system('cvlc --play-and-exit "{0}"'.format(t.getUrl()))

List history of tracks played

Is it possible to export the list of songs that I’ve played along with their time stamps?

I didn’t see a mention of this in the readme so not sure if this can be done.

Since there isn’t a last.fm scrobbler that works with Prime Music on iOS, I’d like to use this library to build something that can scrobble to last.fm

Thanks!

CONTENT_NOT_VALID

Art: https://images-na.ssl-images-amazon.com/images/I/71Uwz5YJlWL._CLa%7C1000,1000%7C61blNmsIFwL.png,719v1WesHcL.png,71J8+2zMNjL.png%7C0,0,500,500+500,0,500,500+0,500,500,500+500,500,500,500_BG34,34,34L.png
Playing station Classic Soul...
Playing Feeling Good by Nina Simone from Feeling Good [Nina Simone]...
Traceback (most recent call last):
File "play-station.py", line 37, in
os.system("cvlc --play-and-exit '%s'" % t.stream_url)
File "C:\Users\estgiug\Desktop\amazon-music-master\amazonmusic.py", line 690, in stream_url
self._url = stream_json['contentResponse']['urlList'][0]
KeyError: 'contentResponse not found in {"__type": "com.amazon.digitalmusiclocator#BadRequestException", "errorCode": "CONTENT_NOT_VALID", "message": "InvalidContentId"}'

Can I search music with track name and artist name?

Hi!

Thanks for the great work!
All other music libraries like apple, spotify, deezer and many more provide apis to search with either track name or artist, or with both.
I am curious to know whether amazon-music also provides that search feature or not.

Regards

Great repo

Please provide more attributes etc :)

Then we can create our own android app or linux desktop app which works better x)

API out of date

appContext is now applicationContextConfiguration

This fixes fetching the track info, but the Track function to fetch the URLs to play is also out of date and non-functional

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.