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 import os
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
logger.setLevel('INFO') logger.setLevel('DEBUG')
log_format = '%(levelname)s %(name)s:%(funcName)s - %(message)s' if os.environ.get('DEPLOY_DESTINATION', None) == 'PROD':
formatter = logging.Formatter(log_format)
if os.environ.get('CLOUD', None):
from google.cloud import logging as glogging from google.cloud import logging as glogging
from google.cloud.logging.handlers import CloudLoggingHandler 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() client = glogging.Client()
handler = CloudLoggingHandler(client) handler = CloudLoggingHandler(client, name='spotframework')
handler.setFormatter(formatter) handler.setFormatter(formatter)
logger.addHandler(handler) logger.addHandler(handler)
else: else:
log_format = '%(levelname)s %(name)s:%(funcName)s - %(message)s'
formatter = logging.Formatter(log_format)
stream_handler = logging.StreamHandler() stream_handler = logging.StreamHandler()
stream_handler.setFormatter(formatter) stream_handler.setFormatter(formatter)

View File

@ -15,14 +15,31 @@ class PlaylistEngine:
self.net = net self.net = net
def load_user_playlists(self): 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): 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): def get_playlist_tracks(self, playlist):
logger.info(f"pulling tracks for {playlist.name}") 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): 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] tracks = [i['track'] for i in tracks]
if include_recommendations: if include_recommendations:
try: recommendations = self.net.get_recommendations(tracks=[i['id'] for i in tracks],
tracks += self.net.get_recommendations(tracks=[i['id'] for i in tracks], response_limit=recommendation_limit)
response_limit=recommendation_limit)['tracks'] if recommendations and len(recommendations) > 0:
except Exception as e: tracks += recommendations['tracks']
logger.exception('exception occured') else:
logger.error('error getting recommendations')
# print(tracks)
return 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() this_month = monthstrings.get_this_month()
last_month = monthstrings.get_last_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) processors.append(datefilter)
return self.make_playlist(recent_playlist_parts + [this_month, last_month], return self.make_playlist(recent_playlist_parts + month_playlists,
processors, processors,
include_recommendations=include_recommendations, include_recommendations=include_recommendations,
recommendation_limit=recommendation_limit) recommendation_limit=recommendation_limit)
def execute_playlist(self, tracks, playlist_id): 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): resp = self.net.replace_playlist_tracks(playlist_id, [i['uri'] for i in tracks])
self.net.change_playlist_details(playlist_id, description=' / '.join(playlistparts)) 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) tracks = self.get_playlist_tracks(playlistid)
playlist = Playlist(playlistid) if tracks is not None:
playlist.tracks += tracks
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): 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: if 200 <= req.status_code < 300:
return req.json() return req.json()
else:
logger.error('error creating playlist')
return None
def get_playlists(self, offset=0): def get_playlists(self, offset=0):
@ -105,18 +113,27 @@ class Network:
# playlists = playlists + resp['items'] # playlists = playlists + resp['items']
if resp['next']: if resp['next']:
playlists += self.get_playlists(offset + limit) more_playlists = self.get_playlists(offset + limit)
if more_playlists:
playlists += more_playlists
return playlists return playlists
else: else:
logger.error(f'error getting playlists offset={offset}')
return None return None
def get_user_playlists(self): def get_user_playlists(self):
logger.info('retrieved') 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): 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) resp = self._make_get_request('getPlaylistTracks', f'playlists/{playlistid}/tracks', params=params)
if resp and resp.get('items'): if resp:
tracks += resp['items'] if resp.get('items', None):
tracks += resp['items']
else:
logger.warning(f'{playlistid} no items returned')
else: else:
logger.warning(f'{playlistid} no response or items') logger.warning(f'{playlistid} error on response')
if resp.get('next', None): 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 return tracks
def get_available_devices(self): 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): def get_player(self):
logger.info("retrieved") 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): def get_device_id(self, devicename):
logger.info(f"{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): def play(self, uri=None, uris=None, deviceid=None):
@ -178,6 +216,8 @@ class Network:
raise Exception('need either context uri or uris') raise Exception('need either context uri or uris')
req = self._make_put_request('play', 'me/player/play', params=params, json=payload) 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): def pause(self, deviceid=None):
@ -189,6 +229,8 @@ class Network:
params = None params = None
req = self._make_put_request('pause', 'me/player/pause', params=params) req = self._make_put_request('pause', 'me/player/pause', params=params)
if req is None:
logger.error('error pausing')
def next(self, deviceid=None): def next(self, deviceid=None):
@ -200,6 +242,8 @@ class Network:
params = None params = None
req = self._make_post_request('next', 'me/player/next', params=params) 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): def set_shuffle(self, state, deviceid=None):
@ -211,6 +255,8 @@ class Network:
params['device_id'] = deviceid params['device_id'] = deviceid
req = self._make_put_request('setShuffle', 'me/player/shuffle', params=params) 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): def set_volume(self, volume, deviceid=None):
@ -224,9 +270,15 @@ class Network:
params['device_id'] = deviceid params['device_id'] = deviceid
req = self._make_put_request('setVolume', 'me/player/volume', params=params) 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: else:
logger.error(f"{volume} not accepted value") logger.error(f"{volume} not accepted value")
return None
def replace_playlist_tracks(self, playlistid, uris): 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) req = self._make_put_request('replacePlaylistTracks', f'playlists/{playlistid}/tracks', json=json, headers=headers)
if req is not None: if req is not None:
resp = req.json()
if len(uris) > 100: 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): 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: if description is not None:
json['description'] = description json['description'] = description
req = self._make_put_request('changePlaylistDetails', f'playlists/{playlistid}', json=json, headers=headers) if len(json) == 0:
return req 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): def add_playlist_tracks(self, playlistid, uris):
@ -280,9 +343,17 @@ class Network:
if req is not None: if req is not None:
resp = req.json() resp = req.json()
snapshots = [resp]
if len(uris) > 100: 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): def get_recommendations(self, tracks=None, artists=None, response_limit=10):
@ -297,4 +368,13 @@ class Network:
random.shuffle(artists) random.shuffle(artists)
params['seed_artists'] = artists[:100] 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