from __future__ import annotations from typing import Iterable, Mapping, Sequence from src.api_client.dsp.deeezer import DeezerApiClient from src.data_info import PlaylistInfo, TrackInfo from src.enums import ServiceType from ..errors import DeezerSynchronizerError from .base import BaseSynchronizer __all__ = ["DeezerSynchronizer"] class DeezerSynchronizer(BaseSynchronizer[DeezerApiClient]): service_type = ServiceType.deezer vendor_specific_sync_error_cls = DeezerSynchronizerError def _get_tracks_from_dsp(self, tracks: Iterable[TrackInfo]) -> Mapping[TrackInfo, str]: mapping = {} for track in tracks: if track.isrc is None: # TODO: consider do searching by title if there is no ISRC for track continue mapping[track] = self.api_client.get_track_id_by_isrc(track.isrc) return mapping def _get_target_track_ids(self, playlist_id: str) -> Iterable[str]: return self.api_client.get_playlist_track_ids(playlist_id) def _synchronize_tracks( self, playlist_id: str, source_track_ids: Sequence[str], target_track_ids: Sequence[str] ) -> tuple[int, int]: source_tracks_set = set(source_track_ids) target_tracks_set = set(target_track_ids) to_insert = source_tracks_set - target_tracks_set to_delete = target_tracks_set - source_tracks_set if to_insert: self.api_client.insert_tracks(playlist_id, to_insert) if to_delete: self.api_client.delete_tracks(playlist_id, to_delete) if source_track_ids != target_track_ids: self.api_client.sort_tracks(playlist_id, source_track_ids) return len(to_insert), len(to_delete) def get_playlist_info(self, playlist_id: str) -> PlaylistInfo: return self.api_client.get_playlist_info(playlist_id) def _update_playlist_info(self, playlist_id: str, old_info: PlaylistInfo, new_info: Mapping[str, str | None]): self.api_client.update_playlist_info(playlist_id, new_info)