7.2. Howdy Music API

This document describes the lower level Howdy Music API, upon which the command line tools are built. It lives in howdy.music.

7.2.1. howdy.music module

This contains only three methods: two format durations strings for YouTube clips, and a third is used to search for M4A music files that are missing artist or album information.

howdy.music.fill_m4a_metadata(filename, data_dict, verify=True, image_data=None)

Low level method that populates the metadata of an M4A music file.

Parameters:
  • filename (str) – a candidate M4A music file name.

  • data_dict (dict) – a dictionary of candidate music metadata with the following obligatory keys: song, album, artist, year, tracknumber, and total tracks. If the URL of the album image, album url, is defined, then also provides the album image into the M4A file.

  • image_data (BytesIO) – optional argument. If defined, is a BytesIO binary data representation of usually a candidate PNG image file.

howdy.music.format_youtube_date(dt_duration)
Parameters:

dt_duration (datetime) – the datetime

Returns:

a standard second, or MM:SS (such as 4:33), or so on from a datetime returned by parse_youtube_date.

Return type:

str

See also

parse_youtube_date.

howdy.music.get_failing_artistalbum(filename)
Parameters:

filename (str) – a candidate M4A music file name (file must also end in ".m4a").

Returns:

the filename ONLY IF it is missing either album or artist metadata. Otherwise returns None.

Return type:

str

howdy.music.get_m4a_metadata(filename)

Low level method that returns the metadata of an M4A music file.

Parameters:

filename (str) – the M4A music file name.

Returns:

a dict of the music metadata that contains as many of these keys: song, album, artist, date, tracknumber, total tracks, album cover.

Return type:

dict

howdy.music.parse_youtube_date(duration_string)

Parses a duration string that isodate can recognize, such as PT4M33S, into a datetime.

Parameters:

duration_string (str) – duration in isodate format, such as PT4M33S to represent 4 minutes and 33 seconds.

Returns:

the datetime that can be used to infer duration using format_youtube_date.

Return type:

datetime

7.2.2. howdy.music.music module

This contains the low-level functionality that does three things.

class howdy.music.music.HowdyLastFM(data=None, verify=True)

This object uses the LastFM API, through the higher level musicbrainzngs Python module, to get information on songs, albums, and artists. Where possible, this extracts additional song metadata using the MusicBrainz API.

Parameters:
  • data (dict) – optional argument, containg the LastFM API data: api_key, api_secret, application_name, and username. See Section 2.1.4 to understand how to set up the LastFM API credentials. If not given, then gets the LastFM API data from HowdyLastFM.get_lastfm_credentials.

  • verify (bool) – optional argument, whether to verify SSL connections. Default is True.

Variables:
  • api_key (str) – the LastFM API key.

  • api_secret (str) – the LastFM API secret.

  • application_name (str) – the LastFM application name.

  • username (str) – the LastFM API user name.

  • endpoint (str) – the LastFM endpoint, here http://ws.audioscrobbler.com/2.0.

  • verify (bool) – whether to verify SSL connections.

get_album_image(artist_name, album_name)
Parameters:
  • artist_name (str) – the artist name.

  • album_name (str) – album_name.

Returns:

If successful, downloads the album image into a PNG file named “artist_name.album_name.png”, and returns a two-element tuple, whose first element is the PNG filename, and whose second element is the string "SUCCESS". If unsuccessful, then returns a tuple of format return_error_raw.

Return type:

tuple

get_album_info(artist_name, album_name)
Parameters:
  • artist_name (str) – the artist name.

  • album_name (str) – the studio album.

Returns:

a two-element tuple, whose first element is a dict of LastFM API low level information on the album, and whose second element is the string "SUCCESS". For example, for Moon Safari from Air, we have, complicated JSON structure stored in HowdyLastFM get_album_info. If unsuccessful, then returns a tuple of format return_error_raw.

Return type:

tuple

classmethod get_album_url(album_url_entries)

Returns the album URL of the largest album image provided.

Parameters:

album_url_entries (list) – a list of album URL information. Each element is a dict with two keys: #text is the URL, and size is a qualifier on the image size – can be one of mega, extralarge, large, medium, small, or “” (no size given).

Returns:

images sizes are ordered this way – mega, extralarge, large, medium, small, and “”. Returns the URL for the largest sized album image in this collection.

Return type:

str

get_collection_album_info(album_name)
Parameters:

album_name (str) – the name of a compilation album (consisting of multiple artists).

Returns:

a two-element tuple, whose first element is a dict of summary information on tracks for this compilation album, and whose second element is the string "SUCCESS". This dictionary is a low level LastFM data structure. The example low level, nicely formatted JSON representation of this dictionary, for the compilation album, The Politics of Photosynthesis, is located in lastfm_collection_data.json. If unsuccessful, then returns a tuple of format return_error_raw.

Return type:

dict

classmethod get_lastfm_credentials()
Returns:

a dict of LastFM API configuration information from the SQLite3 configuration database: api_key, api_secret, application_name, and username.

Return type:

dict

Raises:

ValueError – if LastFM API credentials could not be found.

classmethod get_mb_album_year(year_string)

Returns a year of release given a MusicBrainz style date string, can be either of the form “2000-12-23” (YYYY-MM-DD)” or just four-digit year.

Parameters:

year_string (str) – a MusicBrainz style date string, can be either of the form “2000-12-23” (YYYY-MM-DD) or just four-digit year.

Returns:

the year corresponding to the release date. If date string is invalid, then returns None.

Return type:

int

get_music_metadata(song_name, artist_name, all_data=False)

Uses the MusicBrainz API to fill out as much metadata as possible for a given song. Before running this method, one should first set the MusicBrainz API header data with MusicInfo.get_set_musicbrainz_useragent.

Parameters:
  • song_name (str) – name of the song.

  • artist_name (str) – name of the artist.

  • all_data (bool) – optional argument. If False, then perform a cursory search for metadata on the selected song. If True, then perform a more careful search. Default is False. Running with True can work if running with False does not produce a result.

Returns:

