Skip to content
This repository has been archived by the owner on Jan 22, 2022. It is now read-only.

Commit

Permalink
Merge branch 'release-2013-02-11'
Browse files Browse the repository at this point in the history
  • Loading branch information
simon-weber committed Feb 12, 2013
2 parents 0cea4fb + 9a8b6be commit ce9cfdf
Show file tree
Hide file tree
Showing 9 changed files with 146 additions and 83 deletions.
19 changes: 14 additions & 5 deletions HISTORY.rst
Expand Up @@ -3,25 +3,34 @@
History
-------

2013.02.xx
As of 2013.02.09, releases with breaking changes will be noted with ``**``.

2013.02.11
++++++++++

- improve handling of strange metadata when uploading
- add a dependency on `dateutil <http://labix.org/python-dateutil>`__


``**`` 2013.02.09
+++++++++++++++++

- breaking: upload returns a 3-tuple (`docs
<https://unofficial-google-music-api.readthedocs.org/en
/latest/#gmusicapi.api.Api.upload>`_)
/latest/#gmusicapi.api.Api.upload>`__)

- breaking: get_all_playlist_ids always returns lists of ids; remove always_id_lists option
(`docs <https://unofficial-google-music-api.readthedocs.org/en
/latest/#gmusicapi.api.Api.get_all_playlist_ids>`_)
/latest/#gmusicapi.api.Api.get_all_playlist_ids>`__)

- breaking: remove suppress_failure option in Api.__init__
- breaking: copy_playlist ``orig_id`` argument renamed to ``playlist_id`` (`docs
<https://unofficial-google-music-api.readthedocs.org/en
/latest/#gmusicapi.api.Api.copy_playlist>`_)
/latest/#gmusicapi.api.Api.copy_playlist>`__)

- new: report_incorrect_match (only useful for Music Manager uploads) (`docs
<https://unofficial-google-music-api.readthedocs.org/en
/latest/#gmusicapi.api.Api.report_incorrect_match>`_)
/latest/#gmusicapi.api.Api.report_incorrect_match>`__)

- uploading fixed
- avconv replaces ffmpeg
Expand Down
82 changes: 37 additions & 45 deletions README.rst
Expand Up @@ -2,7 +2,7 @@ gmusicapi: an unofficial Python API for Google Play Music
=========================================================

This project allows control of
`Google Music <http://music.google.com>`_ from Python.
`Google Music <http://music.google.com>`__ from Python.

.. code-block:: python
Expand All @@ -24,37 +24,33 @@ for everyone else.

For those looking to use the api, see the installation and usage
sections below.
`Documentation is hosted at Read the Docs <http://readthedocs.org/docs/unofficial-google-music-api/en/latest>`_.
`Documentation is hosted at Read the Docs <http://readthedocs.org/docs/unofficial-google-music-api/en/latest>`__.

For those looking to port or contribute, see the porting section
below. There's also
`an out of date code overview on the wiki <https://github.com/simon-weber/Unofficial-Google-Music-API/wiki/Codebase-Overview>`_.
`an out of date code overview on the wiki <https://github.com/simon-weber/Unofficial-Google-Music-API/wiki/Codebase-Overview>`__.

For bugs reports, feature requests, and contributions, go ahead and
`open an issue <https://github.com/simon-weber/Unofficial-Google-Music-API/issues/new>`_.
`open an issue <https://github.com/simon-weber/Unofficial-Google-Music-API/issues/new>`__.

Feel free to drop by ``#gmusicapi`` on Freenode with general questions.

Also, check out these nifty projects that use gmusicapi:


- Malcolm Still's `command line Google Music client <https://github.com/mstill/thunner>`_
(`screenshot <http://i.imgur.com/Mwl0k.png>`_)
- David Dooling's `sync scripts for Banshee <https://github.com/ddgenome/banshee-helper-scripts>`_
- Mendhak's `Rhythmbox metadata sync plugin <https://github.com/mendhak/rhythmbox-gmusic-sync>`_
- Ryan McGuire's `GMusicFS <https://github.com/EnigmaCurry/GMusicFS>`_ - a FUSE
- Malcolm Still's `command line Google Music client <https://github.com/mstill/thunner>`__
(`screenshot <http://i.imgur.com/Mwl0k.png>`__)
- David Dooling's `sync scripts for Banshee <https://github.com/ddgenome/banshee-helper-scripts>`__
- Mendhak's `Rhythmbox metadata sync plugin <https://github.com/mendhak/rhythmbox-gmusic-sync>`__
- Ryan McGuire's `GMusicFS <https://github.com/EnigmaCurry/GMusicFS>`__ - a FUSE
filesystem linked to your music
- Kilian Lackhove's `Google Music support <https://github.com/crabmanX/google-music-resolver>`_
- Kilian Lackhove's `Google Music support <https://github.com/crabmanX/google-music-resolver>`__
for http://www.tomahawk-player.org

Features
--------

**New in version 2013.02.09**

- uploading works again
- scan and match support
- avconv replaces ffmpeg
- major code quality and documentation improvements
- a bunch of more minor breaking changes; see HISTORY.rst for details
See ``HISTORY.rst`` for changes by version.

**Feature Overview:**

Expand Down Expand Up @@ -86,53 +82,51 @@ Features
**Coming soon:**

- album art manipulation (issues `#52
<https://github.com/simon-weber/Unofficial-Google-Music-API/issues/52>`_ and `#38
<https://github.com/simon-weber/Unofficial-Google-Music-API/issues/38>`_)
<https://github.com/simon-weber/Unofficial-Google-Music-API/issues/52>`__ and `#38
<https://github.com/simon-weber/Unofficial-Google-Music-API/issues/38>`__)
- library download support

Usage
-----

The API has been tested on Python 2.7.2 on Linux and Windows.
The API has been tested on Python 2.7.3 on Linux and Windows.

Installation
~~~~~~~~~~~~
++++++++++++

Use `pip <http://www.pip-installer.org/en/latest/index.html>`_:
Use `pip <http://www.pip-installer.org/en/latest/index.html>`__:
``pip install gmusicapi`` will grab all the source dependencies.
Windows users could alternatively use the
`installation binary on PyPI <http://pypi.python.org/pypi/gmusicapi/>`_.
I would recommend *against* using ``easy_install``.

If you want to make changes to gmusicapi, see the guidance in the
`contributing doc <https://github.com/simon-weber/Unofficial-Google-Music-API/blob/master/CONTRIBUTING.md>`_.
`contributing doc <https://github.com/simon-weber/Unofficial-Google-Music-API/blob/master/CONTRIBUTING.md>`__.

To upload filetypes other than mp3, you're going to need `Libav's avconv <http://libav.org/avconv.html>`_
To upload filetypes other than mp3, you're going to need `Libav's avconv <http://libav.org/avconv.html>`__
installed and in your system path, along with at least libmp3lame. For Ubuntu users:
``sudo apt-get install libav-tools ubuntu-restricted-extras``. Windows
users, get `the most recent static binaries <http://win32.libav.org/releases/>`_
and then `edit your path <http://www.computerhope.com/issues/ch000549.htm>`_
users, get `the most recent static binaries <http://win32.libav.org/releases/>`__
and then `edit your path <http://www.computerhope.com/issues/ch000549.htm>`__
to include the directory that contains avconv.exe. If you need to install from source,
be sure to use ``./configure --enable-gpl --enable-nonfree --enable-libmp3lame``.
`mediabuntu <http://www.medibuntu.org/>`_ and `deb-multimedia <http://www.deb-multimedia.org/>`_ might be useful.
`mediabuntu <http://www.medibuntu.org/>`__ and `deb-multimedia <http://www.deb-multimedia.org/>`_ might be useful.

To check that everything is set up correctly, you can run the test
suite: ``python -m gmusicapi.test.integration_test_api``. If
something goes wrong during testing, there is the chance that
you'll end up with an extra playlist or test song in your library,
but it should never destructively modify your library. If there is
an error during testing, please
`open an issue <https://github.com/simon-weber/Unofficial-Google-Music-API/issues/new>`_
`open an issue <https://github.com/simon-weber/Unofficial-Google-Music-API/issues/new>`__
to let me know about it.

Getting Started
~~~~~~~~~~~~~~~
+++++++++++++++

gmusicapi.api.Api is the user-facing interface. The provided
`example.py <https://github.com/simon-weber/Unofficial-Google-Music-API/blob/master/example.py>`_
`example.py <https://github.com/simon-weber/Unofficial-Google-Music-API/blob/master/example.py>`__
should be enough to get you started. For complete information, see
the
`documentation <http://readthedocs.org/docs/unofficial-google-music-api/en/latest>`_.
`documentation <http://readthedocs.org/docs/unofficial-google-music-api/en/latest>`__.
The testing code might also be useful.

Ports
Expand All @@ -142,32 +136,32 @@ Here are the ports I'm currently aware of:


- C#:
`Taylor Finnell <https://github.com/Byteopia/GoogleMusicAPI.NET>`_
- Java: `Jens Villadsen <https://github.com/jkiddo/gmusic.api>`_
and `Nick Martin <https://github.com/xnickmx/google-play-client>`_
`Taylor Finnell <https://github.com/Byteopia/GoogleMusicAPI.NET>`__
- Java: `Jens Villadsen <https://github.com/jkiddo/gmusic.api>`__
and `Nick Martin <https://github.com/xnickmx/google-play-client>`__
- PHP:
`raydanhk <http://code.google.com/p/unofficial-google-music-api-php/>`_
`raydanhk <http://code.google.com/p/unofficial-google-music-api-php/>`__

