improved logging

This commit is contained in:
aj 2019-08-17 18:32:13 +01:00
parent 683985d9ce
commit 9af0b4f03d
7 changed files with 171 additions and 168 deletions

View File

@ -1,3 +0,0 @@
from spotframework.google.run_user_playlist import run_user_playlist as run_user_playlist
run_user_playlist('andy', 'DNB')

12
main.py
View File

@ -1,12 +0,0 @@
def run_user_playlist(event, context):
import base64
name = base64.b64decode(event['data']).decode('utf-8')
username = event['attributes']['username']
from spotframework.google.run_user_playlist import run_user_playlist as run
run(username, name)

View File

@ -2,24 +2,24 @@ import logging
import os
logger = logging.getLogger(__name__)
logger.setLevel('INFO')
logger.setLevel('DEBUG')
log_format = '%(levelname)s %(name)s:%(funcName)s - %(message)s'
formatter = logging.Formatter(log_format)
if os.environ.get('CLOUD', None):
if os.environ.get('DEPLOY_DESTINATION', None) == 'PROD':
from google.cloud import logging as glogging
from google.cloud.logging.handlers import CloudLoggingHandler
client = glogging.Client()
log_format = '%(funcName)s - %(message)s'
formatter = logging.Formatter(log_format)
# handler = client.get_default_handler()
handler = CloudLoggingHandler(client)
client = glogging.Client()
handler = CloudLoggingHandler(client, name='spotframework')
handler.setFormatter(formatter)
logger.addHandler(handler)
else:
log_format = '%(levelname)s %(name)s:%(funcName)s - %(message)s'
formatter = logging.Formatter(log_format)
stream_handler = logging.StreamHandler()
stream_handler.setFormatter(formatter)

View File

