diff --git a/spotframework/filter/__init__.py b/spotframework/filter/__init__.py new file mode 100644 index 0000000..028f7e1 --- /dev/null +++ b/spotframework/filter/__init__.py @@ -0,0 +1,16 @@ +from typing import List + + +def remove_local(tracks: List, include_malformed=True) -> List: + prop = 'is_local' + + return_tracks = [] + for track in tracks: + if hasattr(track, prop) and isinstance(getattr(track, prop), bool): + if getattr(track, prop) is False: + return_tracks.append(track) + else: + if include_malformed: + return_tracks.append(track) + + return return_tracks diff --git a/spotframework/filter/added.py b/spotframework/filter/added.py new file mode 100644 index 0000000..ecf6954 --- /dev/null +++ b/spotframework/filter/added.py @@ -0,0 +1,35 @@ +import logging +from typing import List +from datetime import datetime + +logger = logging.getLogger(__name__) + + +def added_before(tracks: List, boundary: datetime, include_malformed=True) -> List: + prop = 'added_at' + + return_tracks = [] + for track in tracks: + if hasattr(track, prop) and isinstance(getattr(track, prop), datetime): + if getattr(track, prop) < boundary: + return_tracks.append(track) + else: + if include_malformed: + return_tracks.append(track) + + return return_tracks + + +def added_after(tracks: List, boundary: datetime, include_malformed=True) -> List: + prop = 'added_at' + + return_tracks = [] + for track in tracks: + if hasattr(track, prop) and isinstance(getattr(track, prop), datetime): + if getattr(track, prop) > boundary: + return_tracks.append(track) + else: + if include_malformed: + return_tracks.append(track) + + return return_tracks diff --git a/spotframework/filter/deduplicate.py b/spotframework/filter/deduplicate.py new file mode 100644 index 0000000..4308e77 --- /dev/null +++ b/spotframework/filter/deduplicate.py @@ -0,0 +1,60 @@ +import logging +from typing import List + +from spotframework.model.track import SpotifyTrack +from spotframework.model.album import SpotifyAlbum +from spotframework.model.uri import Uri + +logger = logging.getLogger(__name__) + + +def deduplicate_by_id(tracks: List, include_malformed=True) -> List: + prop = 'uri' + + return_tracks = [] + for track in tracks: + if hasattr(track, prop) and isinstance(getattr(track, prop), Uri): + if getattr(track, prop) not in [getattr(i, prop) for i in return_tracks]: + return_tracks.append(track) + else: + if include_malformed: + return_tracks.append(track) + + return return_tracks + + +def deduplicate_by_name(tracks: List, include_malformed=True) -> List: + return_tracks = [] + + for track in tracks: + if isinstance(track, SpotifyTrack): + to_check_artists = [i.name.lower() for i in track.artists] + + for index, _track in enumerate(return_tracks): + if track.name.lower() == _track.name.lower(): + + _track_artists = [i.name.lower() for i in _track.artists] + if all((i in _track_artists for i in to_check_artists)): # CHECK ARTISTS MATCH + + if not isinstance(track.album, SpotifyAlbum): + logger.warning(f'{track.name} album not of type SpotifyAlbum') + continue + + if not isinstance(_track.album, SpotifyAlbum): + logger.warning(f'{_track.name} album not of type SpotifyAlbum') + continue + + # CHECK ALBUM TYPE, PREFER ALBUMS OVER SINGLES ETC + if track.album.album_type.value > _track.album.album_type.value: + logger.debug(f'better track source found, {track} ({track.album.album_type}) ' + f'> {_track} ({_track.album.album_type})') + return_tracks[index] = track # REPLACE + break # FOUND, ESCAPE + else: + return_tracks.append(track) # NOT FOUND, ADD TO RETURN + + else: + if include_malformed: + return_tracks.append(track) + + return return_tracks diff --git a/spotframework/filter/sort.py b/spotframework/filter/sort.py new file mode 100644 index 0000000..cf52ffd --- /dev/null +++ b/spotframework/filter/sort.py @@ -0,0 +1,47 @@ +import logging +from typing import List + +from spotframework.model.track import Track + +logger = logging.getLogger(__name__) + + +def sort_by_popularity(tracks: List, reverse: bool = False, include_malformed=False) -> List: + prop = 'popularity' + + return_tracks = sorted([i for i in tracks if hasattr(i, prop) and isinstance(getattr(i, prop), int)], + key=lambda x: x.popularity, reverse=reverse) + + if include_malformed: + return_tracks += [i for i in tracks + if not hasattr(i, prop) + or (hasattr(i, prop) and not isinstance(getattr(i, prop), int))] + + return return_tracks + + +def sort_by_release_date(tracks: List, reverse: bool = False) -> List: + return sorted(sort_artist_album_track_number(tracks), + key=lambda x: x.album.release_date, reverse=reverse) + + +def sort_by_artist_name(tracks: List, reverse: bool = False) -> List: + return_tracks = sorted([i for i in tracks if isinstance(i, Track)], + key=lambda x: (x.album.name.lower(), + x.track_number)) + return_tracks.sort(key=lambda x: x.artists[0].name.lower(), reverse=reverse) + return return_tracks + + +def sort_by_added_date(tracks: List, reverse: bool = False) -> List: + return sorted(sort_artist_album_track_number(tracks), + key=lambda x: x.added_at, + reverse=reverse) + + +def sort_artist_album_track_number(tracks: List) -> List: + return sorted([i for i in tracks if isinstance(i, Track)], + key=lambda x: (x.artists[0].name.lower(), + x.album.name.lower(), + x.track_number)) + diff --git a/spotframework/net/network.py b/spotframework/net/network.py index 4e797e8..e331357 100644 --- a/spotframework/net/network.py +++ b/spotframework/net/network.py @@ -731,8 +731,8 @@ class Network: return [] def get_recommendations(self, - tracks: List[Track] = None, - artists: List[SpotifyArtist] = None, + tracks: List[str] = None, + artists: List[str] = None, response_limit=10) -> Optional[List[Track]]: logger.info(f'getting {response_limit} recommendations, ' @@ -743,10 +743,10 @@ class Network: if tracks: random.shuffle(tracks) - params['seed_tracks'] = tracks[:100] + params['seed_tracks'] = tracks[:5] if artists: random.shuffle(artists) - params['seed_artists'] = artists[:100] + params['seed_artists'] = artists[:5] if len(params) == 1: logger.warning('update dictionairy length 0')