added playlist engine and recent playlist

This commit is contained in:
aj 2019-06-10 21:46:43 +01:00
parent 9750ff8b80
commit 89f8c8961b
15 changed files with 234 additions and 29 deletions

View File

@ -3,6 +3,14 @@ import spotframework.net.network as network
import spotframework.net.user as user import spotframework.net.user as user
import spotframework.log.log as log import spotframework.log.log as log
import spotframework.io.json as json import spotframework.io.json as json
import spotframework.util.monthstrings as monthstrings
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.engine.filter.deduplicatebyname import DeduplicateByName
import datetime
import requests import requests
@ -16,47 +24,58 @@ if __name__ == '__main__':
data = json.loadJson(os.path.join(const.config_path, 'playlists.json')) data = json.loadJson(os.path.join(const.config_path, 'playlists.json'))
net = network.network(user.User()) net = network.network(user.User())
playlists = net.getUserPlaylists()
engine = PlaylistEngine(net)
engine.load_user_playlists()
for tomake in data['playlists']: for tomake in data['playlists']:
log.log("generatePlaylist", tomake['name']) log.log("makePlaylist", tomake['name'])
tracks = [] processors = [DeduplicateByID()]
for part in tomake['playlists']:
play = next((i for i in playlists if i.name == part), None)
if play is not None:
if len(play.tracks) == 0:
log.log("pulling tracks for {}".format(play.name))
play.tracks = net.getPlaylistTracks(play.playlistid)
tracks += [i for i in play.tracks if i['track']['uri'] not in [j['track']['uri'] for j in tracks] and i['is_local'] is False]
else:
log.log("requested playlist {} not found".format(part))
if 'SLACKHOOK' in os.environ:
requests.post(os.environ['SLACKHOOK'], json={"text": "spot playlists: {} not found".format(part)})
if 'shuffle' in tomake: if 'shuffle' in tomake:
if tomake['shuffle'] is True: if tomake['shuffle'] is True:
import random processors.append(Shuffle())
random.shuffle(tracks)
else: else:
tracks.sort(key=lambda x: x['track']['album']['release_date'], reverse=True) processors.append(SortReverseReleaseDate())
else: else:
tracks.sort(key=lambda x: x['track']['album']['release_date'], reverse=True) processors.append(SortReverseReleaseDate())
tracks = engine.make_playlist(tomake['playlists'], processors)
engine.execute_playlist(tracks, tomake['id'])
engine.change_description(tomake['playlists'], tomake['id'])
if 'recents' in data:
recents_id = data['recents']['id']
boundary_date = datetime.datetime.now() - datetime.timedelta(days=data['recents']['boundary'])
recent_parts = []
for playlist in [i for i in data['playlists'] if 'include_in_recents' in i]:
if playlist['include_in_recents']:
recent_parts += [i for i in playlist['playlists']]
if 'playlists' in data['recents']:
recent_parts += data['recents']['playlists']
processors = [DeduplicateByName(), SortReverseReleaseDate()]
recent_tracks = engine.get_recent_playlist(boundary_date, recent_parts, processors)
engine.execute_playlist(recent_tracks, data['recents']['id'])
engine.change_description([monthstrings.get_this_month(),
monthstrings.get_last_month()]
, data['recents']['id'])
net.replacePlaylistTracks(tomake['id'], [i['track']['uri'] for i in tracks])
net.changePlaylistDetails(tomake['id'], description=' / '.join(tomake['playlists']))
else: else:
log.log("config json not found") log.log("config json not found")
if 'SLACKHOOK' in os.environ: if 'SLACKHOOK' in os.environ:
requests.post(os.environ['SLACKHOOK'], json={"text": "spot playlists: config json not found"}) requests.post(os.environ['SLACKHOOK'], json={"text": "spot playlists: config json not found"})
log.dumpLog() log.dumpLog()
except: except Exception:
log.log("exception occured")
if 'SLACKHOOK' in os.environ:
requests.post(os.environ['SLACKHOOK'], json={"text": "spot playlists: exception occured"})
log.dumpLog() log.dumpLog()

View File

View File

View File

@ -0,0 +1,11 @@
from abc import ABC, abstractmethod
class AbstractProcessor(ABC):
def __init__(self, names=[]):
self.playlist_names = names
@abstractmethod
def process(self, tracks):
pass

View File

@ -0,0 +1,17 @@
from .abstractprocessor import AbstractProcessor
import datetime
class AddedBefore(AbstractProcessor):
def __init__(self, boundary, names=[]):
self.playlist_names = names
self.boundary = boundary
def check_date(self, track):
added_at = datetime.datetime.fromisoformat(track['added_at'].replace('T', ' ').replace('Z', ''))
return added_at < self.boundary
def process(self, tracks):
return [i for i in tracks if self.check_date(i)]

View File

