Lire directement la musique de Anywhere.FM : ça marche (presque)
Sunday, 17. August 2008, 20:19:00
Je me suis lancé aujourd'hui dans la "pratique" en écrivant quelques lignes de code et les résultats sont pour le moins encourageants
Je me suis orienté naturellement vers les modules urllib2 et cookielib de Python que j'avais utilisé pour Wapiti.
Les premières étapes se sont réalisées sans problème (envoies de données par GET ou POST, utilisation d'une "boîte à cookies"
Pour la seconde étape j'avais le choix entre utiliser les capacitées de PyAMF à effectuer les requêtes mais en devant injecter mes entêtes HTTP ou rester sur l'utilisation du module urllib2 et injecter les données encodées à l'aide de PyAMF.
J'ai finalement opté pour la seconde méthode, même s'il m'a fallu un peu de temps pour comprendre quels arguments passer à quelles fonctions. Pour résumer j'utilise seulement les fonctionnalitées de création d'objet (plus propre) et d'encodeur/décodeur de PyAMF et toute la partie communication est réalisée par urllib2.
J'ai d'abord implémenté les étapes que j'avais observé au complet puis j'ai ensuite commenté certaines étapes dont l'utilité était douteuse.
Au final les réponses aux questions précédentes sont :
-
_unique_request_id_ est aléatoire. On peut même le définir nous même au début. Reprendre la même valeur à chaque nouvelle session ne semble pas poser de problème, même sur des intervalles de temps rapprochés. Je n'ai pas vérifié si on pouvait se passer de l'incrémentation d'une requête à une autre
- Les fameuses variabes __qca et __qcb définies par le biais du Javascript sur le serveur quantserve semblent totalement superflues. Ne pas les utiliser n'entrave en rien la communication avec Anywhere.FM. De toute évidence elles sont utilisées uniquement à des fins de tracking
-
tracker_id n'a pas d'utilité, malgré qu'il soit explicitement défini (une requête est générée uniquement à cet effet). Il pourrait s'agir d'une fonctionnalitée que les administrateurs n'ont pas encore pû implémenté mais à venir ?!
- Certains arguments passés à get_songs_for_user_playlists restent un mystère, toutefois on n'a pas besoin d'en savoir plus pour accèder à la librairie complète d'un utilisateur
Le code que vous pourrez trouver ici : PyAnywhereFM.py et sur pastebin.com n'est pas totalement fonctionnel.
En effet si on parvient bien à ouvrir une session sur le site, à effectuer des requêtes AMF et obtenir les résultats, on ne parvientpas pour le moment à décoder les réponses AMF à cause d'erreurs de décodage UTF-8. A l'heure actuelle je ne saurais pas dire si le problème vient de Anywhere.FM, de PyAMF ou encore de Python...
Il est tout de même possible d'obtenir un jeton valide pour accèder à un titre dont on connait par avance le "master_id" et le "song_ressource_id" (paramêtres qui sont fixes).
Le code tente de se connecter avec les identifiants présents dans la source (à vous d'y insérer les votres) ou fonctionnera avec l'utilisateur par défaut (démo, id = 89 comme vu la dernière fois) si les identifiants sont invalides. Il va ensuite lire un titre dans ma librairie à l'aide de mplayer.
Vous pouvez utiliser un sniffeur comme Wireshark pour comprendre ce qui se passe en fond lors de l'utilisation du script. Il faut noter toutefois que l'utilisateur "demo" a une librairie vide, c'est pour cela qu'il est possible de décommenter une ligne fixant le user_id à 46 (correspondant au compte "Free Music")
L'étape restante consiste donc à extraire les données des réponses AMF obtenues, ce qui ne devrait pas être trop difficile puisque le "master_id" et le "song_ressource_id" sont envoyés comme des chaines de caractères et non comme des entiers.
Tout cela montre qu'il est assez aisé (le code fait 129 lignes une fois les commentaires et les lignes vides retirées) de télécharger de la musique sur Anywhere.FM et malgré qu'il n'y ait pas de système permettant de rechercher un titre en particulier, il serait possible de générer une base de données des titres disponibles en récupérant les profils puis les listes de lecture des utilisateurs du site. Evidemment ça prendrait du temps, mais ce serait toujours plus rapide que de fouiller par le biais de l'interface web du site








How to use Quote function: