forked from simon-weber/Google-Music-Playlist-Importer
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgm_playlist_importer.py
126 lines (84 loc) · 3.36 KB
/
gm_playlist_importer.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#!/usr/bin/env python
"""Python script to import local playlists to Google Music."""
import re
import sys
import codecs
from getpass import getpass
import chardet
import gmusicapi.gmtools.tools as gm_tools
from gmusicapi import Mobileclient
def init(max_attempts=3):
"""Makes an instance of the api and attempts to login with it.
Returns the api after at most max_attempts.
:param max_attempts:
"""
api = Mobileclient()
logged_in = False
attempts = 0
print "Log in to Google Music."
while not logged_in and attempts < max_attempts:
email = raw_input("Email: ")
password = getpass()
logged_in = api.login(email, password)
attempts += 1
return api
def guess_encoding(filename):
"""Returns a tuple of (guessed encoding, confidence).
:param filename:
"""
res = chardet.detect(open(filename).read())
return (res['encoding'], res['confidence'])
def main():
if not len(sys.argv) == 2:
print "usage:", sys.argv[0], "<playlist file>"
sys.exit(0)
#The three md_ lists define the format of the playlist and how matching should be done against the library.
#They must all have the same number of elements.
#Where this pattern matches, a query will be formed from the captures.
#My example matches against a playlist file with lines like:
# /home/simon/music/library/The Cat Empire/Live on Earth/The Car Song.mp3
#Make sure it won't match lines that don't contain song info!
md_pattern = r"^/ALBUMS/(.*)/(.*)/(.*)$"
#Identify what metadata each capture represents.
#These need to be valid fields in the GM json - see protocol_info in the api repo.
md_cap_types = ('artist', 'album', 'title')
#The lower-better priority of the capture types above.
#In this example, I order title first, then artist, then album.
md_cap_pr = (2, 3, 1)
#Build queries from the playlist.
playlist_fname = sys.argv[1]
pl_encoding, confidence = guess_encoding(playlist_fname)
queries = None
with codecs.open(playlist_fname, encoding=pl_encoding, mode='r') as f:
queries = gm_tools.build_queries_from(f,
re.compile(md_pattern),
md_cap_types,
md_cap_pr,
pl_encoding)
api = init()
if not api.is_authenticated():
print "Failed to log in."
sys.exit(0)
print "Loading library from Google Music..."
library = api.get_all_songs()
print "Matching songs..."
matcher = gm_tools.SongMatcher(library)
matched_songs = matcher.match(queries)
res = raw_input("Output matches to file or terminal? (f/t): ")
if res == "t":
print matcher.build_log()
elif res == "f":
res = raw_input("Filename to write to: ")
with open(res, mode='w') as f:
f.write(matcher.build_log())
print "File written."
go = raw_input("Create playlist from these matches? (y/n): ")
if go == "y":
name = raw_input("playlist name: ")
p_id = api.create_playlist(name)
print "Made playlist", name
res = api.add_songs_to_playlist(p_id,
map(gm_tools.filter_song_md, matched_songs))
print "Added songs."
if __name__ == '__main__':
main()