-
-
Save anupdhml/bd693e85d1ba1186e9d0 to your computer and use it in GitHub Desktop.
Lastfm loved tracks/playlist to Google Music playlist, either with songs from your library or from all access. Order of songs in lastfm is preserved and can export/load them from a json file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# Lastfm loved tracks/playlist to Google Music playlist, either with songs from your library or from all access | |
# Order of songs in lastfm is preserved. | |
# First export the lastfm data in a json file, and then import it into Google Music | |
# You can edit the intermediate json file if you wish. | |
# | |
# Based on this script. | |
# https://gist.github.com/Timmmm/6572592 | |
# | |
# By <anupdhml@gmail.com> Aug 23 2014 | |
# | |
# Instructions: | |
# | |
# 0. Install python and pip. | |
# 1. Download this to a file `lastfm_to_gmusic.py` | |
# 2. Make it executable: `chmod +x lastfm_to_gmusic.py` | |
# 3. Install `gmusicapi` using `pip`: `pip install gmusicapi` | |
# 4. Get a last.fm API key here: http://www.last.fm/api/account/create | |
# 5. Run it, in one of the 4 modes | |
# | |
# Usage: | |
# | |
#./lastfm_to_gmusic.py --get-lfloved <file_to_save_loved_tracks> <lastfm_user> | |
#./lastfm_to_gmusic.py --get-lfplaylist <file_to_save_playlist_tracks> <lastfm_playlist_url | |
#./lastfm_to_gmusic.py --to-gplaylist <file_to_read_tracks> <gmusic_playlist_name | |
#./lastfm_to_gmusic.py --to-gplaylist-allaccess <file_to_read_tracks> <gmusic_playlist_name> | |
# | |
# I don't have all access so I have not really tested that option | |
# | |
# For user playlists, lastfm_playlist_url should be of the format lastfm://playlist/10137642, | |
# where the number is playlist id. You can get the id for your playlist from here | |
# http://ws.audioscrobbler.com/2.0/?method=user.getplaylists&user=anupdhml&api_key=6322b6b48c82cc8ac2fb55713f7d6b90 | |
# (replace the user with your name. The api key is a test one and should work for demo. But if not, use your own key) | |
# Works for album and tag playlists too. See http://www.last.fm/api/playlists | |
# | |
# Troubleshooting: | |
# | |
# 1. It says "Login error": Go to your gmail and check that it didn't block any "suspicious logins". | |
# 2. It doesn't find any tracks: Update gmusicapi. | |
# 3. Something else: Email me. I might reply. | |
# | |
import sys | |
import simplejson | |
import urllib2 | |
import gmusicapi | |
from xml.etree.ElementTree import * | |
def get_lastfm_lovedtracks(lastfm_username, lastfm_key): | |
loved = [] | |
page = 1 | |
while True: | |
url = "http://ws.audioscrobbler.com/2.0/?method=user.getlovedtracks&user=%s&api_key=%s&page=%d" % \ | |
(lastfm_username, lastfm_key, page) | |
print "Fetching: " + url | |
tree = parse(urllib2.urlopen(url)).getroot() | |
tracks = tree.findall('lovedtracks/track') | |
for track in tracks: | |
title = track.find('name').text | |
artist = track.find('artist/name').text | |
loved.append((artist,title)) | |
if len(tracks) < 50: | |
break | |
page += 1 | |
return loved | |
def get_lastfm_playlist(lastfm_playlist_url, lastfm_key): | |
playlist = [] | |
url = "http://ws.audioscrobbler.com/2.0/?method=playlist.fetch&playlistURL=%s&api_key=%s" % \ | |
(lastfm_playlist_url, lastfm_key) | |
print "Fetching: " + url | |
tree = parse(urllib2.urlopen(url)).getroot() | |
# had to add that xspf prefix to make this work here. | |
tracks = tree.findall('{http://xspf.org/ns/0/}playlist/{http://xspf.org/ns/0/}trackList/{http://xspf.org/ns/0/}track') | |
for track in tracks: | |
title = track.find('{http://xspf.org/ns/0/}title').text | |
artist = track.find('{http://xspf.org/ns/0/}creator').text | |
playlist.append((artist,title)) | |
return playlist | |
def make_gmusic_playlist(google_username, google_password, playlist_name, tracks, use_all_access=False): | |
# Log in. | |
api = gmusicapi.Mobileclient() | |
if not api.login(google_username, google_password): | |
print "Login error" | |
return | |
# Will hold tracks to add found in the library or all access | |
# Initializing to_add like this helps us preserve the order of songs in tracks | |
to_add = [None] * len(tracks) | |
if use_all_access: | |
# Search for each song in all access. | |
# This is quite a dirty way to do it, and the gmusicapi seems to be a little out of date | |
# hence the catch-all. This found 529 out of the 787 loved songs I have which is not too bad. | |
print "Searching all access for playlist tracks" | |
for track in tracks: | |
artist = track[0] | |
title = track[1] | |
try: | |
res = api.search_all_access(artist + " " + title, max_results=1) | |
to_add[tracks.index([artist, title])] = res["song_hits"][0]["track"]["nid"] | |
print 'Found: %s - %s' % (artist, title) | |
except: | |
print 'Not found: %s - %s' % (artist, title) | |
else: | |
# Get all library tracks | |
print "Getting all tracks in the library" | |
library = api.get_all_songs() | |
if len(library) == 0: | |
print 'Your library is empty' | |
return | |
# Determine which of the library tracks are to be added to the playlist | |
print "Checking your library for playlist tracks" | |
for track in library: | |
artist = track['artist'] | |
title = track['title'] | |
if [artist, title] in tracks: | |
to_add[tracks.index([artist, title])] = track['id'] | |
print 'Found: %s - %s' % (artist, title) | |
# Now that we have the songs (either from the library or all access) create the playlist | |
to_add = [track_id for track_id in to_add if track_id is not None] | |
if (len(to_add)) > 0: | |
print "Adding " + str(len(to_add)) + " tracks to playlist" | |
playlist_id = api.create_playlist(playlist_name) | |
# reversing to_add here reverses the order of songs in the playlist. useful for loved tracks | |
#api.add_songs_to_playlist(playlist_id, to_add[::-1]) | |
api.add_songs_to_playlist(playlist_id, to_add) | |
else: | |
print "None of the specified tracks were found so playlist was not created" | |
# dumps data in a json file | |
def put(data, filename): | |
try: | |
jsondata = simplejson.dumps(data, indent=4, skipkeys=True, sort_keys=True) | |
fd = open(filename, 'w') | |
fd.write(jsondata) | |
fd.close() | |
except: | |
print 'ERROR writing', filename | |
pass | |
# get data from a json file | |
def get(filename): | |
returndata = {} | |
try: | |
fd = open(filename, 'r') | |
text = fd.read() | |
fd.close() | |
returndata = simplejson.loads(text) | |
except: | |
print 'COULD NOT LOAD:', filename | |
return returndata | |
if __name__ == '__main__': | |
if len(sys.argv) != 4: | |
print 'usage: python lastfm_to_gmusic.py\n\ | |
--get-lfloved <file_to_save_loved_tracks> <lastfm_user>\n\ | |
--get-lfplaylist <file_to_save_playlist_tracks> <lastfm_playlist_url>\n\ | |
--to-gplaylist <file_to_read_tracks> <gmusic_playlist_name>\n\ | |
--to-gplaylist-allaccess <file_to_read_tracks> <gmusic_playlist_name>' | |
sys.exit(1) | |
# get the tracks | |
lftracks = gtracks = [] | |
use_all_access = False | |
command = sys.argv[1] | |
if command == '--get-lfloved': | |
lastfm_key = raw_input("Lastfm API key: ").strip() | |
lftracks = get_lastfm_lovedtracks(sys.argv[3], lastfm_key) | |
elif command == '--get-lfplaylist': | |
lastfm_key = raw_input("Lastfm API key: ").strip() | |
lftracks = get_lastfm_playlist(sys.argv[3], lastfm_key) | |
elif command == '--to-gplaylist': | |
gtracks = get(sys.argv[2]) | |
elif command == '--to-gplaylist-allaccess': | |
use_all_access = True | |
gtracks = get(sys.argv[2]) | |
else: | |
print 'Invalid first argument' | |
sys.exit(1) | |
# Action after getting the tracks | |
if len(lftracks) > 0: | |
print "Got " + str(len(lftracks)) + " tracks from last.fm. Saving to the file..." | |
put(lftracks, sys.argv[2]) | |
if len(gtracks) > 0: | |
print "Got " + str(len(gtracks)) + " tracks from the given file. Creating the google music playlist now..." | |
google_username = raw_input("Google username: ").strip() | |
google_password = raw_input("Google password: ") | |
make_gmusic_playlist(google_username, google_password, sys.argv[3], gtracks, use_all_access) | |
print 'Done!' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I test the script and didn't work well, so i made some changes in the code. https://gist.github.com/asgsilva/eca248ed7e79ecfbf243d80ed7d5873f