You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

145 lines
5.3 KiB

#!/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)