if successful, returns a two element tuple. First element is a dict of information on the song, and the second element is the string "SUCCESS". For example, for the Air song Kelly Watch the Stars in Moon Safari. the closest match is Kelly, Watch the Stars!.

{'album': 'Moon Safari',
 'artist': 'Air',
 'year': 1998,
 'tracknumber': 4,
 'total tracks': 10,
 'song': 'Kelly, Watch the Stars!',
 'duration': 225.746,
 'album url':
    'https://lastfm.freetls.fastly.net/i/u/300x300/016....png'}

If unsuccessful, then returns a tuple of format return_error_raw.

Return type:

tuple

Note

LastFM does not provide a release date at all. Furthermore, LastFM documentation shown here (https://www.last.fm/api/show/album.getInfo) is incorrect. See, e.g, pylast/pylast#177 and feross/last-fm#2.

get_music_metadatas_album(artist_name, album_name)
Parameters:
  • artist_name (str) – the artist name.

  • album_name (str) – the album name.

Returns:

a two-element tuple, whose first element is a list of summary information on tracks for this album, and whose second element is the string "SUCCESS". The elements in this list are ordered by first song track to last song track. An example first song for the Moon Safari album released by Air is,

{'song': 'La Femme D’argent',
 'artist': 'Air',
 'tracknumber': 1,
 'total tracks': 10,
 'duration': 429.56,
 'album url':
    'https://lastfm.freetls.fastly.net/i/u/300x300/016b6....png',
 'album': 'Moon Safari',
 'year': 1998}

If the album name has not been published by this artist, return a tuple of format return_error_raw.

Return type:

tuple

get_song_listing(artist_name, album_name)
Parameters:
  • artist_name (str) – the artist name.

  • album_name (str) – album_name.

Returns:

If successful, returns a two-element tuple, whose first element is the list of songs ordered by track number, and whose second element is the string "SUCCESS". Each element in this list is a tuple of song number and track number. For example, for Moon Safari by Air,

[("La Femme d'Argent", 1),
 ('Sexy Boy', 2),
 ('All I Need', 3),
 ('Kelly Watch the Stars', 4),
 ('Talisman', 5),
 ('Remember', 6),
 ('You Make It Easy', 7),
 ('Ce Matin-Là', 8),
 ('New Star in the Sky (Chanson Pour Solal)', 9),
 ('Le Voyage De Pénélope', 10)]

If unsuccessful, then returns a tuple of format return_error_raw.

Return type:

tuple

classmethod push_lastfm_credentials(api_data)

Pushes the LastFM API configuration into the SQLite3 configuration database.

Parameters:

api_data (dict) – the dictionary containing the LastFM API data: api_key, api_secret, application_name, and username.

class howdy.music.music.HowdyMusic(verify=True)

This object uses the Gracenote API to get information on songs, albums, and artists. Uses HowdyMusic.get_gracenote_credentials to get the Gracenote API configuration data.

Parameters:

verify (bool) – optional argument, whether to verify SSL connections. Default is True.

Variables:
  • clientID (str) – Gracenote API app client ID.

  • userID (str) – Gracenote API app user ID.

  • verify (bool) – whether to verify SSL connections.

Raises:

ValueError – if cannot find the Gracenote API configuration information in the database.

Warning

As of October 20, 2019, this API may not be generally functional. A discussion is found on the Pygn Python Gracenote API implementation, cweichen/pygn#14.

get_album_image(artist_name, album_name)
Parameters:
  • artist_name (str) – the artist name.

  • album_name (str) – album_name.

Returns:

If successful, downloads the album image into a PNG file named “artist_name.album_name.png”, and returns a two-element tuple, whose first element is the PNG filename, and whose second element is the string "SUCCESS". If unsuccessful, then returns a tuple of format return_error_raw.

Return type:

tuple

classmethod get_gracenote_credentials()
Returns:

a tuple of Gracenote API clientID and userID from the SQLite3 configuration database.

Raises:

ValueError – if cannot find the Gracenote_API configuration information in the database.

get_music_metadata(song_name, artist_name)
Parameters:
  • song_name (str) – name of the song.

  • artist_name (str) – name of the artist.

Returns:

if successful, returns a two element tuple. First element is a dict of information on the song, and the second element is the string "SUCCESS". For example, for the Air song Kelly Watch the Stars in Moon Safari,

{'album': 'Moon Safari',
 'artist': 'Air',
 'year': 1998,
 'tracknumber': 4,
 'total tracks': 10,
 'song': 'Kelly, Watch the Stars!',
 'duration': 225.746,
 'album url':
    'https://lastfm.freetls.fastly.net/i/u/300x300/016b6b....png'}

If unsuccessful, then returns a tuple of format return_error_raw.

Return type:

tuple

get_music_metadata_lowlevel(metadata_song, album_title=None)
Parameters:
  • metadata_song (dict) – the low level dict of Gracenote_API produced track information. Must have track__title, track_number, and album_artist_name keys.

  • album_title (str) – optional argument, the candidate album from which the song came. If not defined, then ablum_title key must be set.

Returns:

if successful, returns a two element tuple. First element is a dict of information on the song, and the second element is the string "SUCCESS". This dictionary defines the following keys: song, artist, tracknumber, total tracks, year, album url, and album. If unsuccessful, then returns a tuple of format return_error_raw.

Return type:

tuple

get_music_metadatas_album(artist_name, album_name)
Parameters:
  • artist_name (str) – the artist name.

  • album_name (str) – the album name.

Returns:

a two-element tuple, whose first element is a list of summary information on tracks for this album, and whose second element is the string "SUCCESS". The elements in this list are ordered by first song track to last song track. An example first song for the Moon Safari album released by Air is,

{'song': 'La Femme D’argent',
 'artist': 'Air',
 'tracknumber': 1,
 'total tracks': 10,
 'duration': 429.56,
 'album url':
    'https://lastfm.freetls.fastly.net/i/u/300x300/016b6....png',
 'album': 'Moon Safari',
 'year': 1998}

If the album name has not been published by this artist, return a tuple of format return_error_raw.

Return type:

tuple

get_song_listing(artist_name, album_name)
Parameters:
  • artist_name (str) – the artist name.

  • album_name (str) – album_name.

Returns:

a list of songs ordered by track number, and whose second element is the string "SUCCESS". Each element in this list is a tuple of song number and track number. For example, for Moon Safari by Air,

[("La Femme d'Argent", 1),
 ('Sexy Boy', 2),
 ('All I Need', 3),
 ('Kelly Watch the Stars', 4),
 ('Talisman', 5),
 ('Remember', 6),
 ('You Make It Easy', 7),
 ('Ce Matin-Là', 8),
 ('New Star in the Sky (Chanson Pour Solal)', 9),
 ('Le Voyage De Pénélope', 10)]

Return type:

list

classmethod push_gracenote_credentials(client_ID, verify=True)

Pushes the Gracenote API configuration into the SQLite3 configuration database.

Parameters:
  • client_ID (str) – the Gracenote API client ID.

  • verify (bool) – optional argument, whether to verify SSL connections. Default is True.

Raises:

ValueError – if the client_ID is invalid, or cannot update the database.

class howdy.music.music.MusicInfo(artist_name, artist_mbid=None, do_direct=False)

This object uses the MusicBrainz API, through the higher level musicbrainzngs Python module, to get information on songs, albums, and artists.

Parameters:
  • artist_name (str) – the artist over which to search.

  • artist_mbid (str) – optional argument. If not None, then information on this artist uses this MusicBrainz artist ID to get its info. Default is None.

  • do_direct (bool) – optional argument. If True, then perform a direct search on the artist rather than using the default indexed search at a low lebvel. Default is False. See :py:meth`get_artist_direct_search_MBID <howdy.music.music.MusicInfo.get_artist_direct_search_MBID>` for the low-level functionality.

Variables:
  • artist (dict) –

    the low level information on a specific artist, returned by musicbrainzngs. For example, for the artist Air, this looks like,

    {'id': 'cb67438a-7f50-4f2b-a6f1-2bb2729fd538',
     'type': 'Group',
     'ext:score': '100',
     'name': 'Air',
     'sort-name': 'Air',
     'country': 'FR',
     'area': {'id': '08310658-51eb-3801-80de-5a0739207115',
      'type': 'Country',
      'name': 'France',
      'sort-name': 'France',
      'life-span': {'ended': 'false'}},
     'begin-area': {'id': '2322e571-1d9b-4023-a31c-7222509407ab',
      'type': 'City',
      'name': 'Versailles',
      'sort-name': 'Versailles',
      'life-span': {'ended': 'false'}},
     'disambiguation': 'French band',
     'isni-list': ['0000000123694584'],
     'life-span': {'begin': '1995', 'ended': 'false'},
     'alias-list': [
      {'sort-name': 'Air French Band', 'alias': 'Air French Band'},
      {'sort-name': 'Air (French Band)', 'alias': 'Air (French Band)'},
      {'sort-name': 'Aïr', 'alias': 'Aïr'}],
     'tag-list': [{'count': '2', 'name': 'trip-hop'},
      {'count': '10', 'name': 'electronic'},
      {'count': '7', 'name': 'downtempo'},
      {'count': '0', 'name': 'soundtrack'},
      {'count': '0', 'name': 'pop'},
      {'count': '2', 'name': 'chillout'},
      {'count': '5', 'name': 'ambient'},
      {'count': '0', 'name': 'jazz'},
      {'count': '7', 'name': 'french'},
      {'count': '1', 'name': 'idm'},
      {'count': '0', 'name': 'france'},
      {'count': '0', 'name': 'français'},
      {'count': '3', 'name': 'electronica'},
      {'count': '0', 'name': 'producer'},
      {'count': '0', 'name': 'composer'},
      {'count': '0', 'name': 'lyricist'},
      {'count': '0', 'name': 'european'},
      {'count': '0', 'name': 'parolier'},
      {'count': '0', 'name': 'compositeur'},
      {'count': '0', 'name': 'producteur'},
      {'count': '0', 'name': 'dance and electronica'},
      {'count': '2', 'name': 'ambient pop'}]}
    

  • artist_name (str) – the artist’s name.

  • ambid (int) – the MusicBrainz artist ID.

  • alltrackdata (dict) –

    the low-level dict of information on all studio albums produced by the artist. Each key in this top level dictionary is a studio album. Each value is a lower level dictionary of summary information on that album, with the following keys.

    • release-date is the date when that album was released.

    • album-url if defined, is the URL to the album’s image. If not defined, then it is an empty str.

    • tracks is a dict of tracks on this album. Each key is the track number, and each value is a tuple of song name, and song length.

    For example, here is information on the Moon Safari album released by Air.

    {'release-date': datetime.date(1998, 1, 16),
     'album url': '',
     'tracks': {1: ('La Femme D’argent', 429.56),
      2: ('Sexy Boy', 298.466),
      3: ('All I Need', 268.333),
      4: ('Kelly, Watch the Stars!', 225.746),
      5: ('Talisman', 256.48),
      6: ('Remember', 154.293),
      7: ('You Make It Easy', 240.826),
      8: ('Ce Matin-Là', 218.506),
      9: ('New Star in the Sky (Chanson Pour Solal)', 340.8),
      10: ('Le Voyage De Pénélope', 190.866)}}
    

get_album_image(album_name)
Parameters:

album_name (str) – album_name.

Returns:

If successful, downloads the album image into a PNG file named “artist_name.album_name.png”, and returns a two-element tuple, whose first element is the PNG filename, and whose second element is the string "SUCCESS". If unsuccessful, then returns a tuple of format return_error_raw.

Return type:

tuple

classmethod get_album_info(album)
Parameters:

album (dict) – a dictionary of low-level album info returned by musicbrainzngs associated with this studio album.

Returns:

a two-element tuple if successful, otherwise returns None. The first is the studio album name, and each second element is a dict containing summary album info of that album. See the altrackdata dictionary in MusicInfo to understand the description of summary album information.

Return type:

tuple

classmethod get_albums_lowlevel(ambid, do_all=False)

Used by the constructor to get the collection of studio albums released by this artist.

Parameters:
  • ambid (int) – the MusicBrainz artist ID.

  • do_all (bool) – if True, then return all the MusicBrainz album info provided. If False, then do not include albums that have been classified as remixes or mixtapes. Default is False.

Returns:

a list, where each element of the list is low-level musicbrainzngs music collection information. The album information is a dict with the following keys,

  • id is the MusicBrainz album ID.

  • type is the type of the release (for example, Album s a studio released album).

  • title is the name of the release.

  • first-release-date is the release date, as a str.

  • primary-type is the main type of the release.

For example, for the artist Air, whose MusicBrainz artist ID is "cb67438a-7f50-4f2b-a6f1-2bb2729fd538", an example first element in the list is,

{'id': 'b0bf2b77-b8cf-32f6-8893-9741d757b400',
 'type': 'Album',
 'title': 'Moon Safari',
 'first-release-date': '1998-01-16',
 'primary-type': 'Album'}

Return type:

list

classmethod get_artist_datas_LL(artist_name, min_score=100, do_strict=True, artist_mbid=None, do_direct=False)
Parameters:
  • artist_name (str) – the artist over which to search.

  • min_score (int) – optional argument. Filter on this minimum score on artist name matches to artist_name. 0 \(\le\) min_score \(\le 100\). Default is 100.

  • do_strict (bool) – optional argument. If True, performs a strict search using the musicbrainzngs search_artists method. Default is True.

  • artist_mbid (str) – optional argument. If not None, then uses musicbrainzngs’s get_artist_by_id to get information on an artist. Otherwise, gets all artist matches. Default is None.

  • do_direct (bool) – Sometimes the MusicBrainz server does not update. Fixes-when-broken of the MusicBrainz server do not happen on a schedule, or even a quickness. In such an instance, you can specify the specific artist using direct search rather than indexed search. See :py:meth`get_artist_direct_search_MBID <howdy.music.music.MusicInfo.get_artist_direct_search_MBID>`.

Returns:

a list of artist information matches to artist_name. If artist_mbid is not None, then gets a SINGLE artist match. Otherwise gets all matches found.

Return type:

list

classmethod get_artist_direct_search_MBID(artist_name)

Sometimes the MusicBrainz server does not update. Fixes-when-broken of the MusicBrainz server do not happen on a schedule, or even a quickness. In such an instance, you can specify the specific artist using direct search rather than indexed search. This method returns the artist’s MBID of the artist one queries. If there is more than one match, then returns None.

Parameters:

artist_name (str) – the artist over which to perform a search.

Returns:

the MBID of the artist. If more than one matching artist is found, or no matching artists, then returns None.

get_music_metadata(song_name, min_criterion_score=85)
Parameters:
  • song_name (str) – name of the song.

  • min_criterion_score (int) – the minimum score to accept for a string similarity comparison between song_name and any track created by this artist. 70 \(\le\) min_criterion_score \(\le\) 100, and the default is 85. The get_maximum_matchval performs the string comparison. If no track matches song_name, then track data for a track that is the closest match (while having a similarity score \(\ge\) min_criterion_score) to song_name is returned.

Returns:

if successful, a two element tuple. First element is a dict of information on the song, and the second element is the string "SUCCESS". For example, for the Air song Kelly Watch the Stars in Moon Safari, the closest match is Kelly, Watch the Stars!.

{'album': 'Moon Safari',
 'artist': 'Air',
 'year': 1998,
 'tracknumber': 4,
 'total tracks': 10,
 'song': 'Kelly, Watch the Stars!',
 'duration': 225.746,
 'album url': 'http://...2-490838855977/21141679576.jpg'}

If unsuccessful, then returns a tuple of format return_error_raw.

Return type:

tuple

get_music_metadatas_album(album_name, min_criterion_score=95)
Parameters:
  • album_name (str) – a studio album released by this artist.

  • min_criterion_score (int) – the minimum score to accept for a string similarity comparison between album_name and any studio album created by this artist. 70 \(\le\) min_criterion_score \(\le\) 100, and the default is 95. The get_maximum_matchval performs the string comparison. If no album matches album_name, then return album data for the album whose name is closest (while having a similarity score \(\ge\) min_criterion_score) to album_name is returned.

Returns:

a two-element tuple, whose first element is a list of summary information on tracks for this album, and whose second element is the string "SUCCESS". The elements in this list are ordered by first song track to last song track. An example first song for the Moon Safari album released by Air is,

{'artist': 'Air',
 'album': 'Moon Safari',
 'year': 1998,
 'total tracks': 10,
 'song': 'La Femme D’argent',
 'tracknumber': 1,
 'album url': '',
 'duration': 429}

If the album name has not been published by this artist, return a tuple of format return_error_raw.

Return type:

tuple

classmethod get_set_musicbrainz_useragent(email_address)
Parameters:

email_address (str) – a valid email address to provide to provide to the MusicBrainz API’s user agent.

Returns:

a dict whose two keys and values are,

  • appname is the application name registered with the MusicBrainz API.

  • version is the application version.

This information comes from the SQLite3 configuration database.

Return type:

dict

Raises:

ValueError – if the MusicBrainz API configuration information cannot be found.

get_song_listing(album_name)
Parameters:

album_name (str) – album_name.

Returns:

If successful, returns a two-element tuple, whose first element is the list of songs ordered by track number, and whose second element is the string "SUCCESS". Each element in this list is a tuple of song number and track number. For example, for Moon Safari by Air,

[("La Femme d'Argent", 1),
 ('Sexy Boy', 2),
 ('All I Need', 3),
 ('Kelly Watch the Stars', 4),
 ('Talisman', 5),
 ('Remember', 6),
 ('You Make It Easy', 7),
 ('Ce Matin-Là', 8),
 ('New Star in the Sky (Chanson Pour Solal)', 9),
 ('Le Voyage De Pénélope', 10)]

If unsuccessful, then returns a tuple of format return_error_raw.

Return type:

tuple

print_format_album_names()

Pretty-prints summary table of studio albums released by the artist, ordered by album release date. For example, for Air,

Air has 7 studio albums.

Studio Album                         Year    # Tracks
---------------------------------  ------  ----------
Moon Safari                          1998          10
10 000 Hz Legend                     2001          12
City Reading (Tre Storie Western)    2003          19
Talkie Walkie                        2004          11
Pocket Symphony                      2006          12
Love 2                               2009          12
Music for Museum                     2014           9
classmethod push_musicbrainz_useragent(appname, version)

Pushes the MusicBrainz API configuration into the SQLite3 configuration database.

Parameters:
  • appname (str) – the application name registered with the MusicBrainz API.

  • version (str) – the application version.

classmethod set_musicbrainz_verify(verify=True)

Makes the MusicBrainz API to use either HTTPS (if verifying traffic) or HTTP (if not verifying traffic)

Parameters:

verify (bool) – optional argument, whether to verify SSL connections. Default is True.

howdy.music.music.download_best_song(artist_name, song_name, youtube=None, verify=True)

If successful, downloads the most likely YouTube clip into an M4A file, whose name is "artist_name"."song_name".m4a. Uses the LastFM API functionality, through HowdyLastFM, to get the music metadata.

Parameters:
  • artist_name (str) – the artist name.

  • song_name (str) – name of the song.

  • youtube (Resource) – optional aegument, a googleapiclient Resource object that allows for the access to the YouTube Google API. If not defined, then instantiated with get_youtube_service.

  • verify (bool) – optional argument, whether to verify SSL connections. Default is True.

Returns:

if successful, the file name of the downloaded M4A song ("artist_name"."song_name".m4a). If cannot find the song metadata, or cannot find YouTube clips for this song, then returns None.

howdy.music.music.get_gmusic_all_songs(verify=True, device_id=None)

Returns a dict of all songs stored on one’s Google Play Music account. Each key is an unique song ID, and each value is summary information for that song. Example element output looks like,

{'kind': 'sj#track',
 'id': 'fe65be9b-5e0d-39f8-a104-34579cac7d25',
 'clientId': '0xjqU3q/jCIkKK+42LXx+A',
 'creationTimestamp': '1312046208050197',
 'lastModifiedTimestamp': '1385273200005040',
 'recentTimestamp': '1312050096197000',
 'deleted': False,
 'title': "Why Can't There Be Love (Pilooski Edit)",
 'artist': 'Pilooski',
 'composer': 'Hermon Weems',
 'album': 'Saint-Germain-Des-Pres Cafe (The Blue Edition)',
 'albumArtist': 'Saint-Germain-Des-Prés Café (Selected and mixed by Mr Scruff)',
 'year': 2010,
 'comment': '',
 'trackNumber': 15,
 'genre': 'Dance & DJ',
 'durationMillis': '180720',
 'beatsPerMinute': 0,
 'albumArtRef': [{'kind': 'sj#imageRef',
   'url': 'http://lh5.ggpht.com/Czw3aqGNeQdsXMy9EnaAoC92F3WZHvKO2iqRGyZouUodlJqTP3anpjxb7qdLTdsPae1evBD0'}],
 'playCount': 0,
 'totalTrackCount': 0,
 'discNumber': 0,
 'totalDiscCount': 0,
 'rating': '0',
 'estimatedSize': '5782883',
 'storeId': 'Tovfqdqypwu27btjcetswr464qe',
 'albumId': 'B4utisa64lnb5bja5hg3ym5efrm',
 'artistId': ['A5yefhy34gybvo5okv4hfychfia'],
 'nid': 'Tovfqdqypwu27btjcetswr464qe'}

If cannot access the account, returns None.

Parameters:
  • verify (bool) – optional argument, whether to verify SSL connections. Default is True.

  • device_id (str) – optional argument. If defined, then attempt to use this MAC ID to register the music manager.

Raises:

ValueError – if cannot find and use the correct device ID.

howdy.music.music.get_gmusicmanager(useMobileclient=False, verify=True, device_id=None)

Returns a GmusicAPI manager used to perform operations on one’s Google Play Music account. If the Musicmanager is instantiated but cannot find the device (hence properly authorize for operation), then the attribute error_device_ids is a non-empty set of valid device IDs.

Parameters:
  • useMobileClient (bool) – optional argument. If True, use the MobileClient manager, otherwise use the Musicmanager manager. Default is False.

  • verify (bool) – optional argument, whether to verify SSL connections. Default is True.

  • device_id (str) – optional argument. If defined, then attempt to use this MAC ID to register the music manager.

Raises:

See also

gmusicmanager.

howdy.music.music.get_youtube_file(youtube_URL, outputfile, use_aria2c=True)

Uses youtube-dl programmatically to download into an M4A file.

Parameters:
  • youtube_URL (str) – a valid YouTube URL for the song clip.

  • outputfile (str) – the M4A music file name.

  • use_aria2c (bool) – use the aria2c downloader. Implicitly requires that aria2c exists on the server.

howdy.music.music.get_youtube_service(verify=True)

Gets the YouTube Google API service from the Google OAuth2 credentials stored in the SQLite3 configuration database.

Parameters:

verify (bool) – optional argument, whether to verify SSL connections. Default is True.

Returns:

a googleapiclient Resource object that allows for the access to the YouTube Google API.

howdy.music.music.gmusicmanager(useMobileclient=False, verify=True, device_id=None)

Returns a contextmanager wrapped GmusicAPI manager used to perform operations on one’s Google Play Music account.

Parameters:
  • useMobileClient (bool) – optional argument. If True, use the MobileClient manager, otherwise use the Musicmanager manager. Default is False.

  • verify (bool) – optional argument, whether to verify SSL connections. Default is True.

  • device_id (str) – optional argument. If defined, then attempt to use this MAC ID to register the music manager.

See also

get_gmusicmanager.

howdy.music.music.gmusicmanager_fixlogin(mmg)

Workaround to deal with following problem: cannot create an authorized GmusicAPI Mobileclient because the device ID automatically found is not one of the set of authorized device IDs.

Parameters:

mmg (Mobileclient) – the erroring out Mobileclient music manager.

Raises:
  • ValueError – if the music manager has not errored out.

  • ValueError – if the music manager is not a Mobileclient.

See also

get_gmusicmanager.

howdy.music.music.oauth_get_google_credentials()

Gets the Google Oauth2 credentials, stored in the SQLite3 configuration database, in the form of a refreshed AccessTokenCredentials object. This OAuth2 authentication method IS used only for the GMusicAPI Mobileclient manager.

Returns:

a AccessTokenCredentials form of the Google Oauth2 credentials for various Oauth2 services.

Return type:

AccessTokenCredentials

howdy.music.music.oauth_store_google_credentials(credentials)

Stores the Google OAuth2 credentials, in the form of a AccessTokenCredentials object, into the SQLite3 configuration database for the MobileClient manager.

Parameters:

credentials – the AccessTokenCredentials object to store into the database.

howdy.music.music.plexapi_music_playlist_info(plex_playlist, use_internal_metadata=False)

This creates a DataFrame out of the PlexAPI Playlist. This DataFrame has the following columns:

  • order in playlist

  • filename

  • added date

  • song name

  • artist

  • track number

  • album

  • album number of tracks

  • album year

Parameters:
  • plex_playlist (PlexAPI PlayList) – the PlexAPI Playlist, which must be an audio playlist.

  • use_internal_metadata (bool) – if True, then fill out columns using the M4A metadata from the file, otherwise fill out the columns using information in plex_playlist. Default is False.

Returns:

a DataFrame of useful track information for the playlist.

Return type:

DataFrame

howdy.music.music.save_gmusic_creds(email, password)

Pushes one’s Google account email and password into the gmusic configuration stored in the SQLite3 configuration database.

Parameters:
  • email (str) – Google account email address.

  • password (str) – Google account password.

howdy.music.music.upload_to_gmusic(filenames, verify=True)

Uploads a collection of music files to the Google Play Music account.

Parameters:
  • filenames (list) – a list of candidate files to upload.

  • verify (bool) – optional argument, whether to verify SSL connections. Default is True.

Performs a string query to search through YouTube clips, and returns list of valid YouTube URLs.

Parameters:
  • youtube (Resource) – a googleapiclient Resource object that allows for the access to the YouTube Google API.

  • query (str) – the string on which to search.

  • max_results (int) – optional argument, the maximum number of YouTube clips to return. Must be \(\ge 1\). Default is 10.

Returns:

a list of YouTube URLs of clips that satisfy the query.

Return type:

list

7.2.3. howdy.music.music_spotify module

These module handles integration with the Spotify RESTful API that does the following things:

  • Methods to handle authentication to the Spotify API. See this blog article on the Spotify Web API on how to set up a Spotify Web API client, and to acquire your client ID and client secret.

  • Methods to copy the Spotify song ID into an M4A song file’s metadata, and to get the Spotify song ID of the song.

  • Methods that returns the Spotify ID based on a song’s metadata.

  • Methods that show, create, modify the current user’s Spotify public playlists.

  • Methods that convert a DataFrame representing a Plex music playlist into a DataFrame representing a data structure that can be converted into a Spotify public playlist.

In this API I refer to the Spotify ID of a song, which has format :spotify:track:<STRING>. For example, the song All I Need by Air the French band has a Spotify ID = spotify:track:6T10XPeC9X5xEaD6tMcK6M. It can be found at https://open.spotify.com/track/6T10XPeC9X5xEaD6tMcK6M.

howdy.music.music_spotify.create_public_playlist(oauth2_access_token, name, description, my_userid=None)

Creates a new public Spotify playlist for the current user.

Parameters:
  • oauth2_access_token (str) – the Spotify access token for the OAuth2-authenticated Spotify API. One needs this token to access, add, delete, and modify Spotify playlists.

  • name (str) – name of the new playlist.

  • description (str) – the new playlist’s description.

  • my_userid (str) – Optional argument, which is the Spotify current user ID. If not specified, then determines the current user ID using the OAuth2-authenticated Spotify API.

Returns:

status on whether it can create the playlist. If a playlist, with the same name exists, does nothing and returns False. Otherwise, if no other public playlist (owned by the current user) exists, creates the playlist and returns True.

Return type:

bool

howdy.music.music_spotify.get_existing_track_ids_in_spotify_playlist(spotify_playlist_id, oauth2_access_token)

Low-level method that returns the list of Spotify IDs in a public Spotify playlist. Spotify API quirk: can only get the Spotify IDs in units of 100 at most per Spotify API query.

Parameters:
  • spotify_playlist_id (str) – the Spotify public playlist ID.

  • oauth2_access_token (str) – the Spotify access token for the OAuth2-authenticated Spotify API. One needs this token to access, add, delete, and modify Spotify playlists.

Returns:

the list of Spotify IDs in a public Spotify playlist. Each Spotify ID is a string.

Return type:

list.

howdy.music.music_spotify.get_or_push_spotify_oauth2_token()
Returns:

the Spotify API OAuth2 token that allows you to access, add, delete, and modify Spotify playlists.

Return type:

str

howdy.music.music_spotify.get_public_playlists(oauth2_access_token, my_userid=None)

Returns all the Spotify public playlists for the current user.

Parameters:
  • oauth2_access_token (str) – the Spotify access token for the OAuth2-authenticated Spotify API. One needs this token to access, add, delete, and modify Spotify playlists.

  • my_userid (str) – Optional argument, which is the Spotify current user ID. If not specified, then determines the current user ID using the OAuth2-authenticated Spotify API.

Returns:

a list of summary information on the current user’s public Spotify playlists. Each entry is a dict with the following attributes: its name, description, the Spotify ID of the playlist, the Spotify ID of the user who owns the playlist, and the number of songs in the playlist.

Return type:

list

howdy.music.music_spotify.get_spotify_credentials()
Returns:

a dict whose two keys and values are the client_id and the client_secret for the Spotify web API client in the SQLite3 configuration database.

Return type:

dict

howdy.music.music_spotify.get_spotify_session()

Returns the session token from a valid Spotify API account. :rtype: str

howdy.music.music_spotify.get_spotify_song_id(spotify_access_token, song_metadata_dict, song_limit=5, market='us', dump_response=False, response_file='foo.json')

Heavily-instrumented lower-level method that attempts to find the Spotify ID of a song given its metadata.

Parameters:
  • spotify_access_token (str) – the session’s current Spotify access token for the non-authenticated Spotify API.

  • song_metadata_dict (dict) – the dictionary of a song’s metadata, which has at least the following fields:

  • song is the song title.

  • artist is the song’s artist.

  • date is the album’s release date, of type date.

  • album is the song’s album.

Parameters:
  • dump_response (bool) – by default it is False. If True, then dump interesting information into a JSON file.

  • response_file (str) – by default it is foo.json. This is the name of the JSON file to dump interesting debugging information on this method call used to find a song’s Spotify ID.

Returns:

a str of various types.

  • If the underlying Spotify API call fails, then returns the Spotify API error message.

  • If the Spotify API call is successful, but for some reason cannot find the Spotify ID, returns a message that states.

    CANNOT FIND SPOTIFY TRACK ID FOR <SPOTIFY_QUERY>

    Where <SPOTIFY_QUERY> is the low-level Spotify API query used to search for that song’s Spotify ID.

  • In the best, nominal operation case, returns the Spotify ID.

Return type:

str

howdy.music.music_spotify.get_spotify_song_id_filename(filename)

Returns the Spotify ID found in the M4A file.

Parameters:

filename (str) – the M4A song file name.

Returns:

the Spotify ID of the song if it could be found. Otherwise returns None.

Return type:

str

howdy.music.music_spotify.modify_existing_playlist_with_new_tracks(spotify_playlist_id, oauth2_access_token, spotify_ids_list, spotify_ids_in_playlist=None)

Lower-level method that replaces the collection of songs in Spotify playlist, identified by spotify_playlist_id, with a new collection of Spotify IDs in spotify_ids_list. Interesting Spotify API wrinkle: one can use the Spotify API to remove as many songs from a playlist as possible; one can use the Spotify API to add songs to a playlist in chunks of at most 100 songs.

Parameters:
  • spotify_playlist_id (str) – the Spotify public playlist ID.

  • oauth2_access_token (str) – the Spotify access token for the OAuth2-authenticated Spotify API. One needs this token to access, add, delete, and modify Spotify playlists.

  • spotify_ids_list (list) – the new list of Spotify IDs corresponding to an updated Spotify playlist.

  • spotify_ids_in_playlist (list) – optional argument. If not specified, then uses get_existing_track_ids_in_spotify_playlist to get the list of Spotify IDs for the playlist specified by spotify_playlist_id. If this is specified, then method assumes that this is the list of Spotify IDs for this playlist.

howdy.music.music_spotify.process_dataframe_playlist_spotify(df_playlist, spotify_access_token)

Low-level method that takes a DataFrame representing a Plex playlist (its schema is described in plexapi_music_playlist_info) and converts it into a DataFrame. This returned DataFrame has a column representing Spotify ID.

For each song it finds in the input playlist, df_playlist, it tries to find the Spotify ID.

  1. If it finds the Spotify ID in the M4A file’s metadata, returns that.

  2. If not, it queries the song’s title, artist, album, and year. If it finds the Spotify ID then it returns it.

  3. If not, it queries on a modified song title – replacing mentions of “feat” or “Feat” or variations of “featuring”, title, album, and year. If it finds the Spotify ID then it returns it.

  4. If not, it queries on the modified song title, artist, and album. If it find the Spotify ID then it returns it.

  5. If not, it queries on the modified song title and artist. If it finds the Spotify ID then it returns it.

  6. Finally, if not, returns the error message associated with the above query or other Spotify API error message.

Parameters:
Returns:

the DataFrame with an extra string column, named SPOTIFY ID. Its value is either a valid Spotify ID or other error message.

Return type:

DataFrame

howdy.music.music_spotify.process_dataframe_playlist_spotify_bads(df_playlist_spotify, spotify_access_token)

Necessary method to purify the collection of songs for which we do not have Spotify IDs. For those songs that do not have valid Spotify IDs, it uses the Spotify API to try to find valid Spotify IDs. For each song it tries, if it does find a valid ID, it pushes that ID into the song file (using push_spotify_song_id_to_file).

Parameters:
  • df_playlist_spotify (DataFrame) – the DataFrame of songs. This consists of songs that have valid Spotify IDs and those that do not have valid Spotify IDs.

  • spotify_access_token (str) – the session’s current Spotify access token for the non-authenticated Spotify API.

Returns:

a 2-element tuple: the first element is the number of songs for which it found a Spotify ID; the second element is the number of bad (initially did not have Spotify ID) songs it processed.

Return type:

tuple

howdy.music.music_spotify.process_dataframe_playlist_spotify_multiproc(df_playlist, spotify_access_token, numprocs=12)

Method that chunks out the identification of Spotify IDs from a Plex playlist among multiple processors. It uses process_dataframe_playlist_spotify on each processor chunk of the input Plex music playlist DataFrame.

Parameters:
Returns:

the DataFrame with an extra string column, named SPOTIFY ID. Its value is either a valid Spotify ID or other error message.

Return type:

DataFrame

howdy.music.music_spotify.push_spotify_credentials(client_id, client_secret, verify=True)

Pushes the Spotify API configuration into the SQLite3 configuration database. Take a look at this blog article on the Spotify API for some more information on setting up your Spotify web API client.

Parameters:
  • client_id (str) – the Spotify client ID.

  • client_secret (str) – the Spotify client secret.

  • verify (bool) – if True, then use HTTPS authentication. Otherwise do not. Default is True.

howdy.music.music_spotify.push_spotify_song_id_to_file(spotify_id, filename)

This copies the Spotify ID of a song to a given M4A file. This puts the Spotify ID into the comments tags in the M4A file.

Parameters:
  • spotify_id (str) – The Spotify ID of a song.

  • filename (str) – the M4A song file name.

7.2.4. howdy.music.pygn module

This contains functionality used by the HowdyMusic higher level object interface to the Gracenote API.

pygn (pronounced “pigeon”) is a simple Python client for the Gracenote Music Web API, which can retrieve Artist, Album and Track metadata with the most common options.

You will need a Gracenote Client ID to use this module. Please contact developers@gracenote.com to get one.

This module has been enhanced in the following ways beyond the main version, that lives in https://github.com/cweichen/pygn.

  • Uses the requests module for HTTP processing.

  • debug logging is now handled through the logging module in DEBUG mode.

  • extensively fleshed out documentation.

howdy.music.pygn.createRadio(clientID, userID, artist='', track='', mood='', era='', genre='', popularity=None, similarity=None, count=10, verify=True)

Queries a set of radio stations on Gracenote to create, and returns a list of gnmetadata dictionaries corresponding to those radio stations that have been created. This was created by the GitHub user Fabian to cover the Gracenote Rhythm API.

Parameters:
  • clientID (str) – the Gracenote client ID.

  • userID (str) – the Gracenote user ID.

  • artist (str) – the artist name.

  • track (str) – the song name.

  • mood (str) – the song mood.

  • era (str) – the song era.

  • genre (str) – the genre.

  • popularity (str) – optional argument. The song popularity.

  • similarity (str) – optional argument. The song similariy.

  • count (int) – optional argument, the maximum number of matches to return, must be \(\ge 1\). Default is 10.

  • verify (bool) – optional argument, whether to verify SSL connections. Default is True.

Returns:

a list of gnmetadata radio stations that match the above query.

Return type:

list

Raises:
  • ValueError – if all of artist, track, mood, era, and genre are empty.

  • ValueError – if count \(\le 0\).

howdy.music.pygn.fetch(clientID, userID, GNID, verify=True)

Fetches a track or album by their Gracenote API ID.

Parameters:
Returns:

a gnmetadata containing the metadata for the album.

Return type:

gnmetadata

howdy.music.pygn.get_discography(clientID, userID, artist, rangeStart=1, rangeEnd=10, verify=True)

Queries the Gracenote API service for all albums containing an artist.

Parameters:
  • clientID (str) – the Gracenote client ID.

  • userID (str) – the Gracenote user ID.

  • artist (str) – the artist name.

  • rangeStart (int) – optional argument. This is the order for the HIGHEST cardinal rank of an album that matches a given album name associated with the artist (lower number is better). Must be \(\ge 1\), and default is 1.

  • rangeEnd (int) – optional argument. This is the order for the LOWEST cardinal rank of an album that matches a given album name associated with the artist (lower number is better). Must be \(\ge 1\), \(ge\) rangeStart, and default is 10.

  • verify (bool) – optional argument, whether to verify SSL connections. Default is True.

Returns:

a list of all albums found for artist. Each album is stored as gnmetadata.

Return type:

gnmetadata

class howdy.music.pygn.gnmetadata

This class is a dictionary containing metadata fields that are available for the queried item.

howdy.music.pygn.radioEvent(clientID, userID, radioID, GNID, event='TRACK_PLAYED', count=10, popularity=None, similarity=None, verify=True)

Queries a set of radio stations on Gracenote to find based on certain queries, and returns a list of gnmetadata dictionaries corresponding to those radio stations that have been found. This was created by the GitHub user Fabian to cover the Gracenote Rhythm API.

Parameters:
  • clientID (str) – the Gracenote client ID.

  • userID (str) – the Gracenote user ID.

  • GNID (str) – the Gracenote music ID of the music data.

  • event (str) – optional argument, search on what happened to the song whose Gracenote ID is GNID. Default is TRACK_PLAYED.

  • genre (str) – the genre.

  • count (int) – optional argument, the maximum number of matches to return, must be \(\ge 1\). Default is 10.

  • popularity (str) – optional argument. The song popularity.

  • similarity (str) – optional argument. The song similariy.

  • verify (bool) – optional argument, whether to verify SSL connections. Default is True.

Returns:

a list of gnmetadata radio stations that match the above query.

Return type:

list

Raises:

ValueError – if count \(\le 0\).

howdy.music.pygn.register(clientID, verify=True)

This function registers an application as a user of the Gracenote service.

It takes as a parameter a clientID string in the form of “NNNNNNN-NNNNNNNNNNNNNNNNNNNNNNNNNNNNNNN” and returns a userID in a similar format.

As the quota of number of users (installed applications or devices) is typically much lower than the number of queries, best practices are for a given installed application to call this only once, store the UserID in persistent storage (e.g. filesystem), and then use these IDs for all subsequent calls to the service.

Parameters:
  • clientID (str) – the Gracenote client ID.

  • verify (bool) – optional argument, whether to verify SSL connections. Default is True.

Returns:

the Gracenote user ID if valid client ID.

Return type:

str

howdy.music.pygn.search(clientID, userID, artist='', album='', track='', toc='', verify=True)

Queries the Gracenote service for a track, album, artist, or TOC entry. TOC is a string of offsets in the format, 150 20512 30837 50912 64107 78357 ....

Parameters:
  • clientID (str) – the Gracenote API client ID.

  • userID (str) – the Gracenote API user ID.

  • artist (str) – the artist name.

  • album (str) – the song album.

  • track (str) – the song name.

  • toc (str) – the album’s string of offsets in the following format, 150 20512 30837 50912 64107 78357 ....

  • verify (bool) – optional argument, whether to verify SSL connections. Default is True.

Returns:

a gnmetadata of album metadata corresponding to this query.

Return type:

gnmetadata

Raises:

ValueError – if all of artist, album, track, toc, are empty.