#!/usr/bin/env python
# devloop.lyua.org 08/2008
# Download and dump the Entire Library playlist as a Python list of dictionnaries
import urllib, urllib2, cookielib, random
import sys, socket, os

# >> Please modify account information <<
account={'login':'toto','password':'toto'}

cj = cookielib.LWPCookieJar()

opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cj))
urllib2.install_opener(opener)

print "Connection on the server..."
# Get our PHPSESSID
req=urllib2.Request("http://www.anywhere.fm/")
socket.setdefaulttimeout(6)
try:
  fd=urllib2.urlopen(req)
except IOError:
  print "Error getting url"
  sys.exit(1)

# Hardcoded initial Unique Request ID : works! :)
urid=1218964000
# Open a session with account information
req = urllib2.Request("http://music.anywhere.fm/account/login?_unique_request_id_="+str(urid),urllib.urlencode(account))
try:
  fd=urllib2.urlopen(req)
  htmlSource=fd.read()
except IOError:
  print "Error getting url"
  sys.exit(1)
except socket.timeout:
  print "timeout error"
  sys.exit(1)

if htmlSource.strip()!="<success>true</success>":
  print "Warning: Connexion error! Check the credentials!"
  print "Using default user_id (demo)"
else:
  print "Connexion successfull!"

urid+=1
# Get our user_id
req=urllib2.Request("http://music.anywhere.fm/account/get_current_user?_unique_request_id_="+str(urid))
try:
  fd=urllib2.urlopen(req)
  htmlSource=fd.read()
except IOError:
  print "Error getting url"
  sys.exit(1)
except socket.timeout:
  print "timeout error"
  sys.exit(1)

user_id=[q.strip() for q in htmlSource.split("\n") if q.find("user_id")>=0][0].split('>')[1].split('<')[0]
print "user_id =",user_id

# ! required for AMF queries, don't remove !
session_id=cj._cookies['music.anywhere.fm']['/']['auth_session_id'].value

# Now let's go AMF :p
# You can modify the user_id here to get another playlist
#user_id=46
import pyamf
from pyamf.remoting import client
from pyamf.flex import messaging
from pyamf import remoting
from pyamf import util
import uuid
from pyamf.amf3 import Decoder
from string import maketrans

in_string="".join([chr(i) for i in range(126,256)])
out_string="_"*130
trans=maketrans(in_string,out_string)

def my_readString(object, use_references=True):
  """
  Reads and returns a string from the stream.

  @type use_references: C{bool}
  @param use_references:
  """
  def readLength():
      x = object.readUnsignedInteger()

      return (x >> 1, x & 1 == 0)

  length, is_reference = readLength()

  if use_references and is_reference:
      return object.context.getString(length)

  buf = object.stream.read(length)

#  print buf.encode("hex_codec")
  try:
    result = unicode(buf, "utf8")
  except UnicodeDecodeError:
    buf=buf.translate(trans)
    result = unicode(buf, "utf8")

  if len(result) != 0 and use_references:
      object.context.addString(result)

  return result

print "Hooking the PyAMF Decoder"
sav_readString=Decoder.readString
Decoder.readString=my_readString

urid+=1
# Get the entire playlist of the user
url='http://www.anywhere.fm/amfphp/gateway.php?_unique_request_id_='+str(urid)
gw = client.RemotingService(url,pyamf.AMF0,pyamf.ClientTypes.Flash9)
message = messaging.RemotingMessage(operation=u'get_songs_for_user_playlists',
    source=u'BlazingFast.DBQueries',
    timestamp=0,
    destination=u'amf',
    clientId=None,
    headers={u'DSEndpoint':None,u'DSId': u'nil'},
    timeToLive=0,
    messageId=unicode(uuid.uuid4()),
    messageRefType=u'flex.messaging.messages.RemotingMessage',
    body=[unicode(session_id),user_id,True,[user_id],[200],[u'0']])
gw.addRequest('null', message)

# Encode and inject
print "Getting the Entire Library playlist..."
x=remoting.encode(gw.getAMFRequest(gw.requests)).getvalue()
xamf =  {'Content-Type' : 'application/x-amf'}
req=urllib2.Request(url,data=x,headers=xamf)
socket.setdefaulttimeout(6)
try:
  fd=urllib2.urlopen(req)
  htmlSource=fd.read()
except IOError:
  print "Error getting url"
  sys.exit(1)

library=remoting.decode(htmlSource)
fdlib=open("library.py","w")
fdlib.write("library="+str(library['/1'].body.body[0]))
fdlib.close()
print "Library dumped! :)"
