#!/usr/bin/env python3 from gmusicapi import Mobileclient import argparse import sys import requests import json creds_path=sys.path[0] + '/mobileclient.cred' def authenticate(api): creds = api.perform_oauth(storage_filepath=creds_path, open_browser=False) def uploadLibrary(mudbase_api, songs): # Determine all unique artists artists = sorted(set([song['artist'] for song in songs if 'artist' in song])) # Determine all genres genres = sorted(set([song['genre'] for song in songs if 'genre' in song])) # Store the artist index of each song songArtistIdxs = [ artists.index(song['artist']) for song in songs if 'artist' in song ] # Store the genre index of each song songGenreIdxs = [ genres.index(song['genre']) for song in songs if 'genre' in song ] # Determine all unique albums per artist artistAlbums = [ sorted(set([ song['album'] for song in songs if song['artist'] == artist ])) for artist in artists ] # Determine store ID for all artists def getArtistStoreIds(song): if 'artistId' in song: return [ song['artistId'][0] ] return []; artistStoreIds = [ [ getArtistStoreIds(song) for song in songs if song['artist'] == artist ][0] for artist in artists ] # Create GPM import tag gpmTagIdResponse = requests.post(mudbase_api + '/tag', data = { 'name': 'GPM Import' }).json() print(f"Created tag \"GPM Import\", response: {gpmTagIdResponse}") # Create genres and store their mudbase Ids genreRootResponse = requests.post(mudbase_api + '/tag', data = { 'name': 'Genre' }).json() print(f"Created tag \"Genre\", response: {genreRootResponse}") genreMudbaseIds = [] for idx,genre in enumerate(genres): response = requests.post(mudbase_api + '/tag', data = { 'name': genre, 'parentId': genreRootResponse['id'] }).json() print(f"Created tag \"Genre/{genre}\", response: {response}") genreMudbaseIds.append(response['id']) # Create artists and store their mudbase Ids artistMudbaseIds = [] for idx,artist in enumerate(artists): response = requests.post(mudbase_api + '/artist', json = { 'name': artist, 'storeLinks': [ 'https://play.google.com/music/m/' + id for id in artistStoreIds[idx] ], 'tagIds': [ gpmTagIdResponse['id'] ] }).json() print(f"Created artist \"{artist}\", response: {response}") artistMudbaseIds.append(response['id']) # Create songs def getSongStoreIds(song): if 'storeId' in song: return [ song['storeId'] ] return [] for song in songs: artistMudbaseId = artistMudbaseIds[ artists.index(song['artist']) ] tagIds = [ gpmTagIdResponse['id'] ] if 'genre' in song: genreMudbaseId = genreMudbaseIds[ genres.index(song['genre']) ] tagIds.append(genreMudbaseId) response = requests.post(mudbase_api + '/song', json = { 'title': song['title'], 'artistIds': [ artistMudbaseId ], 'tagIds' : tagIds, 'storeLinks': [ 'https://play.google.com/music/m/' + id for id in getSongStoreIds(song) ], }).json() print(f"Created song \"{song['title']}\" with artist ID {artistMudbaseId}, response: {response}") def getData(api): return { "songs": api.get_all_songs(), "playlists": api.get_all_user_playlist_contents() } def getSongs(data): # Get songs from library songs = [] #data['songs'] # Append songs from playlists for playlist in data['playlists']: for track in playlist['tracks']: if 'track' in track: songs.append(track['track']) # Uniquify by using a dict. After all, same song may appear in # multiple playlists. sI = lambda song: song['artist'] + '-' + song['title'] if 'artist' in song and 'title' in song else 'z' return list(dict((sI(song), song) for song in songs).values()) api = Mobileclient() parser = argparse.ArgumentParser(description="Import Google Music library into MudBase.") parser.add_argument('--authenticate', help="Generate credentials for authentication", action="store_true") parser.add_argument('--store-to', help="Store GPM library to JSON for later upload", action='store', dest='store_to') parser.add_argument('--load-from', help="Load GPM library from JSON for upload", action='store', dest='load_from') parser.add_argument('--mudbase_api', help="Address for the Mudbase back-end API to upload to", action='store', dest='mudbase_api') args = parser.parse_args() if args.authenticate: authenticate(api) data = None # Determine whether we need to log in to GPM and get songs if args.store_to or (not args.load_from and args.mudbase_api): api.oauth_login(Mobileclient.FROM_MAC_ADDRESS, oauth_credentials=creds_path) data = getData(api) # Determine whether to save to a file if args.store_to: with open(args.store_to, 'w') as outfile: json.dump(data, outfile, sort_keys=True, indent=2) # Determine whether to load from a file if args.load_from: with open(args.load_from, 'r') as f: data = json.load(f) songs = getSongs(data) print(f"Found {len(songs)} songs.") if args.mudbase_api: api.oauth_login(Mobileclient.FROM_MAC_ADDRESS, oauth_credentials=creds_path) uploadLibrary(args.mudbase_api, songs)