Google Play Music (GPM) is a service proposed by Google to listen musics online (like Spotify, Deezer, …). Having a premium subscription, I can listen a lot of music by using the online service, but when I have no internet connection… I cannot 😦 . So I wanted to download the music ^^.
> This might be illegal, so, I used this situation to explain the process to use Pharo to download musics from GPM but you must not use this for real.
My idea is simple: if I can listen to musics from my computer, it means my computer has to download the music. I know that musics coming from GPM are in the mp3 format. So the process to download the music is simple:
- Access the my GPM library.
- For each music download the corresponding mp3 file.
- Set the metadata of each music.
Access my GPM library
There is no official API for GPM service, however, the gmusicapi python project has been developed to create an unofficial API. This API allows us to access every element of our GPM library.
PyBridge allows us to use python language in Pharo. So, I’ll use it to load and use the unofficial GPM API.
Set up PyBridge
PyBridge is currently a work in progress and consequently requires a little set up. One needs to download the server project and the Pharo client project.
For the Pharo client project, it is super easy. I only need to download the project from GitHub and install the baseline:
Metacello new baseline: 'PyBridge'; repository: 'github://aranega/pybridge/src'; load
For the Server project, the project is inside the
python branch of the git repository. It requires
pipenv to simply setup python vritual environments. So clone it in another folder and create a virtualenv by doing a simple:
$ pipenv install
Then, install the
gmusicapi and run the server by executing the following commands:
$ pipenv shell (pybridge) $ pip install gmusicapi (pybridge) $ python server.py
Congratulations! You have correctly set up
PyBridge to use the
Log in GPM
Before using the library, I need to log in inside GPM. To do so, I will use
gmusicapi. The usage of the python library in Pharo is pretty forward as PyBridge exposes python objects in a Smalltalk fashion.
| mobileClient api | "Access to the API class" mobileClient := PyBridge load: #'gmusicapi::Mobileclient'. "Create a new instance" api := mobileClient new. "Create authentification key" api perform_oauth. "This step must be done only once by GPM account to get a oauth key." "Login using oauth key" api oauth_login: 'XXXXX' "XXXXX is my private key ^-^"
Nice! I have now a full access to the GPM API using PyBridge and Pharo.
Download mp3 files
GPM does not allow the users to download music. However, it is possible to ask for the audio stream in a mp3 format. I will use this to download the files ^-^.
In the following, I will present an example to download the album Hypnotize of System Of A Down. The album is in my GPM library so I can retrieve it in “my songs”.
To download the musics, I will access to all my musics libraries, select the music that belongs to the album, and then download the musics.
"access to all my songs" library := api get_all_songs. "get_all_songs is part of the python library". 0 to: (library size - 1) do: [:index | "take care with index in python" | music | music := (library at: index) ((music at: #album) literalValue beginsWith: 'Hypnotize') "is the music at index part of the album?" ifTrue: [ | fileRef | fileRef := ('/home/user/music' asFileReference / ((music at: #title), '.mp3')). fileRef binaryWriteStreamDo: [:mp3WriteStream | (ZnEasy get: (api get_stream_url: (music at: #id))) writeOn: mp3WriteStream. "download the file" ]. ] ]
I have now downloaded all the music of the album. To summarize:
- Pharo asks for all songs to Python.
- Then Pharo iterates on the Pyhton Map to select the correct musics.
- It asks to Python the URL stream for a Music.
- And it uses Zinc to download the music and creates the mp3 file.
Set the metadata
Our strategy works pretty well but the metadata of the mp3 files are not set. It can not be a problem but it is preferable when using a music manager (such as Clementine, Music Bee, Itunes, …). So, I will use VLC to set the metadata of our files. It is possible to use VLC through Pharo using the Pharo-LibVLC project.
Set Up Pharo LibVLC
Metacello new baseline: 'VLC'; repository: 'github://badetitou/Pharo-LibVLC'; load.
Then, it is possible to use VLC in Pharo after initializing it.
vlc := VLCLibrary uniqueInstance createVLCInstance
Set the metadata
Inside the previous script, I insert the code to set metadata using VLC.
First, I create a reference to the mp3 file for VLC, then I set the metadata using VLC API.
... | media | media := vlc createMediaFromPath: fileRef fullName. "create mp3 reference for VLC" media setMeta: VLCMetaT libvlc_meta_Album with: (music at: #album) literalValue asString. media setMeta: VLCMetaT libvlc_meta_Title with: (music at: #title) literalValue asString. media saveMeta. media release. ...
In the example, I only set “album” and “title” attribute but it is possible to set more metadata.
I have used Zinc, VLC, and Python with a Python library to download musics for Google Play Music service. It shows how easy it is to use Pharo with other programming languages and I hope it will help you to create many super cool projects.
> I REMIND YOU THAT THIS WORK MIGHT NOT LEGAL SO CONSIDER IT ONLY AS AN EXAMPLE!