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
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)
|
|
|