diff --git a/pyproject.toml b/pyproject.toml index 3b51085..95109da 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "unitunes" -version = "0.1.3" +version = "1.0.0" description = "A CLI tool to manage playlists across music streaming services." authors = ["platers "] readme = "README.md" diff --git a/unitunes/cli/cli.py b/unitunes/cli/cli.py index 009b327..bf99c84 100644 --- a/unitunes/cli/cli.py +++ b/unitunes/cli/cli.py @@ -236,30 +236,30 @@ def remove_tracks(current_tracks: List[Track], missing: List[TrackURIs]) -> None missing_uris: List[TrackURIs] = [] for service in services: - playlist_uri = pl.get_uri(service.name) - if not playlist_uri: + if service.name not in pl.uris: continue - remote_tracks = service.pull_tracks(playlist_uri) + for playlist_uri in pl.uris[service.name]: + remote_tracks = service.pull_tracks(playlist_uri) - added = tracks_to_add(service.type, pl.tracks, remote_tracks) - print(f"Added {len(added)} tracks") + added = tracks_to_add(service.type, pl.tracks, remote_tracks) + print(f"Added {len(added)} tracks") - if added: - console.print( - f"{playlist_uri.url} added {len(added)} tracks from {service.name}" - ) - print_tracks(added) - new_tracks.extend(added) - - if not dont_remove: - missing = get_missing_uris(service.type, pl.tracks, remote_tracks) - if missing: + if added: console.print( - f"{playlist_uri.url} missing {len(missing)} tracks from {pl.name}" + f"{playlist_uri.url} added {len(added)} tracks from {service.name}" ) + print_tracks(added) + new_tracks.extend(added) + + if not dont_remove: + missing = get_missing_uris(service.type, pl.tracks, remote_tracks) + if missing: + console.print( + f"{playlist_uri.url} missing {len(missing)} tracks from {pl.name}" + ) - missing_uris.extend(missing) + missing_uris.extend(missing) if verbose: print_tracks(new_tracks) @@ -310,42 +310,42 @@ def push( if not any([t.find_uri(service.type) for t in pl.tracks]): continue - playlist_uri = pl.get_uri(service.name) - if not playlist_uri: + if not service.name in pl.uris: console.print(f"{pl.name} does not have a uri for {service.type}") create_new = typer.confirm("Create new playlist?", default=False) if not create_new: continue playlist_uri = service.create_playlist(pl.name) console.print(f"Created {playlist_uri.url}") - pl.set_uri(service.name, playlist_uri) + pl.add_uri(service.name, playlist_uri) pm.save_playlist(pl.name) - current_tracks = service.pull_tracks(playlist_uri) - added = tracks_to_add(service.type, current_tracks, pl.tracks) - removed = tracks_to_remove(service.type, current_tracks, pl.tracks) - - if added: - console.print(f"{len(added)} new tracks") - console.print("Added tracks:") - print_tracks(added) - if removed: - console.print("Removed tracks:") - console.print(f"{len(removed)} removed tracks") - print_tracks(removed) - - if not added and not removed: - continue + for playlist_uri in pl.uris[service.name]: + current_tracks = service.pull_tracks(playlist_uri) + added = tracks_to_add(service.type, current_tracks, pl.tracks) + removed = tracks_to_remove(service.type, current_tracks, pl.tracks) + + if added: + console.print(f"{len(added)} new tracks") + console.print("Added tracks:") + print_tracks(added) + if removed: + console.print("Removed tracks:") + console.print(f"{len(removed)} removed tracks") + print_tracks(removed) + + if not added and not removed: + continue - if not typer.confirm(f"Push to {playlist_uri.url}?", default=False): - continue + if not typer.confirm(f"Push to {playlist_uri.url}?", default=False): + continue - if added: - service.add_tracks(playlist_uri, added) - if removed: - service.remove_tracks(playlist_uri, removed) + if added: + service.add_tracks(playlist_uri, added) + if removed: + service.remove_tracks(playlist_uri, removed) - console.print(f"Pushed {pl.name} to {playlist_uri.url}") + console.print(f"Pushed {pl.name} to {playlist_uri.url}") @app.command() @@ -463,6 +463,10 @@ def add( """ pm = get_playlist_manager(Path.cwd()) + if service_name not in pm.services: + console.print(f"Service {service_name} not found", style="red") + return + if playlist_name not in pm.playlists: pm.add_playlist(playlist_name) console.print(f"Created playlist {playlist_name}") diff --git a/unitunes/cli/utils.py b/unitunes/cli/utils.py index 40768a6..0c8e6b9 100644 --- a/unitunes/cli/utils.py +++ b/unitunes/cli/utils.py @@ -62,8 +62,5 @@ def print_tracks(tracks: List[Track], plain: bool = False) -> None: def print_playlist(playlist: Playlist, plain: bool = False) -> None: - console.print(playlist.name, style="bold") - console.print(f"Description: {playlist.description}") - console.print(f"{len(playlist.tracks)} tracks") - console.print(f"URIs: {', '.join([u.url for u in playlist.uris.values()])}") + console.print(playlist) print_tracks(playlist.tracks, plain=plain) diff --git a/unitunes/main.py b/unitunes/main.py index c6722bf..e09d95b 100644 --- a/unitunes/main.py +++ b/unitunes/main.py @@ -167,7 +167,7 @@ def remove_service(self, name: str) -> None: self.config.remove_service(name) for playlist in self.playlists.values(): - playlist.remove_uri(name) + playlist.remove_service(name) self.file_manager.save_playlist(playlist) self.file_manager.save_config(self.config) @@ -184,7 +184,7 @@ def add_uri_to_playlist( ) -> None: """Link a playlist URI to a UP. UP must exist.""" pl = self.playlists[playlist_name] - pl.set_uri(service_name, uri) + pl.add_uri(service_name, uri) self.file_manager.save_config(self.config) self.file_manager.save_playlist(pl) diff --git a/unitunes/playlist.py b/unitunes/playlist.py index e6af198..194c0dd 100644 --- a/unitunes/playlist.py +++ b/unitunes/playlist.py @@ -18,39 +18,38 @@ class PlaylistMetadata(BaseModel): class Playlist(BaseModel): name: str description: str = "" - uris: Dict[str, PlaylistURIs] = {} + uris: Dict[str, List[PlaylistURIs]] = {} tracks: List[Track] = [] def __rich__(self): s = f"[b]{self.name}[/b]\n" s += f"Description: {self.description}\n" if self.uris: - s += f"\nURIs: {', '.join(uri.__rich__() for uri in self.uris.values())}" + for service_name, uris in self.uris.items(): + s += f"{service_name}: " + for uri in uris: + s += f"{uri.url} " if self.tracks: joined = "\n".join(track.__rich__() for track in self.tracks) s += f"\nTracks:\n{joined}" return s - def find_uri(self, service: ServiceType) -> Optional[PlaylistURIs]: - for uri in self.uris.values(): - if uri.service == service: - return uri - return None + def add_uri(self, service_name: str, uri: PlaylistURIs) -> None: + if service_name not in self.uris: + self.uris[service_name] = [] + self.uris[service_name].append(uri) - def get_uri(self, service_name: str) -> Optional[PlaylistURIs]: - if service_name in self.uris: - return self.uris[service_name] - return None + def remove_uri(self, service_name: str, uri: PlaylistURIs) -> None: + self.uris[service_name].remove(uri) + if not self.uris[service_name]: + del self.uris[service_name] - def set_uri(self, service_name: str, uri: PlaylistURIs) -> None: - self.uris[service_name] = uri - - def remove_uri(self, service_name: str) -> None: + def remove_service(self, service_name: str) -> None: del self.uris[service_name] def contains_uri(self, uri: PlaylistURIs) -> bool: - for uri_ in self.uris.values(): - if uri_.uri == uri.uri: + for service_name, uris in self.uris.items(): + if uri in uris: return True return False