@ -0,0 +1,17 @@
from .abstractprocessor import AbstractProcessor
import datetime
class AddedSince(AbstractProcessor):
def __init__(self, boundary, names=[]):
self.playlist_names = names
self.boundary = boundary
def check_date(self, track):
added_at = datetime.datetime.fromisoformat(track['added_at'].replace('T', ' ').replace('Z', ''))
return added_at > self.boundary
def process(self, tracks):
return [i for i in tracks if self.check_date(i)]

View File

@ -0,0 +1,13 @@
from .abstractprocessor import AbstractProcessor
class DeduplicateByID(AbstractProcessor):
def process(self, tracks):
return_tracks = []
for track in tracks:
if track['track']['uri'] not in [i['track']['uri'] for i in return_tracks]:
return_tracks.append(track)
return return_tracks

View File

@ -0,0 +1,19 @@
from .abstractprocessor import AbstractProcessor
class DeduplicateByName(AbstractProcessor):
def process(self, tracks):
return_tracks = []
for to_check in tracks:
for cache_track in return_tracks:
if to_check['track']['name'].lower() == cache_track['track']['name'].lower():
if to_check['track']['artists'][0]['name'].lower() \
== cache_track['track']['artists'][0]['name'].lower():
break
else:
return_tracks.append(to_check)
return return_tracks

View File

@ -0,0 +1,9 @@
from .abstractprocessor import AbstractProcessor
import random
class Shuffle(AbstractProcessor):
def process(self, tracks):
random.shuffle(tracks)
return tracks

View File

@ -0,0 +1,8 @@
from .abstractprocessor import AbstractProcessor
class SortReverseReleaseDate(AbstractProcessor):
def process(self, tracks):
tracks.sort(key=lambda x: x['track']['album']['release_date'], reverse=True)
return tracks

View File

@ -0,0 +1,72 @@
import spotframework.log.log as log
import requests
import os
import spotframework.util.monthstrings as monthstrings
from spotframework.engine.filter.addedsince import AddedSince
class PlaylistEngine:
def __init__(self, net):
self.playlists = []
self.net = net
def load_user_playlists(self):
self.playlists = self.net.getUserPlaylists()
def append_user_playlists(self):
self.playlists += self.net.getUserPlaylists()
def get_playlist_tracks(self, playlist):
log.log("pulling tracks for {}".format(playlist.name))
playlist.tracks = self.net.getPlaylistTracks(playlist.playlistid)
def make_playlist(self, playlist_parts, processors=[]):
tracks = []
for part in playlist_parts:
play = next((i for i in self.playlists if i.name == part), None)
if play is not None:
if play.has_tracks() is False:
self.get_playlist_tracks(play)
playlist_tracks = list(play.tracks)
for processor in [i for i in processors if play.name in [j for j in i.playlist_names]]:
playlist_tracks = processor.process(playlist_tracks)
tracks += [i for i in playlist_tracks if i['is_local'] is False]
else:
log.log("requested playlist {} not found".format(part))
if play is not None:
if 'SLACKHOOK' in os.environ:
requests.post(os.environ['SLACKHOOK'], json={"text": "spot playlists: {} not found".format(part)})
for processor in [i for i in processors if len(i.playlist_names) <= 0]:
tracks = processor.process(tracks)
# print(tracks)
return tracks
def get_recent_playlist(self, boundary_date, recent_playlist_parts, processors=[]):
this_month = monthstrings.get_this_month()
last_month = monthstrings.get_last_month()
datefilter = AddedSince(boundary_date, recent_playlist_parts)
processors.append(datefilter)
return self.make_playlist(recent_playlist_parts + [this_month, last_month], processors)
def execute_playlist(self, tracks, playlist_id):
self.net.replacePlaylistTracks(playlist_id, [i['track']['uri'] for i in tracks])
def change_description(self, playlistparts, playlist_id):
self.net.changePlaylistDetails(playlist_id, description=' / '.join(playlistparts))

View File

@ -1,6 +1,6 @@
class playlist: class Playlist:
def __init__(self, playlistid, uri=None, name=None, userid=None): def __init__(self, playlistid, uri=None, name=None, userid=None):
self.tracks = [] self.tracks = []
@ -8,3 +8,9 @@ class playlist:
self.playlistid = playlistid self.playlistid = playlistid
self.userid = userid self.userid = userid
self.uri = uri self.uri = uri
def has_tracks(self):
if len(self.tracks) > 0:
return True
else:
return False

View File

@ -1,6 +1,6 @@
import requests import requests
from . import const from . import const
from spotframework.model.playlist import playlist as playlistclass from spotframework.model.playlist import Playlist as playlistclass
import spotframework.log.log as log import spotframework.log.log as log
limit = 50 limit = 50

View File

View File

@ -0,0 +1,14 @@
import datetime
def get_this_month():
return datetime.date.today().strftime('%B %y').lower()
def get_last_month():
month = datetime.date.today().replace(day=1) - datetime.timedelta(days=1)
return month.strftime('%B %y').lower()
def get_this_year():
return datetime.date.today().strftime('%y')