#!/usr/bin/env python
# -*- coding: utf-8 -*-
# File: spotifyclient.py
#
# Copyright 2017 Oriol Fabregas
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
#
"""
Main code for spotifyclient
.. _Google Python Style Guide:
http://google.github.io/styleguide/pyguide.html
"""
from spotifylib import Spotify
import logging
__author__ = '''Oriol Fabregas <fabregas.oriol@gmail.com>'''
__docformat__ = '''google'''
__date__ = '''2017-10-13'''
__copyright__ = '''Copyright 2017, Oriol Fabregas'''
__credits__ = ["Oriol Fabregas"]
__license__ = '''MIT'''
__maintainer__ = '''Oriol Fabregas'''
__email__ = '''<fabregas.oriol@gmail.com>'''
__status__ = '''Development''' # "Prototype", "Development", "Production".
# This is the main prefix used for logging
LOGGER_BASENAME = '''spotifyclient'''
LOGGER = logging.getLogger(LOGGER_BASENAME)
LOGGER.addHandler(logging.NullHandler())
[docs]class SpotifyClient(object):
def __init__(self,
client_id,
client_secret,
username,
password,
callback,
scope):
"""
Initialise object to interact with Spotify API
+info: https://github.com/wefner/spotifylib
Args:
client_id: string
client_secret: string
username: string
password: string
callback: string
scope: string
"""
self._logger = logging.getLogger('{base}.{suffix}'
.format(base=LOGGER_BASENAME,
suffix=self.__class__.__name__)
)
self._username = username
self._spotify = Spotify(client_id=client_id,
client_secret=client_secret,
username=username,
password=password,
callback=callback,
scope=scope)
self._playlists = None
@property
def playlists(self):
"""
Get all playlists for the user within its scope
It also passes username and Spotify instance as it is needed for
Playlist object
Returns: list of Playlist objects
"""
if not self._playlists:
raw_playlists = self._spotify.user_playlists(self._username)
self._playlists = [Playlist(self._username, self._spotify, playlist)
for playlist in raw_playlists.get('items')]
return self._playlists
[docs] def get_track_by_title(self, track_title, limit=5):
"""
Looks up on Spotify for a text string and returns tracks if found
The limit is an optional argument to retrieve more results
Examples:
'Eric Clapton - Cocaine'
"Bon Jovi - Livin' On A Prayer"
Args:
track_title: string
limit: integer
Returns: list of Track objects
"""
self._logger.debug('Looking for title: %s', track_title)
songs = self._spotify.search(q=track_title.encode('utf-8'), limit=limit, type='track')
return [Track(track) for track in songs.get('tracks', {}).get('items')]
[docs] def get_playlist_by_name(self, playlist_name):
"""
Looks into all playlists and returns the one that matched
Args:
playlist_name: string
Returns: Playlist object
"""
playlist = next((plist for plist in self.playlists
if plist.name == playlist_name), None)
return playlist
[docs]class Track(object):
"""Model for a Track"""
def __init__(self, track_details):
"""
Initialise object
Args:
track_details: dictionary
"""
self._track_details = track_details
@property
def uri(self):
"""
URI of the track
Returns: URI
"""
return self._track_details.get('uri', None)
@property
def track_id(self):
"""
Track ID
Returns: string
"""
return self._track_details.get('id', None)
@property
def popularity(self):
"""
Popularity of the track
Returns: integer
"""
return self._track_details.get('popularity', None)
@property
def name(self):
"""
Name of the track
Returns: string
"""
return self._track_details.get('name', None)
@property
def duration_ms(self):
"""
Duration in milliseconds
Returns: integer
"""
return self._track_details.get('duration_ms', None)
[docs]class Playlist(object):
"""Playlist model"""
def __init__(self, username, spotify_instance, playlist_details):
"""
Initialise object
Args:
username: string
spotify_instance: SpotifyClient object
playlist_details: dictionary
"""
self._logger = logging.getLogger('{base}.{suffix}'
.format(base=LOGGER_BASENAME,
suffix=self.__class__.__name__)
)
self._username = username
self._spotify = spotify_instance
self._playlist_details = playlist_details
@property
def tracks(self):
"""
Get all tracks in the playlist
Returns: list of Track objects
"""
songs_playlist = self._spotify.user_playlist_tracks(user=self._username,
playlist_id=self.playlist_id)
return [Track(track.get('track')) for track
in songs_playlist.get('items')]
[docs] def delete_all_tracks(self):
"""
Deletes all tracks that are in the playlist
Returns: Snapshot ID
"""
track_ids = [track.track_id for track in self.tracks]
return self._spotify.user_playlist_remove_all_occurrences_of_tracks(self._username,
self.playlist_id,
track_ids)
[docs] def add_track(self, track_id):
"""
Add a track to the playlist
Args:
track_id: string
Returns: Boolean
"""
self._logger.info("Adding song %s", track_id)
self._spotify.user_playlist_add_tracks(user=self._username,
playlist_id=self.uri,
tracks=[track_id])
return True
@property
def href(self):
"""
Link of the Playlist
Returns: string
"""
return self._playlist_details.get('href', None)
@property
def collaborative(self):
"""
Whether it is collaborative or not
Returns: boolean
"""
return self._playlist_details.get('collaborative', None)
@property
def playlist_id(self):
"""
Playlist ID
Returns: string
"""
return self._playlist_details.get('id', None)
@property
def name(self):
"""
Name of the Playlist
Returns:
"""
return self._playlist_details.get('name', None)
@property
def public(self):
"""
Whether it is a public playlist or not
Returns: boolean
"""
return self._playlist_details.get('public', None)
@property
def uri(self):
"""
URI of the playlist
Returns: string
"""
return self._playlist_details.get('uri', None)