simon-weber / gmusicapi Goto Github PK
View Code? Open in Web Editor NEWAn unofficial client library for Google Music.
Home Page: https://unofficial-google-music-api.readthedocs.io
License: BSD 3-Clause "New" or "Revised" License
An unofficial client library for Google Music.
Home Page: https://unofficial-google-music-api.readthedocs.io
License: BSD 3-Clause "New" or "Revised" License
I assumed that MM did transcoding locally for non-mp3 tracks, but this was never verified. @mgillespie believes it's done server-side.
This should be investigated - it would drop a dependency and remove a lot of logic.
This is more of a question than an issue.
Unofficial Google Music API uses some Python 2.6/2.7 specific features like collections.mapping
module, except Foo as bar
syntax, context managers and named tuples. Due to this it's Python 2.5 incompatible so it cannot run under Maemo 5 (Meego Harmattan as well).
I was wondering what could be done with this problem.
I don't except a refactor for Python 2.5 as it'd really be a regression -- it's only natural to write for Python 2.7/3.x.
The only polite solution I have right now is to wait for the stable version of the API and then make a fork to introduce these incompatible changes.
Hi, I ran across thunner the other day and wanted to try it out. I'm getting the following error in the gmusicapi.log file:
2012-12-26 19:07:44,537 - gmusicapi.Api - WARNING - Received an unexpected response from call loadalltracks.
... a gigantic response object...
2012-12-26 19:07:44,551 - gmusicapi.Api - DEBUG - failed schema: {'additionalProperties': {'continuationToken': {'type': 'string'}}, 'type': 'object', 'properties': {'continuation': {'type': 'boolean'}, 'playlist': {'items': {'additionalProperties': False, 'type': 'object', 'properties': {'comment': {'type': 'string', 'blank': True}, 'rating': {'type': 'integer'}, 'lastPlayed': {'required': False, 'type': 'integer'}, 'disc': {'required': False, 'type': 'integer'}, 'matchedId': {'type': 'string', 'blank': True}, 'composer': {'type': 'string', 'blank': True}, 'year': {'required': False, 'type': 'integer'}, 'id': {'type': 'string', 'blank': True}, 'subjectToCuration': {'type': 'boolean'}, 'album': {'type': 'string', 'blank': True}, 'playlistEntryId': {'required': False, 'type': 'string', 'blank': True}, 'title': {'type': 'string', 'blank': True}, 'deleted': {'type': 'boolean'}, 'albumArtist': {'type': 'string', 'blank': True}, 'durationMillis': {'type': 'integer'}, 'type': {'type': 'integer'}, 'titleNorm': {'type': 'string', 'blank': True}, 'track': {'required': False, 'type': 'integer'}, 'storeId': {'required': False, 'type': 'string', 'blank': True}, 'albumArtistNorm': {'type': 'string', 'blank': True}, 'totalTracks': {'required': False, 'type': 'integer'}, 'beatsPerMinute': {'type': 'integer'}, 'genre': {'type': 'string', 'blank': True}, 'playCount': {'type': 'integer'}, 'creationDate': {'type': 'integer'}, 'name': {'type': 'string', 'blank': True}, 'albumNorm': {'type': 'string', 'blank': True}, 'artist': {'type': 'string', 'blank': True}, 'url': {'type': 'string', 'blank': True}, 'totalDiscs': {'required': False, 'type': 'integer'}, 'albumArtUrl': {'required': False, 'type': 'string', 'blank': True}, 'artistNorm': {'type': 'string', 'blank': True}}}, 'type': 'array'}, 'playlistId': {'type': 'string'}, 'differentialUpdate': {'type': 'boolean'}, 'requestTime': {'type': 'integer'}}}
2012-12-26 19:07:44,552 - gmusicapi.Api - WARNING - error was: Failed to validate field 'playlist' list schema: additional properties not defined by 'properties' are not allowed in list item
'gigantic response object' has all of my tracks in it, which I don't really want to post here, but it's a dict containing the following (top-level) keys:
This same error occurs when I run the gmusicapi.test.integration_test_api.
This same error occurs for the 'loadplaylist' call as well.
I'm in the US if that matters.
I'm currently trying to debug it myself, but I'm not very familiar with this code yet.
Thanks!
Two new fields have appeared: subjectToCuration
and metajamId
. Their purpose and requirements are unknown.
All of my tracks have False for curation, and a majority have a 26 character alphanumberic for the mjid.
They've got their own client library for use: https://developers.google.com/gdata/docs/auth/clientlogin.
Currently, get_playlists
returns a mapping of {playlist name: playlist id}
. Apparently, multiple playlists of the same name are allowed; get_playlists
needs to be changed to support this.
Since this seems to be an edge case, it makes sense to keep mapping names -> single ids when possible. Perhaps an option to always return lists would be a good compromise, for when someone doesn't know anything about the library they're working with.
Album art can be changed through the web interface, and should be a fairly straightforward feature to add. I don't have the time to implement it, though.
Great job on the project.
Some of my mp3 files have no metadata. I've notice that those files fail to upload. See the traceback stack below. I've also noticed that when any kind of exception happens in upload, I can't use it again.
Otherwise, great job!
lateef@neuron ~/Videos> kgmp --add j-cole-visionz-of-home-prod-by-elite-mp3.mp3
'title'
Traceback (most recent call last):
File "/home/lateef/Dropbox/Korin/Korin/Korin/KorinGoogleMusicService/Manager.py", line 69, in add_songs
result = self.gmapi.upload(filenames)
File "", line 2, in upload
File "/home/lateef/Dropbox/Korin/Korin/Korin/KorinGoogleMusicService/gmapi/utils/utils.py", line 65, in wrapper
return function(_args, *_kw)
File "/home/lateef/Dropbox/Korin/Korin/Korin/KorinGoogleMusicService/gmapi/api.py", line 328, in upload
session_requests = self.mm_protocol.make_upload_session_requests(cid_map, metadataresp)
File "/home/lateef/Dropbox/Korin/Korin/Korin/KorinGoogleMusicService/gmapi/protocol.py", line 408, in make_upload_session_requests
"CurrentUploadingTrack": audio["title"][0], #there's an assumption here...
File "/usr/lib/python2.7/site-packages/mutagen/init.py", line 83, in getitem
if self.tags is None: raise KeyError, key
It will not appear if the song was never played. This is a simple tweak in protocol.py
Within the last day or two, method calls to gmusicapi have been throwing errors like this:
2012-05-04 11:00:25,663 - gmusicapi.Api - WARNING - Received an unexpected response from call loadalltracks.
2012-05-04 11:00:25,692 - gmusicapi.Api - WARNING - error was: Failed to validate field 'playlist' list schema: additional properties not defined by 'properties' are not allowed in list item
2012-05-04 11:10:13,506 - gmusicapi.Api - WARNING - Received an unexpected response from call loadplaylist.
2012-05-04 11:10:13,507 - gmusicapi.Api - WARNING - error was: Failed to validate field 'playlist' list schema: additional properties not defined by 'properties' are not allowed in list item
I checked two different accounts (one with a large library and one with a small one) and see the warnings from both. As shown above, I have seen the calls from loadalltracks and loadplaylist. It does not seem to appear when creating playlists or updating track metadata.
Some calls return raw json from the Music server, and others abstract it away. This needs to be made consistent across the Api interface.
In most cases, calls return two things: if they succeeded, and the data that the call operated on. One way to standardize this would be to raise exceptions on failure (there's already code to detect failure across all web client calls), and always return the identity of data that was modified (usually an id of some sort).
This interface should be broad enough to allow for any kind of underlying Session to use it: web client, music manager, skyjam, etc.
It might be desirable to allow a user to configure the api to not raise any exceptions, and only log warnings. Custom context managers may be useful here, too.
The call to loadplaylist
returns a continuationToken just like loadalltracks
. Currently, Google limits playlists to 1000 tracks, so there will never be a non-empty second continuation.
If the track limit was ever raised so that continuations are needed, get_playlist_songs
would fail silently. The code for handling continuations already exists for loadalltracks
and should be used to avoid this in the future.
I noticed that 'track' appears to be an optional entity.
When I do a search, if the song was uploaded with no track meta-data than that field is missing in the returned meta-data.
Currently the documentation implies that the field will always be present (which isn't the case).
Calling loadplaylists
with no json body will return a list of all user playlists and instant mixes, along with ids and tracks. This is a much better approach than the current html parsing used in get_playlists
.
Auto playlists (eg "new and recent") are not included.
Hi,
Is it possible to add functionality for getting the Instant Mixes that Google throws together? I don't mind writing it myself, but I was just wondering if you knew the particular call of the top of your head or something.
Charles
Google Music is now Google Play Music, but the change seems mostly cosmetic from the api's end. All tests pass right now, but there's no guarantee they'll stay this way. Things should be looked in to:
play.google.com/music/services
I noticed that Google made a change in their API
and now i need to send a session-id every time i send a request, any idea where i get it?
The newest music managers use oauth instead of clientlogin.
Not really an issue, but I noticed when you change the last parameters in the url, in this case, the parameter s130 to for ex. s400, you'll get an album art image of size 400x400 px. Could this be implemented as a function like api.Api.getAlbumArt(songid,size) ?
Hi .
It is very useful library.
But, it seems to not supporting utf-8 encode.
I try upload korean filename. encoded with utf-8
But I get below error
ValueError: '\xed\x95\x9c\xea\xb8\x80.mp3' has type str, but isn't in 7-bit ASCII encoding. Non-ASCII strings must be converted to unicode objects before being added.
also i try unicode filename include korean
I get below error
File "/home/abyss/Unofficial-Google-Music-API/gmusicapi/protocol.py", line 866, in make_upload_session_requests
"content": str(inlined[key]),
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
Me again
Suddenly my app Authentication with Google not work and i want to know if they make any change that you notice in the couple days ago.
Around line 800 in protocol.py there are assumptions for the formatting of track/disc numbers that will cause a crash in badly formatted cases.
I'm starting to build a C++ version of the gmapi library. If you happen to have the .proto file available, would it be possible to check it in?
In #51, @fruel and @damariei both upload from a VPS, where the MAC address will change; this registers a device for each upload.
A more static id needs to be used. @damariei suggested the hostid, though I think this will also break if the vm migrates physical machines. Using the public-facing IP may be a better option.
A way to set a user-defined MAC might need to be used as well.
Im getting low quality streams on a 8Mbps internet connection, sounds like 128KBps on my Home Theater speakers, i can tell the difference between streams and my local copies, even the volume is lower.
Possible to implement an option to force stream highest quality stream like in Google Music App on Android?
maxik@power:~$ python -m gmusicapi.test.integration_test_api
Warning: this test suite _might_ modify the library it is run on.
Email: [email protected]
Password:
E
======================================================================
ERROR: setUpClass (__main__.TestWCApiCalls)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/gmusicapi/test/integration_test_api.py", line 53, in setUpClass
super(TestWCApiCalls, cls).setUpClass()
File "/usr/local/lib/python2.7/dist-packages/gmusicapi/test/utils.py", line 190, in setUpClass
cls.api = init()
File "/usr/local/lib/python2.7/dist-packages/gmusicapi/test/utils.py", line 68, in init
logged_in = api.login(email, password)
File "/usr/local/lib/python2.7/dist-packages/gmusicapi/api.py", line 145, in login
self.session.login(email, password)
File "/usr/local/lib/python2.7/dist-packages/gmusicapi/api.py", line 985, in login
tokenauth.authenticate(self.client)
File "/usr/local/lib/python2.7/dist-packages/gmusicapi/utils/tokenauth.py", line 117, in authenticate
err, resp = self._make_request(url, None, headers)
File "/usr/local/lib/python2.7/dist-packages/gmusicapi/utils/tokenauth.py", line 76, in _make_request
resp_obj = handler.open(req)
File "/usr/lib/python2.7/urllib2.py", line 406, in open
response = meth(req, response)
File "/usr/lib/python2.7/urllib2.py", line 519, in http_response
'http', request, response, code, msg, hdrs)
File "/usr/lib/python2.7/urllib2.py", line 438, in error
result = self._call_chain(*args)
File "/usr/lib/python2.7/urllib2.py", line 378, in _call_chain
result = func(*args)
File "/usr/lib/python2.7/urllib2.py", line 625, in http_error_302
return self.parent.open(new, timeout=req.timeout)
File "/usr/lib/python2.7/urllib2.py", line 406, in open
response = meth(req, response)
File "/usr/lib/python2.7/urllib2.py", line 519, in http_response
'http', request, response, code, msg, hdrs)
File "/usr/lib/python2.7/urllib2.py", line 438, in error
result = self._call_chain(*args)
File "/usr/lib/python2.7/urllib2.py", line 378, in _call_chain
result = func(*args)
File "/usr/lib/python2.7/urllib2.py", line 625, in http_error_302
return self.parent.open(new, timeout=req.timeout)
File "/usr/lib/python2.7/urllib2.py", line 406, in open
response = meth(req, response)
File "/usr/lib/python2.7/urllib2.py", line 519, in http_response
'http', request, response, code, msg, hdrs)
File "/usr/lib/python2.7/urllib2.py", line 438, in error
result = self._call_chain(*args)
File "/usr/lib/python2.7/urllib2.py", line 378, in _call_chain
result = func(*args)
File "/usr/lib/python2.7/urllib2.py", line 625, in http_error_302
return self.parent.open(new, timeout=req.timeout)
File "/usr/lib/python2.7/urllib2.py", line 400, in open
response = self._open(req, data)
File "/usr/lib/python2.7/urllib2.py", line 418, in _open
'_open', req)
File "/usr/lib/python2.7/urllib2.py", line 378, in _call_chain
result = func(*args)
File "/usr/lib/python2.7/urllib2.py", line 1215, in https_open
return self.do_open(httplib.HTTPSConnection, req)
File "/usr/lib/python2.7/urllib2.py", line 1177, in do_open
raise URLError(err)
URLError: <urlopen error [Errno 101] Network is unreachable>
----------------------------------------------------------------------
Ran 0 tests in 77.587s
FAILED (errors=1)
maxik@power:~/docs/gplay$ python example_play.py
Email: [email protected]
Password:
Success: logged in.
Search Query: epica
2012-07-18 00:01:36,745 - gmusicapi.Api - WARNING - Received an unexpected response from call search.
2012-07-18 00:01:36,748 - gmusicapi.Api - WARNING - error was: Failed to validate field 'artists' list schema: additional properties not defined by 'properties' are not allowed in list item
Nothing found :(
maxik@power:~/docs/gplay$ pip freeze
Warning: cannot find svn location for distribute==0.6.24dev-r0
GnuPGInterface==0.3.2
PIL==1.1.7
apt-xapian-index==0.44
apturl==0.5.1ubuntu3
argparse==1.2.1
chardet==2.0.1
command-not-found==0.2.44
decorator==3.3.3
## FIXME: could not find svn URL in dependency_links for this package:
distribute==0.6.24dev-r0
foobnix==2.5.36
gmusicapi==2012.05.04
httplib2==0.7.2
jockey==0.9.7
keyring==0.7.1
language-selector==0.1
launchpadlib==1.9.12
lazr.restfulclient==0.12.0
lazr.uri==1.0.3
mutagen==1.20
nvidia-common==0.0.0
oauth==1.0.1
pexpect==2.3
protobuf==2.4.1
pycrypto==2.4.1
pycups==1.9.61
pycurl==7.19.0
pysmbc==1.0.13
python-apt==0.8.3ubuntu7
python-debian==0.1.21ubuntu1
pyudev==0.13
pyxdg==0.19
reportlab==2.5
simplejson==2.3.2
synaptiks==0.8.1
ufw==0.31.1-1
unattended-upgrades==0.1
usb-creator==0.2.23
validictory==0.8.3
vboxapi==1.0
wadllib==1.3.0
wsgiref==0.1.2
xkit==0.0.0
zope.interface==3.6.1
I've started documenting the requests and responses for Skyjam more thoroughly at https://github.com/dpogue/Unofficial-Google-Music-API/wiki/Skyjam-API
Should be of use to people wanting to avoid dealing with cookies and the ever-changing format of web responses.
According to Google's support page, other than mp3, there are four more audio types supported for upload:
However, the actual Music service only supports mp3 and (presumably) wma; the first three formats are transcoded by Music Manager before upload.
Since we can't distribute encoders/decoders, we're going to need to have end-users download things like lame and oggdec. Python Audio Tools has a page on the dependencies they use.
That said, it's probably easiest to assume whatever tools we need are in the path, and call out to them with subprocess
. With that decision made, it should be fairly easy to support other formats: just transcode them in a way that preserves metadata, then use our existing mp3 support.
Api should expose a way to safely mutate metadata, by specifying which keys are changing. The underlying call does not require an entire song each time, just the keys that are changing.
Currently, requesting the expectation of an unknown key will cause an exception:
api.change_song_metadata({'foo':'bar'})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 2, in change_song_metadata
File "gmusicapi/utils/utils.py", line 70, in wrapper
return function(*args, **kw)
File "gmusicapi/api.py", line 177, in change_song_metadata
return self._wc_call("modifyentries", songs)
File "gmusicapi/api.py", line 564, in _wc_call
body, res_schema = protocol.build_transaction(*args)
File "gmusicapi/protocol.py", line 542, in build_transaction
allowed_values = Metadata_Expectations.get_expectation(key).allowed_values
File "gmusicapi/protocol.py", line 158, in get_expectation
expt = getattr(cls, "gm_"+key)
AttributeError: class Metadata_Expectations has no attribute 'gm_foo'
There should be a flexible default expectation to prevent future breakage when metadata keys are added. There should still be a warning, however: something like "key [name] is not known - using default expectation".
@dpogue: I've been thinking of a building a unified data model lately, that I think may simplify implementation and ease some of the concerns with mutation and building dictionaries. The basic idea is that we'd have a single collection of all the tracks/playlists backed with the actual representations from Google Music. The Song and Playlist models would basically be pointers into this central collection, keeping everything in sync across models. It would look something like this:
This is the main collection of all the songs and playlists.
It's backed by two privateish dictionaries: {"song id": {<GM song dictionary>}}
and {"playlist id": [("song id", "entryId"), ...]}
. It also exposes methods for searching and retrieving songs/playlists (I've already got some things in gmtools that'll come in handy here for searching locally. There's also the slower search()
that hits the server.).
I'll show how we'd handle mutation and updates later, but my idea is that Songs and Playlists expose methods that simply change the GM representations in the Library. That way, we can leave it up to the user at runtime whether they want to auto-update or batch their changes. Keeping everything in their GM representation is a big help there; we'd just have to track which ids changed, and then push their current representation. (only thing: I'm not actually sure what we have to work with in the way of pushing playlist changes, but worst case we can always erase and create a new one with the same name).
This represents a single song in the Library. The only data member is the id string, which is used to index into the Library dictionary when metadata is requested.
Metadata changes could either be done by indexing into a song:
song['artist'] = 'foo'
print song['album']
or by properties. That's just a choice between hooking __getitem__
or __getattribute__
.
Getting/setting metadata goes through the Library to keep everything in sync, which I think makes more sense than being able to have different instances of songs:
song = library.songs["id"] # not direct access to the underlying
# dictionaries; we'd control this. maybe
# a get() that support lists would be better
same_song = library.songs["id"] # returns a new Song instance
assert song.id() != same_song.id() # id() being the Python id (memory location)
assert song == same_song # comparison/hashing is just done with GM ids
print song["artist"] # => "old artist"
song["artist"] = "new artist"
print same_song["artist"] # => "new artist"
The setters in Song (or Library, which is probably better) would hook into the Metadata_Expectations to ensure we're only setting mutable things to the allowed values, etc.
Playlists are a lot like songs; they'd just store their playlistId, and modify the Library collection. Tools for changing them are exposed just like songs.
Songs and Playlists wouldn't be directly manipulating the dictionaries that back Library. There'd be one level (or two, if we want to check change validity in Library instead of Song) of indirection, which handles whether or not we want to batch changes or update everything on every change. Batching changes would just mean maintaining a set of all the song/playlist ids that have been modified.
Either way, when an update occurs, we flush out all our changes and verify they went ok (metadata poses a problem, since the server doesn't actually accurately tell us if our request succeeded. I'm not really sure how to deal with this. Right now, when I test, I'm pulling down the entire library to see my changes - not ideal for large libraries. I'm thinking an optimistic approach would be best here: assume we succeeded, and fork a thread to verify at some later time that we actually did. If not, either try again or warn/raise an exception that the Library is out of date. That's just details, though.).
Assuming away the metadata verification for now, the entire process looks something like:
Whew, that was a bit more than I thought it would - which brings me to my next point!
I'm afraid this might be a bit heavy to build in to Api. Maybe we can provide it as another abstraction layer on top of Api? This helps with two things:
Let me know what you think! I'll have plenty of time next week to work on this if/when we decide on something.
Hello,
first thanks for developing this API !
I wanted to know how hard is it to port the code to JavaScript, since I want to use it in Nightingale (an app based of Mozilla framework).
Is it something that could be achieved easily ?
I saw you mention a property in the SkyJam docs called estimatedSize - I haven't seen that property yet on the JSON that Google returns, and it is not written current doc. Did it disappear from the API or what happened to it?
Hi
i research about all google music stuff and use:
http://music.google.com/music/services/loadalltracks?u=0&xt=? link to get all songs data from google music.
i try to search about another services of google music but didn't found anything for handle playlists and other stuff.
did you can help with stuff like this?
Thanks for gmapi, it's awesome and I'm actually building an App around it.
So the issue is that gmapi is not currently usable from an Python folder or Package other than if it is installed in the default site-packages folder. This is a reasonable assumption but for people who are testing the API or just want to bundle the API in their packages or apps, this poses a problem.
The problem is solved by not using global imports in the source files, but using relative imports instead. For example instead of
from gmapi.session import WC_Session, MM_Session
this is preferable
from session import WC_Session, MM_Session
This way, I can use put the gmapi folder in any python package or folder that has init.py and use it without problems like I do in my project.
Thanks for gmapi and keep up the great work!
Google will sort the returned songs with, for example, ascendingSort=true
and sort="album"
. This should be an option in get_all_songs
.
@mgillespie, @damariei, @fruel, and anyone else:
I want uploading to work again, and more reliably. I've been thinking of changing direction and using the Music Manager instead of trying to replace it. I'd still be able to provide the same interface as now, I think.
So, a question for you folks: is requiring an installed Music Manager a dealbreaker? I don't think it would be a problem to get everything working on a headless box.
The big gains for you would be scan and match, faster uploads and fewer breakages. On my end: (hopefully) less scrambling on protocol changes, and a compliant client.
Personally, I think it would be worth it, but I don't want to make a big switch without getting some opinions first. So, let me know what you think.
Also, happy holidays! =)
At the moment, only the structure and type of the responses are validated in protocol.WC_Protocol
. However, Validictory has a whole host of other tools to use (some undocumented), and the stricter validation is, the sooner a protocol change would become apparent.
Some simple things to validate:
continuation
should always be False - this tests the playlist limit assumptiontest.utils
Also, it's probably smart to prompt end-users to submit an issue when validations fail.
Reports that it's uploaded correctly, but it's missed everything in my library.
Running the tests, I see the following:
2012-11-21 22:08:45,573 - gmusicapi.UnitTestedApi - WARNING - Received an unexpected response from call loadalltracks.
2012-11-21 22:08:45,821 - gmusicapi.UnitTestedApi - WARNING - error was: Failed to validate field 'playlist' list schema: additional properties not defined by 'properties' are not allowed in list item
.2012-11-21 22:09:55,008 - gmusicapi.UnitTestedApi - WARNING - Received an unexpected response from call loadalltracks.
2012-11-21 22:09:55,250 - gmusicapi.UnitTestedApi - WARNING - error was: Failed to validate field 'playlist' list schema: additional properties not defined by 'properties' are not allowed in list item
2012-11-21 22:10:56,259 - gmusicapi.UnitTestedApi - WARNING - Received an unexpected response from call loadalltracks.
2012-11-21 22:10:56,488 - gmusicapi.UnitTestedApi - WARNING - error was: Failed to validate field 'playlist' list schema: additional properties not defined by 'properties' are not allowed in list item
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/gmusicapi/test/integration_test_api.py", line 211, in test_up_deletion
self.run_steps("updel_")
File "/usr/local/lib/python2.7/dist-packages/gmusicapi/test/utils.py", line 234, in run_steps
step()
File "/usr/local/lib/python2.7/dist-packages/gmusicapi/test/integration_test_api.py", line 185, in updel_1_upload
result = self.api.upload(some_files)
File "", line 2, in upload
File "/usr/local/lib/python2.7/dist-packages/gmusicapi/utils/utils.py", line 136, in wrapper
return function(_args, *_kw)
File "", line 2, in upload
File "/usr/local/lib/python2.7/dist-packages/gmusicapi/utils/utils.py", line 113, in wrapper
return function(_args, *_kw)
File "/usr/local/lib/python2.7/dist-packages/gmusicapi/api.py", line 690, in upload
fname_to_id = self._upload_mp3s(map(lambda f: f.name, upload_files))
File "/usr/local/lib/python2.7/dist-packages/gmusicapi/api.py", line 781, in _upload_mp3s
metadataresp = self._mm_pb_call("metadata", metadata_request)
File "/usr/local/lib/python2.7/dist-packages/gmusicapi/api.py", line 887, in _mm_pb_call
res.ParseFromString(self.session.post_protobuf(url, req))
File "/usr/local/lib/python2.7/dist-packages/gmusicapi/api.py", line 1058, in post_protobuf
resp = self.android.getresponse()
File "/usr/lib/python2.7/httplib.py", line 1030, in getresponse
response.begin()
File "/usr/lib/python2.7/httplib.py", line 407, in begin
version, status, reason = self._read_status()
File "/usr/lib/python2.7/httplib.py", line 371, in _read_status
raise BadStatusLine(line)
BadStatusLine: ''
Ran 6 tests in 298.702s
FAILED (errors=1)
This is not a feature request per se.
I'd like to know whether it's (or will be) possible to use application specific password like the Google Music Manager does in case user has two-factor auth enabled.
The question is more like, whether the API can handle it (currently it throws an exception)?
I tried to use your API to upload mp3s to Google Music but calling api.upload always returns an empty dictionary.
My upload script: http://pastebin.com/b7r7GPNj
I run it with this command: python google_music.py -e [email protected] /x/y/z/This\ is\ a\ MP3.mp3
MP3 file: http://pastebin.com/WCUWg5Ub
I have 510 songs on my Google Music account and the the device I want to use for uploading is authorized.
I traced the problem to the following lines:
protocol.py:841 (make_upload_session_requests): The array server_response.response.uploads is empty.
api.py:781 (_upload_mp3s): self._mm_pb_call("metadata", metadata_request) returns this:
u0: 1
response {
}
state {
u0: 0
u1: 0
u2: 5
u3: 12000
u4: 0
u5: 16000
}
Until last week I used https://github.com/antimatter15/google-music-protocol/blob/master/py/upload.py to upload mp3s to Google Music but this script stopped working last week. Runnig it in verbose mode it prints the same response as your API (self._mm_pb_call("metadata", metadata_request) )
This would be an opportunity to overhaul the terrible PlaySession code by moving to Requests (which would also be a good time for authentication changes, eg #48).
For some flacs (not all unfortunately), the transcoded versions will not play on the google play music page. Nor will they play on my android devices. Not sure how to debug this, but let me know.
ffmpeg version 1.0.1 Copyright (c) 2000-2012 the FFmpeg developers
built on Dec 4 2012 13:43:06 with gcc 4.7 (Debian 4.7.2-4)
configuration: --prefix=/usr --extra-cflags='-g -O2 -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security ' --extra-ldflags='-Wl,-z,relro' --cc='ccache cc' --enable-shared --enable-libmp3lame --enable-gpl --enable-nonfree --disable-decoder=libdirac --enable-libvorbis --enable-pthreads --enable-libfaac --enable-libxvid --enable-postproc --enable-x11grab --enable-libgsm --enable-libtheora --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libx264 --enable-libspeex --enable-nonfree --disable-stripping --enable-libschroedinger --disable-encoder=libschroedinger --enable-version3 --enable-libopenjpeg --enable-libvpx --enable-librtmp --enable-avfilter --enable-libfreetype --enable-libvo-aacenc --disable-decoder=amrnb --enable-libvo-amrwbenc --enable-libaacplus --libdir=/usr/lib/x86_64-linux-gnu --disable-vda --enable-libbluray --enable-libcdio --enable-gnutls --enable-frei0r --enable-openssl --enable-libass --enable-libopus --enable-fontconfig --enable-libdc1394 --disable-altive libavutil 51. 73.101 / 51. 73.101
libavcodec 54. 59.100 / 54. 59.100
libavformat 54. 29.104 / 54. 29.104
libavdevice 54. 2.101 / 54. 2.101
libavfilter 3. 17.100 / 3. 17.100
libswscale 2. 1.101 / 2. 1.101
libswresample 0. 15.100 / 0. 15.100
libpostproc 52. 0.100 / 52. 0.100
While testing my application which uploads files using the API, I seemingly at random started to get the following issue when doing api.upload('file.mp3'):
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<string>", line 2, in upload
File "/usr/local/lib/python2.7/dist-packages/gmusicapi/utils/utils.py", line 136, in wrapper
return function(*args, **kw)
File "<string>", line 2, in upload
File "/usr/local/lib/python2.7/dist-packages/gmusicapi/utils/utils.py", line 113, in wrapper
return function(*args, **kw)
File "/usr/local/lib/python2.7/dist-packages/gmusicapi/api.py", line 690, in upload
fname_to_id = self._upload_mp3s(map(lambda f: f.name, upload_files))
File "/usr/local/lib/python2.7/dist-packages/gmusicapi/api.py", line 781, in _upload_mp3s
metadataresp = self._mm_pb_call("metadata", metadata_request)
File "/usr/local/lib/python2.7/dist-packages/gmusicapi/api.py", line 887, in _mm_pb_call
res.ParseFromString(self.session.post_protobuf(url, req))
File "/usr/local/lib/python2.7/dist-packages/google/protobuf/message.py", line 179, in ParseFromString
self.MergeFromString(serialized)
File "/usr/local/lib/python2.7/dist-packages/google/protobuf/internal/python_message.py", line 758, in MergeFromString
raise message_mod.DecodeError('Unexpected end-group tag.')
google.protobuf.message.DecodeError: Unexpected end-group tag.
I have not been able to make it go away after trying with multiple files.
Any ideas?
The current code base needs an overview to get future contributors up to speed; I'll take care of it.
The project should be packaged using pip and be submitted to PyPI. Read the Docs supports pip dependencies, so this has the added benefit of cleaning up the mock-out mess that currently exists.
__all__
should be used to export only relevant modules/classes.
it seems, that google changed the protocoll for the playlist services
see test suite result: https://gist.github.com/6fa9b9beeb95a6d3cb61
@dpogue @antimatter15 @mystilleef @gumho (I also just realized antimatter15 isn't in the AUTHORS file - I'll fix that)
Hey, all. Everyone above has contributed to the project in some way or another. I'm thinking about a possible license change from GPLv3, and my understanding is that you would all have to agree to it before I changed it.
My original reasoning for picking the GPL was simply to choose the most restrictive license I could. I intend the project to be a value-add for Google, and I thought restricting use would also prevent abuse.
Today, I'm not as concerned about this, since the api really doesn't enable more than Google's end-user tools do. So, I'm proposing a switch to the 3-clause BSD license. The license change is to address two things that the GPL doesn't do:
Any thoughts? If you agree, just leave a comment saying to go ahead with the change.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.