Porting Information for Developers
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++++++++++++++++++++++++++++++++++

Get in touch if you're working on a port. Even if I can't
contribute, I might know people who'd like to.

The current implementation uses the same interface that a web
browser does, and a code overview can be found
`on the wiki <https://github.com/simon-weber/Unofficial-Google-Music-API/wiki/Codebase-Overview>`_.
`on the wiki <https://github.com/simon-weber/Unofficial-Google-Music-API/wiki/Codebase-Overview>`__.
Darryl Pogue is worked on a more durable implementation by
emulating Google's Android app. His work is
`here <https://github.com/dpogue/Unofficial-Google-Music-API>`_,
`here <https://github.com/dpogue/Unofficial-Google-Music-API>`__,
and may easier to port. More information this alternative protocol
is
`here <https://github.com/dpogue/Unofficial-Google-Music-API/wiki/Skyjam-API>`_.
`here <https://github.com/dpogue/Unofficial-Google-Music-API/wiki/Skyjam-API>`__.

Either way, you'll probably want to ignore anything related to
Music Manager; that's just for uploading. If uploading interests
you, more information is
`here <https://github.com/simon-weber/google-music-protocol>`_.
`here <https://github.com/simon-weber/google-music-protocol>`__.

Lastly, keep the license in mind, and, again, be sure to respect
Google.
Expand All @@ -180,9 +174,7 @@ gmusicapi.log in your working directory, with warnings and above
printed to the console. Nothing related to authenticated gets
logged aside from "logged in" and "logged out" messages.

--------------

Copyright 2012 `Simon Weber <http://www.simonmweber.com>`_.
Copyright 2012 `Simon Weber <http://www.simonmweber.com>`__.
Licensed under the 3-clause BSD. See COPYING.

.. image:: https://cruel-carlota.pagodabox.com/68a92ecf6b6590372f435fb2674d072e
2 changes: 1 addition & 1 deletion docs/source/index.rst
Expand Up @@ -51,7 +51,7 @@ Song Dictionary Format
Google Music sends song metadata in dictionaries.
Many of them cannot be changed, and others don't appear in all songs.
See `the code <https://github.com/simon-weber/Unofficial-Google-Music-API
/blob/develop/gmusicapi/protocol/metadata.py>`_ for complete information.
/blob/develop/gmusicapi/protocol/metadata.py>`__ for complete information.

Songs retrieved in the context of a playlist will contain a ``playlistEntryId``
which is unique to the relevant playlist.
Expand Down
40 changes: 21 additions & 19 deletions gmusicapi/api.py
Expand Up @@ -23,7 +23,7 @@
CallFailure, ParseException, ValidationException,
AlreadyLoggedIn, NotLoggedIn
)
from gmusicapi.protocol import webclient, musicmanager, upload_pb2
from gmusicapi.protocol import webclient, musicmanager, upload_pb2, locker_pb2
from gmusicapi.utils import utils
from gmusicapi.utils.apilogging import UsesLog
from gmusicapi.utils.clientlogin import ClientLogin
Expand Down Expand Up @@ -80,7 +80,7 @@ def login(self, email, password, perform_upload_auth=True,
to log in.
There are strict limits on how many upload devices can be registered; refer to `Google's
docs <http://support.google.com/googleplay/bin/answer.py?hl=en&answer=1230356>`_. There
docs <http://support.google.com/googleplay/bin/answer.py?hl=en&answer=1230356>`__. There
have been limits on deauthorizing devices in the past, so it's smart not to register
more devices than necessary.
"""
Expand Down Expand Up @@ -175,9 +175,9 @@ def change_song_metadata(self, songs):
For up-to-date information on metadata, refer to `the code
<https://github.com/simon-weber/Unofficial-Google-Music-API/
blob/develop/gmusicapi/protocol/metadata.py>`_.
blob/develop/gmusicapi/protocol/metadata.py>`__.
Better docs are in the works; see issue `#73
<https://github.com/simon-weber/Unofficial-Google-Music-API/issues/73>`_.
<https://github.com/simon-weber/Unofficial-Google-Music-API/issues/73>`__.
"""

