From 43fb4679a79f62c859f2b1a59b0bf5f330595fa4 Mon Sep 17 00:00:00 2001 From: WorldObservationLog Date: Mon, 6 May 2024 23:52:04 +0800 Subject: [PATCH] feat: support playlistSongIndex --- src/metadata.py | 6 ++++++ src/models/playlist_info.py | 1 + src/rip.py | 14 ++++++++++---- src/utils.py | 15 +++++++++++---- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/metadata.py b/src/metadata.py index 5b17543..0f90b0a 100644 --- a/src/metadata.py +++ b/src/metadata.py @@ -25,6 +25,7 @@ class SongMetadata(BaseModel): record_company: Optional[str] = None upc: Optional[str] = None isrc: Optional[str] = None + playlistIndex: Optional[int] = None def to_itags_params(self, embed_metadata: list[str]): tags = [] @@ -32,6 +33,8 @@ class SongMetadata(BaseModel): if not value: continue if key in embed_metadata and value: + if "playlist" in key: + continue if key == "cover": continue if key == "lyrics": @@ -60,3 +63,6 @@ class SongMetadata(BaseModel): async def get_cover(self, cover_format: str, cover_size: str): self.cover = await get_cover(self.cover_url, cover_format, cover_size) + + def set_playlist_index(self, index: int): + self.playlistIndex = index diff --git a/src/models/playlist_info.py b/src/models/playlist_info.py index 0f2e04e..f6e6978 100644 --- a/src/models/playlist_info.py +++ b/src/models/playlist_info.py @@ -132,3 +132,4 @@ class Datum(BaseModel): class PlaylistInfo(BaseModel): data: List[Datum] + songIdIndexMapping: dict[str, int] = {} diff --git a/src/rip.py b/src/rip.py index ff0e619..f4e0171 100644 --- a/src/rip.py +++ b/src/rip.py @@ -14,7 +14,7 @@ from src.mp4 import extract_media, extract_song, encapsulate, write_metadata from src.save import save from src.types import GlobalAuthParams, Codec from src.url import Song, Album, URLType, Artist, Playlist -from src.utils import check_song_exists, if_raw_atmos +from src.utils import check_song_exists, if_raw_atmos, playlist_write_song_index @logger.catch @@ -24,6 +24,8 @@ async def rip_song(song: Song, auth_params: GlobalAuthParams, codec: str, config token = auth_params.anonymousAccessToken song_data = await get_song_info(song.id, token, song.storefront, config.region.language) song_metadata = SongMetadata.parse_from_song_data(song_data) + if playlist: + song_metadata.set_playlist_index(playlist.songIdIndexMapping.get(song.id)) logger.info(f"Ripping song: {song_metadata.artist} - {song_metadata.title}") if not force_save and check_song_exists(song_metadata, config.download, codec, playlist): logger.info(f"Song: {song_metadata.artist} - {song_metadata.title} already exists") @@ -74,13 +76,17 @@ async def rip_album(album: Album, auth_params: GlobalAuthParams, codec: str, con async def rip_playlist(playlist: Playlist, auth_params: GlobalAuthParams, codec: str, config: Config, device: Device, force_save: bool = False): - playlist_info = await get_playlist_info_and_tracks(playlist.id, auth_params.anonymousAccessToken, playlist.storefront, + playlist_info = await get_playlist_info_and_tracks(playlist.id, auth_params.anonymousAccessToken, + playlist.storefront, config.region.language) - logger.info(f"Ripping Playlist: {playlist_info.data[0].attributes.curatorName} - {playlist_info.data[0].attributes.name}") + playlist_info = playlist_write_song_index(playlist_info) + logger.info( + f"Ripping Playlist: {playlist_info.data[0].attributes.curatorName} - {playlist_info.data[0].attributes.name}") async with asyncio.TaskGroup() as tg: for track in playlist_info.data[0].relationships.tracks.data: song = Song(id=track.id, storefront=playlist.storefront, url="", type=URLType.Song) - tg.create_task(rip_song(song, auth_params, codec, config, device, force_save=force_save, playlist=playlist_info)) + tg.create_task( + rip_song(song, auth_params, codec, config, device, force_save=force_save, playlist=playlist_info)) logger.info( f"Playlist: {playlist_info.data[0].attributes.curatorName} - {playlist_info.data[0].attributes.name} finished ripping") diff --git a/src/utils.py b/src/utils.py index 4499bf5..286582a 100644 --- a/src/utils.py +++ b/src/utils.py @@ -147,11 +147,12 @@ def playlist_metadata_to_params(playlist: PlaylistInfo): "playlistCuratorName": playlist.data[0].attributes.curatorName} -def get_song_name_and_dir_path(codec: str, config: Download, metadata, playlist: PlaylistMeta = None): +def get_song_name_and_dir_path(codec: str, config: Download, metadata, playlist: PlaylistInfo = None): if playlist: - song_name = config.playlistSongNameFormat.format(codec=codec, **metadata.model_dump(), - **playlist_metadata_to_params(playlist)) - dir_path = Path(config.playlistDirPathFormat.format(codec=codec, **metadata.model_dump(), + song_name = config.playlistSongNameFormat.format(codec=codec, playlistSongIndex=metadata.playlistIndex, + **metadata.model_dump()) + dir_path = Path(config.playlistDirPathFormat.format(codec=codec, + **metadata.model_dump(), **playlist_metadata_to_params(playlist))) else: song_name = config.songNameFormat.format(codec=codec, **metadata.model_dump()) @@ -160,3 +161,9 @@ def get_song_name_and_dir_path(codec: str, config: Download, metadata, playlist: song_name = get_valid_filename(song_name) dir_path = Path(*[get_valid_filename(part) if ":\\" not in part else part for part in dir_path.parts]) return song_name, dir_path + + +def playlist_write_song_index(playlist: PlaylistInfo): + for track_index, track in enumerate(playlist.data[0].relationships.tracks.data): + playlist.songIdIndexMapping[track.id] = track_index + 1 + return playlist