improved logging
This commit is contained in:
parent
683985d9ce
commit
9af0b4f03d
@ -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
12
main.py
@ -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)
|
@ -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)
|
||||
|
@ -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')
|
||||
|
@ -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
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user