From 7f60f65403f6c3c8d3476b0330b90bfa54ce15db Mon Sep 17 00:00:00 2001 From: aj Date: Sun, 1 Mar 2020 13:15:32 +0000 Subject: [PATCH] added track_number and album_type to model, fixed sort and dedupe by name --- spotframework/engine/processor/deduplicate.py | 22 ++++++++++++++----- spotframework/engine/processor/sort.py | 10 ++++++++- spotframework/model/album.py | 13 +++++++++++ spotframework/model/track.py | 20 ++++++++++++----- spotframework/net/network.py | 14 ++++++++++++ 5 files changed, 68 insertions(+), 11 deletions(-) diff --git a/spotframework/engine/processor/deduplicate.py b/spotframework/engine/processor/deduplicate.py index 8911006..dc8b974 100644 --- a/spotframework/engine/processor/deduplicate.py +++ b/spotframework/engine/processor/deduplicate.py @@ -1,8 +1,11 @@ from spotframework.engine.processor.abstract import BatchSingleProcessor, BatchSingleTypeAwareProcessor from typing import List +import logging from spotframework.model.track import Track, SpotifyTrack from spotframework.model.uri import Uri +logger = logging.getLogger(__name__) + class DeduplicateByID(BatchSingleTypeAwareProcessor): @@ -31,12 +34,21 @@ class DeduplicateByName(BatchSingleProcessor): return_tracks = [] for to_check in tracks: + to_check_artists = [i.name.lower() for i in to_check.artists] - 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 + for index, _track in enumerate(return_tracks): + if to_check.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 + + # CHECK ALBUM TYPE, PREFER ALBUMS OVER SINGLES ETC + if to_check.album.album_type.value > _track.album.album_type.value: + logger.debug(f'better track source found, {to_check} ({to_check.album.album_type}) ' + f'> {_track} ({_track.album.album_type})') + return_tracks[index] = to_check # REPLACE + break # FOUND, ESCAPE else: - return_tracks.append(to_check) + return_tracks.append(to_check) # NOT FOUND, ADD TO RETURN return return_tracks diff --git a/spotframework/engine/processor/sort.py b/spotframework/engine/processor/sort.py index 01fccf9..7e088fe 100644 --- a/spotframework/engine/processor/sort.py +++ b/spotframework/engine/processor/sort.py @@ -17,6 +17,9 @@ class BasicReversibleSort(AbstractProcessor, ABC): class SortReleaseDate(BasicReversibleSort): def process(self, tracks: List[Track]) -> List[Track]: + tracks.sort(key=lambda x: (x.artists[0].name.lower(), + x.album.name.lower(), + x.track_number)) tracks.sort(key=lambda x: x.album.release_date, reverse=self.reverse) return tracks @@ -24,7 +27,9 @@ class SortReleaseDate(BasicReversibleSort): class SortArtistName(BasicReversibleSort): def process(self, tracks: List[Track]) -> List[Track]: - tracks.sort(key=lambda x: x.artists[0].name, reverse=self.reverse) + tracks.sort(key=lambda x: (x.album.name.lower(), + x.track_number)) + tracks.sort(key=lambda x: x.artists[0].name.lower(), reverse=self.reverse) return tracks @@ -42,5 +47,8 @@ class SortAddedDate(BatchSingleTypeAwareProcessor): self.reverse = reverse def process_batch(self, tracks: List[PlaylistTrack]) -> List[PlaylistTrack]: + tracks.sort(key=lambda x: (x.artists[0].name.lower(), + x.album.name.lower(), + x.track_number)) tracks.sort(key=lambda x: x.added_at, reverse=self.reverse) return tracks diff --git a/spotframework/model/album.py b/spotframework/model/album.py index 7e2db64..85667a5 100644 --- a/spotframework/model/album.py +++ b/spotframework/model/album.py @@ -1,5 +1,6 @@ from __future__ import annotations from datetime import datetime +from enum import Enum from typing import TYPE_CHECKING from typing import List, Union from spotframework.util.console import Color @@ -45,9 +46,16 @@ class Album: class SpotifyAlbum(Album): + + class Type(Enum): + single = 0 + compilation = 1 + album = 2 + def __init__(self, name: str, artists: List[Artist], + album_type: Type, href: str = None, uri: Union[str, Uri] = None, @@ -73,6 +81,8 @@ class SpotifyAlbum(Album): if self.uri.object_type != Uri.ObjectType.album: raise TypeError('provided uri not for an album') + self.album_type = album_type + self.genres = genres self.release_date = release_date @@ -101,6 +111,8 @@ class LibraryAlbum(SpotifyAlbum): name: str, artists: List[Artist], + album_type: SpotifyAlbum.Type, + href: str = None, uri: Union[str, Uri] = None, @@ -117,6 +129,7 @@ class LibraryAlbum(SpotifyAlbum): ): super().__init__(name=name, artists=artists, + album_type=album_type, href=href, uri=uri, genres=genres, diff --git a/spotframework/model/track.py b/spotframework/model/track.py index b2663a0..e6afe35 100644 --- a/spotframework/model/track.py +++ b/spotframework/model/track.py @@ -7,7 +7,7 @@ from spotframework.util.console import Color from spotframework.util import convert_ms_to_minute_string from enum import Enum if TYPE_CHECKING: - from spotframework.model.album import Album + from spotframework.model.album import Album, SpotifyAlbum from spotframework.model.artist import Artist from spotframework.model.user import User from spotframework.model.service import Context @@ -20,6 +20,7 @@ class Track: artists: List[Artist], disc_number: int = None, + track_number: int = None, duration_ms: int = None, excplicit: bool = None ): @@ -28,6 +29,7 @@ class Track: self.artists = artists self.disc_number = disc_number + self.track_number = track_number self.duration_ms = duration_ms self.explicit = excplicit @@ -69,13 +71,14 @@ class Track: class SpotifyTrack(Track): def __init__(self, name: str, - album: Album, + album: SpotifyAlbum, artists: List[Artist], href: str = None, uri: Union[str, Uri] = None, disc_number: int = None, + track_number: int = None, duration_ms: int = None, explicit: bool = None, is_playable: bool = None, @@ -86,6 +89,7 @@ class SpotifyTrack(Track): ): super().__init__(name=name, album=album, artists=artists, disc_number=disc_number, + track_number=track_number, duration_ms=duration_ms, excplicit=explicit) @@ -131,13 +135,14 @@ class SpotifyTrack(Track): class LibraryTrack(SpotifyTrack): def __init__(self, name: str, - album: Album, + album: SpotifyAlbum, artists: List[Artist], href: str = None, uri: Union[str, Uri] = None, disc_number: int = None, + track_number: int = None, duration_ms: int = None, explicit: bool = None, is_playable: bool = None, @@ -153,6 +158,7 @@ class LibraryTrack(SpotifyTrack): uri=uri, disc_number=disc_number, + track_number=track_number, duration_ms=duration_ms, explicit=explicit, is_playable=is_playable, @@ -174,7 +180,7 @@ class LibraryTrack(SpotifyTrack): class PlaylistTrack(SpotifyTrack): def __init__(self, name: str, - album: Album, + album: SpotifyAlbum, artists: List[Artist], added_at: datetime, @@ -185,6 +191,7 @@ class PlaylistTrack(SpotifyTrack): uri: Union[str, Uri] = None, disc_number: int = None, + track_number: int = None, duration_ms: int = None, explicit: bool = None, is_playable: bool = None, @@ -198,6 +205,7 @@ class PlaylistTrack(SpotifyTrack): uri=uri, disc_number=disc_number, + track_number=track_number, duration_ms=duration_ms, explicit=explicit, is_playable=is_playable, @@ -221,13 +229,14 @@ class PlaylistTrack(SpotifyTrack): class PlayedTrack(SpotifyTrack): def __init__(self, name: str, - album: Album, + album: SpotifyAlbum, artists: List[Artist], href: str = None, uri: Union[str, Uri] = None, disc_number: int = None, + track_number: int = None, duration_ms: int = None, explicit: bool = None, is_playable: bool = None, @@ -245,6 +254,7 @@ class PlayedTrack(SpotifyTrack): disc_number=disc_number, duration_ms=duration_ms, + track_number=track_number, explicit=explicit, is_playable=is_playable, popularity=popularity, diff --git a/spotframework/net/network.py b/spotframework/net/network.py index 84cf66a..f7bf3ca 100644 --- a/spotframework/net/network.py +++ b/spotframework/net/network.py @@ -1062,6 +1062,11 @@ class Network: artists = [self.parse_artist(i) for i in album.get('artists', [])] + if album.get("album_type") is not None: + album_type = SpotifyAlbum.Type[album.get('album_type').lower()] + else: + album_type = SpotifyAlbum.Type.single + href = album.get('href', None) uri = album.get('uri', None) @@ -1092,6 +1097,8 @@ class Network: return LibraryAlbum(name=name, artists=artists, + album_type=album_type, + href=href, uri=uri, @@ -1109,6 +1116,8 @@ class Network: return SpotifyAlbum(name=name, artists=artists, + album_type=album_type, + href=href, uri=uri, @@ -1143,6 +1152,7 @@ class Network: uri = track.get('uri', None) disc_number = track.get('disc_number', None) + track_number = track.get('track_number', None) duration_ms = track.get('duration_ms', None) explicit = track.get('explicit', None) is_playable = track.get('is_playable', None) @@ -1175,6 +1185,7 @@ class Network: uri=uri, disc_number=disc_number, + track_number=track_number, duration_ms=duration_ms, explicit=explicit, is_playable=is_playable, @@ -1189,6 +1200,7 @@ class Network: uri=uri, disc_number=disc_number, + track_number=track_number, duration_ms=duration_ms, explicit=explicit, is_playable=is_playable, @@ -1204,6 +1216,7 @@ class Network: uri=uri, disc_number=disc_number, + track_number=track_number, duration_ms=duration_ms, explicit=explicit, is_playable=is_playable, @@ -1220,6 +1233,7 @@ class Network: uri=uri, disc_number=disc_number, + track_number=track_number, duration_ms=duration_ms, explicit=explicit, is_playable=is_playable,