res = self._make_call(webclient.ChangeSongMetadata, songs)
Expand Down Expand Up @@ -274,7 +274,7 @@ def get_all_playlist_ids(self, auto=True, user=True):
}
There is currently no support for retrieving automatically-created instant mixes
(see issue `#67 <https://github.com/simon-weber/Unofficial-Google-Music-API/issues/67>`_).
(see issue `#67 <https://github.com/simon-weber/Unofficial-Google-Music-API/issues/67>`__).
"""

Expand Down Expand Up @@ -620,7 +620,7 @@ def report_incorrect_match(self, song_ids):
Note that if you uploaded a song through gmusicapi, it won't be reuploaded
automatically - this currently only works for songs uploaded with the Music Manager.
See issue `#89 <https://github.com/simon-weber/Unofficial-Google-Music-API/issues/89>`_.
See issue `#89 <https://github.com/simon-weber/Unofficial-Google-Music-API/issues/89>`__.
This should only be used on matched tracks (``song['type'] == 6``).
"""
Expand Down Expand Up @@ -669,7 +669,7 @@ def upload(self, filepaths, transcode_quality=3, enable_matching=False):
"""Uploads the given filepaths.
Any non-mp3 files will be `transcoded with avconv
<https://github.com/simon-weber/Unofficial-Google-Music-API/
blob/develop/gmusicapi/utils/utils.py#L18>`_ before being uploaded.
blob/develop/gmusicapi/utils/utils.py#L18>`__ before being uploaded.
Return a 3-tuple ``(uploaded, matched, not_uploaded)`` of dictionaries, eg::
Expand All @@ -682,21 +682,21 @@ def upload(self, filepaths, transcode_quality=3, enable_matching=False):
:param filepaths: a list of filepaths, or a single filepath.
:param transcode_quality: if int, pass to avconv ``-qscale`` for libmp3lame
(lower-better int, roughly corresponding to `hydrogenaudio -vX settings
<http://wiki.hydrogenaudio.org/index.php?title=LAME#Recommended_encoder_settings>`_).
<http://wiki.hydrogenaudio.org/index.php?title=LAME#Recommended_encoder_settings>`__).
If string, pass to avconv ``-ab`` (eg ``'128k'`` for an average bitrate of 128k). The
default is ~175kbs vbr.
:param enable_matching: if ``True``, attempt to use `scan and match
<http://support.google.com/googleplay/bin/answer.py?hl=en&answer=2920799&topic=2450455>`_
<http://support.google.com/googleplay/bin/answer.py?hl=en&answer=2920799&topic=2450455>`__
to avoid uploading every song.
**WARNING**: currently, mismatched songs can *not* be fixed with the 'Fix Incorrect Match'
button or :func:`report_incorrect_match`. They would have to be deleted and reuploaded
with the Music Manager.
Fixing matches from gmusicapi will be supported in a future release; see issue `#89
<https://github.com/simon-weber/Unofficial-Google-Music-API/issues/89>`_.
<https://github.com/simon-weber/Unofficial-Google-Music-API/issues/89>`__.
All Google-supported filetypes are supported; see `Google's documentation
<http://support.google.com/googleplay/bin/answer.py?hl=en&answer=1100462>`_.
<http://support.google.com/googleplay/bin/answer.py?hl=en&answer=1100462>`__.
Unlike Google's Music Manager, this function will currently allow the same song to
be uploaded more than once if its tags are changed. This is subject to change in the future.
Expand Down Expand Up @@ -865,15 +865,17 @@ def upload(self, filepaths, transcode_quality=3, enable_matching=False):
session_url = external['putInfo']['url']
content_type = external['content_type']

try:
transcoded_audio = utils.transcode_to_mp3(contents, quality=transcode_quality)
except (OSError, ValueError) as e:
self.log.warning("error transcoding %s: %s", path, e)
not_uploaded[path] = "transcoding error: %s" % e
continue
if track.original_content_type != locker_pb2.Track.MP3:
try:
self.log.info("transcoding '%s' to mp3", path)
contents = utils.transcode_to_mp3(contents, quality=transcode_quality)
except (OSError, ValueError) as e:
self.log.warning("error transcoding %s: %s", path, e)
not_uploaded[path] = "transcoding error: %s" % e
continue

upload_response = self._make_call(musicmanager.UploadFile,
session_url, content_type, transcoded_audio)
session_url, content_type, contents)

success = upload_response.get('sessionStatus', {}).get('state')
if success:
Expand All @@ -882,7 +884,7 @@ def upload(self, filepaths, transcode_quality=3, enable_matching=False):
#404 == already uploaded? serverside check on clientid?
self.log.debug("could not finalize upload of '%s'. response: %s",
path, upload_response)
not_uploaded[path] = 'could not finalize upload'
not_uploaded[path] = 'could not finalize upload; details in log'

self._make_call(musicmanager.UpdateUploadState, 'stopped', self.uploader_id)

Expand Down

0 comments on commit ce9cfdf

Please sign in to comment.