diff --git a/generateplaylists.py b/generateplaylists.py index 19772c7..760ee5a 100644 --- a/generateplaylists.py +++ b/generateplaylists.py @@ -4,9 +4,9 @@ from spotframework.net.user import NetworkUser 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.sort import SortReleaseDate -from spotframework.engine.filter.deduplicate import DeduplicateByID, DeduplicateByName +from spotframework.engine.processor.shuffle import Shuffle +from spotframework.engine.processor.sort import SortReleaseDate +from spotframework.engine.processor.deduplicate import DeduplicateByID, DeduplicateByName import os import datetime diff --git a/spotframework/engine/filter/abstract.py b/spotframework/engine/filter/abstract.py deleted file mode 100644 index b14c752..0000000 --- a/spotframework/engine/filter/abstract.py +++ /dev/null @@ -1,47 +0,0 @@ -from abc import ABC, abstractmethod -from typing import List -from spotframework.model.track import Track - - -class AbstractProcessor(ABC): - - def __init__(self, names: List[str] = None): - self.playlist_names = names - - def has_targets(self): - if self.playlist_names: - return True - else: - return False - - @abstractmethod - def process(self, tracks: List[Track]): - pass - - -class AbstractTestFilter(AbstractProcessor, ABC): - - def __init__(self, - names: List[str] = None, - keep_failed: bool = True): - super().__init__(names) - self.keep_failed = keep_failed - - @abstractmethod - def logic_test(self, track: Track): - pass - - def process(self, tracks: List[Track]): - - return_tracks = [] - malformed_tracks = [] - - for track in tracks: - if self.logic_test(track): - return_tracks.append(track) - else: - malformed_tracks.append(track) - if self.keep_failed: - return_tracks += malformed_tracks - - return return_tracks diff --git a/spotframework/engine/filter/added.py b/spotframework/engine/filter/added.py deleted file mode 100644 index 582103f..0000000 --- a/spotframework/engine/filter/added.py +++ /dev/null @@ -1,47 +0,0 @@ -from abc import ABC, abstractmethod -from .abstract import AbstractProcessor -import datetime -from typing import List -from spotframework.model.track import Track, PlaylistTrack - - -class Added(AbstractProcessor, ABC): - - def __init__(self, - boundary: datetime.datetime, - names: List[str] = None, - keep_malformed_type: bool = True): - super().__init__(names) - self.boundary = boundary - self.keep_malformed_type = keep_malformed_type - - @abstractmethod - def check_date(self, track: PlaylistTrack): - pass - - def process(self, tracks: List[Track]): - - return_tracks = [] - malformed_tracks = [] - - for track in tracks: - if isinstance(track, PlaylistTrack): - if self.check_date(track): - return_tracks.append(track) - else: - malformed_tracks.append(track) - - if self.keep_malformed_type: - return_tracks += malformed_tracks - - return return_tracks - - -class AddedBefore(Added): - def check_date(self, track: PlaylistTrack): - return track.added_at < self.boundary - - -class AddedSince(Added): - def check_date(self, track: PlaylistTrack): - return track.added_at > self.boundary diff --git a/spotframework/engine/filter/deduplicate.py b/spotframework/engine/filter/deduplicate.py deleted file mode 100644 index c98c5e1..0000000 --- a/spotframework/engine/filter/deduplicate.py +++ /dev/null @@ -1,45 +0,0 @@ -from spotframework.engine.filter.abstract import AbstractProcessor -from typing import List -from spotframework.model.track import Track, SpotifyTrack - - -class DeduplicateByID(AbstractProcessor): - - def __init__(self, - names: List[str] = None, - keep_malformed_type: bool = True): - super().__init__(names) - self.keep_malformed_type = keep_malformed_type - - def process(self, tracks: List[Track]): - return_tracks = [] - malformed_tracks = [] - - for track in tracks: - if isinstance(track, SpotifyTrack): - if track.uri not in [i.uri for i in return_tracks]: - return_tracks.append(track) - else: - malformed_tracks.append(track) - - if self.keep_malformed_type: - return_tracks += malformed_tracks - - return return_tracks - - -class DeduplicateByName(AbstractProcessor): - - def process(self, tracks: List[Track]): - return_tracks = [] - - for to_check in tracks: - - for cache_track in return_tracks: - if to_check.name.lower() == cache_track.name.lower(): - if to_check.artists[0].name.lower() == cache_track.artists[0].name.lower(): - break - else: - return_tracks.append(to_check) - - return return_tracks diff --git a/spotframework/engine/filter/popularity.py b/spotframework/engine/filter/popularity.py deleted file mode 100644 index 9746ff4..0000000 --- a/spotframework/engine/filter/popularity.py +++ /dev/null @@ -1,38 +0,0 @@ -from spotframework.engine.filter.abstract import AbstractProcessor -from typing import List -from spotframework.model.track import Track, SpotifyTrack - - -class SortPopularity(AbstractProcessor): - - def __init__(self, - names: List[str] = None, - keep_malformed_type: bool = True): - super().__init__(names) - self.keep_malformed_type = keep_malformed_type - - def sort(self, tracks: List[SpotifyTrack]): - tracks.sort(key=lambda x: x.popularity, reverse=True) - - def process(self, tracks: List[Track]): - return_tracks = [] - malformed_tracks = [] - - for track in tracks: - if isinstance(track, SpotifyTrack): - return_tracks.append(track) - else: - malformed_tracks.append(track) - - self.sort(return_tracks) - - if self.keep_malformed_type: - return_tracks += malformed_tracks - - return return_tracks - - -class SortReversePopularity(SortPopularity): - - def sort(self, tracks: List[SpotifyTrack]): - tracks.sort(key=lambda x: x.popularity, reverse=False) diff --git a/spotframework/engine/playlistengine.py b/spotframework/engine/playlistengine.py index 3a12b5c..f16c2bf 100644 --- a/spotframework/engine/playlistengine.py +++ b/spotframework/engine/playlistengine.py @@ -3,13 +3,13 @@ import os import logging import spotframework.util.monthstrings as monthstrings -from spotframework.engine.filter.added import AddedSince +from spotframework.engine.processor.added import AddedSince from typing import List from spotframework.model.track import SpotifyTrack from spotframework.model.playlist import SpotifyPlaylist from spotframework.net.network import Network -from spotframework.engine.filter.abstract import AbstractProcessor +from spotframework.engine.processor.abstract import AbstractProcessor from datetime import datetime logger = logging.getLogger(__name__) diff --git a/spotframework/engine/filter/__init__.py b/spotframework/engine/processor/__init__.py similarity index 100% rename from spotframework/engine/filter/__init__.py rename to spotframework/engine/processor/__init__.py diff --git a/spotframework/engine/processor/abstract.py b/spotframework/engine/processor/abstract.py new file mode 100644 index 0000000..98974e3 --- /dev/null +++ b/spotframework/engine/processor/abstract.py @@ -0,0 +1,71 @@ +from abc import ABC, abstractmethod +from typing import List +from spotframework.model.track import Track + + +class AbstractProcessor(ABC): + + def __init__(self, names: List[str] = None): + self.playlist_names = names + + def has_targets(self): + if self.playlist_names: + return True + else: + return False + + @abstractmethod + def process(self, tracks: List[Track]): + pass + + +class BatchSingleProcessor(AbstractProcessor, ABC): + + @staticmethod + def process_single(track: Track): + return track + + def process_batch(self, tracks: List[Track]): + processed = [] + + for track in tracks: + processed_track = self.process_single(track) + processed.append(processed_track) + + return processed + + def process(self, tracks: List[Track]): + return [i for i in self.process_batch(tracks) if i] + + +class BatchSingleTypeAwareProcessor(BatchSingleProcessor, ABC): + + def __init__(self, + names: List[str] = None, + instance_check=None, + append_malformed: bool = True): + super().__init__(names) + self.instance_check = instance_check + self.append_malformed = append_malformed + + def process(self, tracks: List[Track]): + + if self.instance_check: + return_tracks = [] + malformed_tracks = [] + + for track in tracks: + + if isinstance(track, self.instance_check): + return_tracks.append(track) + else: + malformed_tracks.append(track) + + return_tracks = super().process(return_tracks) + + if self.append_malformed: + return_tracks += malformed_tracks + + return return_tracks + else: + return tracks diff --git a/spotframework/engine/processor/added.py b/spotframework/engine/processor/added.py new file mode 100644 index 0000000..75c46bc --- /dev/null +++ b/spotframework/engine/processor/added.py @@ -0,0 +1,28 @@ +from .abstract import BatchSingleTypeAwareProcessor +import datetime +from typing import List +from spotframework.model.track import PlaylistTrack + + +class Added(BatchSingleTypeAwareProcessor): + + def __init__(self, + boundary: datetime.datetime, + names: List[str] = None, + append_malformed: bool = True): + super().__init__(names, + instance_check=PlaylistTrack, + append_malformed=append_malformed) + self.boundary = boundary + + +class AddedBefore(Added): + def process_single(self, track: PlaylistTrack): + if track.added_at < self.boundary: + return track + + +class AddedSince(Added): + def process_single(self, track: PlaylistTrack): + if track.added_at > self.boundary: + return track diff --git a/spotframework/engine/processor/deduplicate.py b/spotframework/engine/processor/deduplicate.py new file mode 100644 index 0000000..90beeee --- /dev/null +++ b/spotframework/engine/processor/deduplicate.py @@ -0,0 +1,39 @@ +from spotframework.engine.processor.abstract import BatchSingleProcessor, BatchSingleTypeAwareProcessor +from typing import List +from spotframework.model.track import Track, SpotifyTrack + + +class DeduplicateByID(BatchSingleTypeAwareProcessor): + + def __init__(self, + names: List[str] = None, + append_malformed: bool = True): + super().__init__(names, + instance_check=SpotifyTrack, + append_malformed=append_malformed) + + def process_batch(self, tracks: List[SpotifyTrack]): + return_tracks = [] + + for track in tracks: + if track.uri not in [i.uri for i in return_tracks]: + return_tracks.append(track) + + return return_tracks + + +class DeduplicateByName(BatchSingleProcessor): + + def process_batch(self, tracks: List[Track]): + return_tracks = [] + + for to_check in tracks: + + for cache_track in return_tracks: + if to_check.name.lower() == cache_track.name.lower(): + if to_check.artists[0].name.lower() == cache_track.artists[0].name.lower(): + break + else: + return_tracks.append(to_check) + + return return_tracks diff --git a/spotframework/engine/processor/popularity.py b/spotframework/engine/processor/popularity.py new file mode 100644 index 0000000..43aaf6f --- /dev/null +++ b/spotframework/engine/processor/popularity.py @@ -0,0 +1,19 @@ +from spotframework.engine.processor.abstract import BatchSingleTypeAwareProcessor +from typing import List +from spotframework.model.track import SpotifyTrack + + +class SortPopularity(BatchSingleTypeAwareProcessor): + + def __init__(self, + names: List[str] = None, + append_malformed: bool = True, + reverse: bool = False): + super().__init__(names, + instance_check=SpotifyTrack, + append_malformed=append_malformed) + self.reverse = reverse + + def process_batch(self, tracks: List[SpotifyTrack]): + tracks.sort(key=lambda x: x.popularity, reverse=self.reverse) + return tracks diff --git a/spotframework/engine/filter/shuffle.py b/spotframework/engine/processor/shuffle.py similarity index 100% rename from spotframework/engine/filter/shuffle.py rename to spotframework/engine/processor/shuffle.py diff --git a/spotframework/engine/filter/sort.py b/spotframework/engine/processor/sort.py similarity index 100% rename from spotframework/engine/filter/sort.py rename to spotframework/engine/processor/sort.py