@ -15,14 +15,31 @@ class PlaylistEngine:
self.net = net
def load_user_playlists(self):
self.playlists = self.net.get_playlists()
logger.info('loading')
playlists = self.net.get_playlists()
if playlists and len(playlists) > 0:
self.playlists = playlists
else:
logger.error('error getting playlists')
def append_user_playlists(self):
self.playlists += self.net.get_playlists()
logger.info('loading')
playlists = self.net.get_playlists()
if playlists and len(playlists) > 0:
self.playlists += playlists
else:
logger.error('error getting playlists')
def get_playlist_tracks(self, playlist):
logger.info(f"pulling tracks for {playlist.name}")
playlist.tracks = self.net.get_playlist_tracks(playlist.playlistid)
tracks = self.net.get_playlist_tracks(playlist.playlistid)
if tracks and len(tracks) > 0:
playlist.tracks = tracks
else:
logger.error('error getting tracks')
def make_playlist(self, playlist_parts, processors=[], include_recommendations=False, recommendation_limit=10):
@ -55,30 +72,62 @@ class PlaylistEngine:
tracks = [i['track'] for i in tracks]
if include_recommendations:
try:
tracks += self.net.get_recommendations(tracks=[i['id'] for i in tracks],
response_limit=recommendation_limit)['tracks']
except Exception as e:
logger.exception('exception occured')
recommendations = self.net.get_recommendations(tracks=[i['id'] for i in tracks],
response_limit=recommendation_limit)
if recommendations and len(recommendations) > 0:
tracks += recommendations['tracks']
else:
logger.error('error getting recommendations')
# print(tracks)
return tracks
def get_recent_playlist(self, boundary_date, recent_playlist_parts, processors=[], include_recommendations=False, recommendation_limit=10):
def get_recent_playlist(self,
boundary_date,
recent_playlist_parts,
processors=[],
include_recommendations=False,
recommendation_limit=10,
add_this_month=False,
add_last_month=False):
this_month = monthstrings.get_this_month()
last_month = monthstrings.get_last_month()
datefilter = AddedSince(boundary_date, recent_playlist_parts + [last_month])
month_playlists = []
if add_this_month:
month_playlists.append(this_month)
if add_last_month:
month_playlists.append(last_month)
datefilter = AddedSince(boundary_date, recent_playlist_parts + month_playlists)
processors.append(datefilter)
return self.make_playlist(recent_playlist_parts + [this_month, last_month],
return self.make_playlist(recent_playlist_parts + month_playlists,
processors,
include_recommendations=include_recommendations,
recommendation_limit=recommendation_limit)
def execute_playlist(self, tracks, playlist_id):
self.net.replace_playlist_tracks(playlist_id, [i['uri'] for i in tracks])
def change_description(self, playlistparts, playlist_id):
self.net.change_playlist_details(playlist_id, description=' / '.join(playlistparts))
resp = self.net.replace_playlist_tracks(playlist_id, [i['uri'] for i in tracks])
if resp:
return resp
else:
logger.error('error executing')
return None
def change_description(self, playlistparts, playlist_id, suffix=None):
if suffix:
string = ' / '.join(playlistparts) + f' - {str(suffix)}'
else:
string = ' / '.join(playlistparts)
resp = self.net.change_playlist_details(playlist_id, description=string)
if resp:
return resp
else:
logger.error('error changing description')

View File

@ -1,111 +0,0 @@
from google.cloud import firestore
import datetime
import logging
from spotframework.engine.playlistengine import PlaylistEngine
from spotframework.engine.filter.shuffle import Shuffle
from spotframework.engine.filter.sortreversereleasedate import SortReverseReleaseDate
from spotframework.engine.filter.deduplicatebyid import DeduplicateByID
from spotframework.net.network import Network
from spotframework.net.user import User
db = firestore.Client()
captured_playlists = []
def run_user_playlist(username, playlist_name):
logger = logging.getLogger(__name__)
users = [i for i in db.collection(u'spotify_users').where(u'username', u'==', username).stream()]
logger.info(f'{username} / {playlist_name}')
if len(users) == 1:
user_dict = users[0].to_dict()
playlist_collection = db.collection(u'spotify_users', u'{}'.format(users[0].id), 'playlists')
playlists = [i for i in playlist_collection.where(u'name', u'==', playlist_name).stream()]
if len(playlists) == 1:
playlist_dict = playlists[0].to_dict()
if playlist_dict['playlist_id'] is None:
logger.critical(f'no playlist id to populate ({username}/{playlist_name})')
return
if len(playlist_dict['parts']) == 0 and len(playlist_dict['playlist_references']) == 0:
logger.critical(f'no playlists to use for creation ({username}/{playlist_name})')
return
spotify_keys = db.document('key/spotify').get().to_dict()
net = Network(User(spotify_keys['clientid'],
spotify_keys['clientsecret'],
user_dict['access_token'],
user_dict['refresh_token']))
engine = PlaylistEngine(net)
engine.load_user_playlists()
processors = [DeduplicateByID()]
if playlist_dict['shuffle'] is True:
processors.append(Shuffle())
else:
processors.append(SortReverseReleaseDate())
global captured_playlists
captured_playlists = []
submit_parts = playlist_dict['parts'] + generate_parts(users[0].id, playlist_dict['name'])
submit_parts = [i for i in {j for j in submit_parts}]
if playlist_dict['type'] == 'recents':
boundary_date = datetime.datetime.now() - datetime.timedelta(days=int(playlist_dict['day_boundary']))
tracks = engine.get_recent_playlist(boundary_date,
submit_parts,
processors,
include_recommendations=playlist_dict['include_recommendations'],
recommendation_limit=int(playlist_dict['recommendation_sample']))
else:
tracks = engine.make_playlist(submit_parts,
processors,
include_recommendations=playlist_dict['include_recommendations'],
recommendation_limit=int(playlist_dict['recommendation_sample']))
engine.execute_playlist(tracks, playlist_dict['playlist_id'])
engine.change_description(sorted(submit_parts), playlist_dict['playlist_id'])
else:
logger.critical(f'multiple/no playlists found ({username}/{playlist_name})')
return
else:
logger.critical(f'multiple/no user(s) found ({username}/{playlist_name})')
return
def generate_parts(user_id, name):
playlist_doc = [i.to_dict() for i in
db.document(u'spotify_users/{}'.format(user_id))
.collection(u'playlists')
.where(u'name', '==', name).stream()][0]
return_parts = playlist_doc['parts']
captured_playlists.append(name)
for i in playlist_doc['playlist_references']:
if i not in captured_playlists:
return_parts += generate_parts(user_id, i)
return return_parts

View File

@ -65,10 +65,15 @@ class Network:
tracks = self.get_playlist_tracks(playlistid)
playlist = Playlist(playlistid)
playlist.tracks += tracks
if tracks is not None:
return playlist
playlist = Playlist(playlistid)
playlist.tracks += tracks
return playlist
else:
logger.error(f"{playlistid} - no tracks returned")
return None
def create_playlist(self, username, name='New Playlist', public=True, collaborative=False, description=None):
@ -81,6 +86,9 @@ class Network:
if 200 <= req.status_code < 300:
return req.json()
else:
logger.error('error creating playlist')
return None
def get_playlists(self, offset=0):
@ -105,18 +113,27 @@ class Network:
# playlists = playlists + resp['items']
if resp['next']:
playlists += self.get_playlists(offset + limit)
more_playlists = self.get_playlists(offset + limit)
if more_playlists:
playlists += more_playlists
return playlists
else:
logger.error(f'error getting playlists offset={offset}')
return None
def get_user_playlists(self):
logger.info('retrieved')
return list(filter(lambda x: x.userid == self.user.username, self.get_playlists()))
playlists = self.get_playlists()
if playlists:
return list(filter(lambda x: x.userid == self.user.username, playlists))
else:
logger.error('no playlists returned to filter')
return None
def get_playlist_tracks(self, playlistid, offset=0):
@ -128,33 +145,54 @@ class Network:
resp = self._make_get_request('getPlaylistTracks', f'playlists/{playlistid}/tracks', params=params)
if resp and resp.get('items'):
tracks += resp['items']
if resp:
if resp.get('items', None):
tracks += resp['items']
else:
logger.warning(f'{playlistid} no items returned')
else:
logger.warning(f'{playlistid} no response or items')
logger.warning(f'{playlistid} error on response')
if resp.get('next', None):
tracks += self.get_playlist_tracks(playlistid, offset + limit)
more_tracks = self.get_playlist_tracks(playlistid, offset + limit)
if more_tracks:
tracks += more_tracks
return tracks
def get_available_devices(self):
logger.info("retrieved")
logger.info("retrieving")
return self._make_get_request('getAvailableDevices', 'me/player/devices')
resp = self._make_get_request('getAvailableDevices', 'me/player/devices')
if resp:
return resp
else:
logger.error('no devices returned')
return None
def get_player(self):
logger.info("retrieved")
return self._make_get_request('getPlayer', 'me/player')
resp = self._make_get_request('getPlayer', 'me/player')
if resp:
return resp
else:
logger.error('no player returned')
return None
def get_device_id(self, devicename):
logger.info(f"{devicename}")
return next((i for i in self.get_available_devices()['devices'] if i['name'] == devicename), None)['id']
resp = self.get_available_devices()
if resp:
return next((i for i in resp['devices'] if i['name'] == devicename), None)['id']
else:
logger.error('no devices returned')
return None
def play(self, uri=None, uris=None, deviceid=None):
@ -178,6 +216,8 @@ class Network:
raise Exception('need either context uri or uris')
req = self._make_put_request('play', 'me/player/play', params=params, json=payload)
if req is None:
logger.error('error playing')
def pause(self, deviceid=None):
@ -189,6 +229,8 @@ class Network:
params = None
req = self._make_put_request('pause', 'me/player/pause', params=params)
if req is None:
logger.error('error pausing')
def next(self, deviceid=None):
@ -200,6 +242,8 @@ class Network:
params = None
req = self._make_post_request('next', 'me/player/next', params=params)
if req is None:
logger.error('error skipping')
def set_shuffle(self, state, deviceid=None):
@ -211,6 +255,8 @@ class Network:
params['device_id'] = deviceid
req = self._make_put_request('setShuffle', 'me/player/shuffle', params=params)
if req is None:
logger.error(f'error setting shuffle {state}')
def set_volume(self, volume, deviceid=None):
@ -224,9 +270,15 @@ class Network:
params['device_id'] = deviceid
req = self._make_put_request('setVolume', 'me/player/volume', params=params)
if req:
return req
else:
logger.error(f'error setting volume {volume}')
return None
else:
logger.error(f"{volume} not accepted value")
return None
def replace_playlist_tracks(self, playlistid, uris):
@ -239,10 +291,13 @@ class Network:
req = self._make_put_request('replacePlaylistTracks', f'playlists/{playlistid}/tracks', json=json, headers=headers)
if req is not None:
resp = req.json()
if len(uris) > 100:
self.add_playlist_tracks(playlistid, uris[100:])
return self.add_playlist_tracks(playlistid, uris[100:])
return req
else:
logger.error(f'error replacing playlist tracks, total: {len(uris)}')
def change_playlist_details(self, playlistid, name=None, public=None, collaborative=None, description=None):
@ -264,8 +319,16 @@ class Network:
if description is not None:
json['description'] = description
req = self._make_put_request('changePlaylistDetails', f'playlists/{playlistid}', json=json, headers=headers)
return req
if len(json) == 0:
logger.warning('update dictionairy length 0')
return None
else:
req = self._make_put_request('changePlaylistDetails', f'playlists/{playlistid}', json=json, headers=headers)
if req:
return req
else:
logger.error('error updating details')
return None
def add_playlist_tracks(self, playlistid, uris):
@ -280,9 +343,17 @@ class Network:
if req is not None:
resp = req.json()
snapshots = [resp]
if len(uris) > 100:
self.add_playlist_tracks(playlistid, uris[100:])
snapshots += self.add_playlist_tracks(playlistid, uris[100:])
return snapshots
else:
logger.error(f'error retrieving tracks {playlistid}, total: {len(uris)}')
return []
def get_recommendations(self, tracks=None, artists=None, response_limit=10):
@ -297,4 +368,13 @@ class Network:
random.shuffle(artists)
params['seed_artists'] = artists[:100]
return self._make_get_request('getRecommendations', 'recommendations', params=params)
if len(params) == 1:
logger.warning('update dictionairy length 0')
return None
else:
resp = self._make_get_request('getRecommendations', 'recommendations', params=params)
if resp:
return resp
else:
logger.error('error getting recommendations')
return None