Hello Amazon Cloud Player via Python

It plays randomly one song of all in your Amazon Cloud Player's library. You can listen to the music with a line typing. Have a lot of fun!

Update 07.28.2011

  • changed sound library from pygame to pymedia.

Requirements

  • python (I recommend 2.6.x or higher, but not 3.x.)
  • pygame
  • pymedia
  • simplejson (If your python is lower than 2.5.x.)

Known Issues

  • It's tested in only MP3.
  • It starts to play after downloading entire data. (Not streaming)
  • 'pygame.mixer.quit()' hangs on my PC. (Why?)
administrator@CF-T4 ~ $ uname -a
Linux CF-T4 2.6.35-22-generic #33-Ubuntu SMP Sun Sep 19 20:34:50 UTC 2010 i686 GNU/Linux
administrator@CF-T4 ~ $ dpkg -l|grep "pygame"
ii  python-pygame                         1.9.1release-0ubuntu1                             SDL bindings for games development in Python
administrator@CF-T4 ~ $ python -c "import pymedia;print pymedia.__version__"
1.3.7.0

Usage

administrator@CF-T4 ~ $ ./amusicplay.py 
./amusicplay.py EMAIL PASSWD
administrator@CF-T4 ~ $ ./amusicplay.py someone@example.com YourPassword

Source Code of 'amusicplay.py'

This is MIT License.

#!/usr/bin/env python

import sys,re,time
import urllib,urllib2,cookielib
import xml.dom.minidom
#import cStringIO,random

try:
  import json
except ImportError,e:
  import simplejson as json

#import pygame
import random
import pymedia.audio.acodec
import pymedia.muxer
import pymedia.audio.sound

if len(sys.argv)!=3:
  sys.stderr.write("%s EMAIL PASSWD\n"%sys.argv[0])
  sys.exit(2)

_,email,passwd=sys.argv

urls=[
  "http://www.amazon.com/",
  "http://www.amazon.com/gp/dmusic/mp3/player/",
  "https://www.amazon.com/cirrus/",
]

cj = cookielib.CookieJar() 
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
opener.addheaders = [('User-agent', '')]
res=opener.open(urls[0])
#res=opener.open(urls[0])

res=opener.open(urls[1])
html=re.sub(r"\r|\n"," ",re.sub(r"\s{2,}"," ",res.read()))
form=re.search('<form name="signIn".*?</form>',html).group()
urls.append(re.search('action=".*?"',form).group()[8:-1])
form=re.sub('onsubmit=".*?"|action=".*?"',"",form)
inputs="\n".join(re.findall("<input .*?/>",form))

dom=xml.dom.minidom.parseString(
  re.match("<form.*?>",form).group()+inputs+"</form>")

params={}
for tag in dom.getElementsByTagName("input"):
  params[tag.getAttribute("name")]=tag.getAttribute("value")

params["email"]=email
params["password"]=passwd

res = opener.open(urls[-1],urllib.urlencode(params))
html=re.sub(r"\r|\n"," ",re.sub(r"\s{2,}"," ",res.read()))
javascript="\n".join(re.findall("<script type=.*?</script>",html))

customerId = re.search(r"amznMusic\.customerId.*?;",javascript).group().split("'")[1]
deviceId = re.search(r"window\.amznMusic\.did.*?;",javascript).group().split("'")[1]
deviceType = re.search(r"window\.amznMusic\.dtid.*?;",javascript).group().split("'")[1]
x_adp_token = re.search(r"window\.amznMusic\.tid.*?;",javascript).group().split("'")[1]
opener.addheaders.append(("x-adp-token",x_adp_token))

query={
  "searchReturnType":"TRACKS",
  "searchCriteria.member.1.attributeName":"keywords",
  "searchCriteria.member.1.comparisonType":"LIKE",
  "searchCriteria.member.1.attributeValue":"",
  "searchCriteria.member.2.attributeName":"assetType",
  "searchCriteria.member.2.comparisonType":"EQUALS",
  "searchCriteria.member.2.attributeValue":"AUDIO",
  "searchCriteria.member.3.attributeName":"status",
  "searchCriteria.member.3.comparisonType":"EQUALS",
  "searchCriteria.member.3.attributeValue":"AVAILABLE",
  "albumArtUrlsRedirects":"false",
  "distinctOnly":"false",
  "countOnly":"false",
  "sortCriteriaList":"",
  "maxResults":"100",
  "nextResultsToken":"",
  "caller":"getServerSongs",
  "Operation":"searchLibrary",
  "selectedColumns.member.1":"albumArtistName",
  "selectedColumns.member.2":"albumName",
  "selectedColumns.member.3":"artistName",
  "selectedColumns.member.4":"assetType",
  "selectedColumns.member.5":"duration",
  "selectedColumns.member.6":"objectId",
  "selectedColumns.member.7":"sortAlbumArtistName",
  "selectedColumns.member.8":"sortAlbumName",
  "selectedColumns.member.9":"sortArtistName",
  "selectedColumns.member.10":"title",
  "selectedColumns.member.11":"status",
  "selectedColumns.member.12":"trackStatus",
  "selectedColumns.member.13":"extension",
  "sortCriteriaList.member.1.sortColumn":"sortTitle",
  "sortCriteriaList.member.1.sortType":"ASC",
  "ContentType":"JSON",
  "customerInfo.customerId":customerId,
  "customerInfo.deviceId":deviceId,
  "customerInfo.deviceType":deviceType
}

res = opener.open(urls[2],urllib.urlencode(query))
all_tracks = [x["metadata"] for x in json.loads(res.read())\
  ["searchLibraryResponse"]["searchLibraryResult"]["searchReturnItemList"]]

index=random.randint(0,len(all_tracks)-1)
print "%s / %s"%(all_tracks[index]["title"],all_tracks[index]["artistName"])

query={
  "trackIdList.member.1":all_tracks[index]["objectId"],
  "Operation":"getStreamUrls",
  "urlExpiration":"",
  "https":"true",
  "caller":"player.playSong",
  "ContentType":"JSON",
  "customerInfo.customerId":customerId,
  "customerInfo.deviceId":deviceId,
  "customerInfo.deviceType":deviceType
}

res = opener.open(urls[2],urllib.urlencode(query))
res = opener.open(json.loads(res.read())["getStreamUrlsResponse"]\
  ["getStreamUrlsResult"]["trackStreamUrlList"][0]["url"])
ext=all_tracks[index]["extension"]

snd=dec=None
dm = pymedia.muxer.Demuxer(ext)
s = res.read(1024*200)
while len(s):
  frames = dm.parse(s)
  if not dec:
    dec = pymedia.audio.acodec.Decoder(dm.streams[0])
  for fr in frames:
    r= dec.decode(fr[1])
    if not snd:
      snd= pymedia.audio.sound.Output(r.sample_rate,r.channels,
                                      pymedia.audio.sound.AFMT_S16_LE)
    snd.play(r.data)
  s=res.read(len(s))

"""
audio=cStringIO.StringIO(res.read())

pygame.mixer.pre_init(44100, -16, 2, 1024*3)
pygame.init()
pygame.mixer.music.load(audio)
try:
  pygame.mixer.music.play()
  while pygame.mixer.music.get_busy():
    time.sleep(1)
except KeyboardInterrupt:
  pygame.mixer.music.stop()

pygame.mixer.quit()
pygame.quit()
"""

See Also