mirror of
https://github.com/zhaarey/AppleMusicDecrypt.git
synced 2025-10-23 15:11:06 +00:00
feat: playlist download
This commit is contained in:
49
src/rip.py
49
src/rip.py
@@ -3,27 +3,29 @@ import subprocess
|
||||
|
||||
from loguru import logger
|
||||
|
||||
from src.api import (get_info_from_adam, get_song_lyrics, get_meta, download_song,
|
||||
get_m3u8_from_api, get_artist_info, get_songs_from_artist, get_albums_from_artist)
|
||||
from src.api import (get_song_info, get_song_lyrics, get_album_info, download_song,
|
||||
get_m3u8_from_api, get_artist_info, get_songs_from_artist, get_albums_from_artist,
|
||||
get_playlist_info_and_tracks)
|
||||
from src.config import Config, Device
|
||||
from src.decrypt import decrypt
|
||||
from src.metadata import SongMetadata
|
||||
from src.models import PlaylistMeta
|
||||
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
|
||||
from src.utils import check_song_exists
|
||||
from src.url import Song, Album, URLType, Artist, Playlist
|
||||
from src.utils import check_song_exists, if_raw_atmos
|
||||
|
||||
|
||||
@logger.catch
|
||||
async def rip_song(song: Song, auth_params: GlobalAuthParams, codec: str, config: Config, device: Device,
|
||||
force_save: bool = False, specified_m3u8: str = ""):
|
||||
force_save: bool = False, specified_m3u8: str = "", playlist: PlaylistMeta = None):
|
||||
logger.debug(f"Task of song id {song.id} was created")
|
||||
token = auth_params.anonymousAccessToken
|
||||
song_data = await get_info_from_adam(song.id, token, song.storefront, config.region.language)
|
||||
song_data = await get_song_info(song.id, token, song.storefront, config.region.language)
|
||||
song_metadata = SongMetadata.parse_from_song_data(song_data)
|
||||
logger.info(f"Ripping song: {song_metadata.artist} - {song_metadata.title}")
|
||||
if not force_save and check_song_exists(song_metadata, config.download, codec):
|
||||
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")
|
||||
return
|
||||
await song_metadata.get_cover(config.download.coverFormat, config.download.coverSize)
|
||||
@@ -47,11 +49,9 @@ async def rip_song(song: Song, auth_params: GlobalAuthParams, codec: str, config
|
||||
song_info = extract_song(raw_song, codec)
|
||||
decrypted_song = await decrypt(song_info, keys, song_data, device)
|
||||
song = encapsulate(song_info, decrypted_song, config.download.atmosConventToM4a)
|
||||
if codec != Codec.EC3 or (codec == Codec.EC3 and config.download.atmosConventToM4a):
|
||||
if not if_raw_atmos(codec, config.download.atmosConventToM4a):
|
||||
song = write_metadata(song, song_metadata, config.metadata.embedMetadata, config.download.coverFormat)
|
||||
elif codec != Codec.AC3 or (codec == Codec.AC3 and config.download.atmosConventToM4a):
|
||||
song = write_metadata(song, song_metadata, config.metadata.embedMetadata, config.download.coverFormat)
|
||||
filename = save(song, codec, song_metadata, config.download)
|
||||
filename = save(song, codec, song_metadata, config.download, playlist)
|
||||
logger.info(f"Song {song_metadata.artist} - {song_metadata.title} saved!")
|
||||
if config.download.afterDownloaded:
|
||||
command = config.download.afterDownloaded.format(filename=filename)
|
||||
@@ -61,7 +61,8 @@ async def rip_song(song: Song, auth_params: GlobalAuthParams, codec: str, config
|
||||
|
||||
async def rip_album(album: Album, auth_params: GlobalAuthParams, codec: str, config: Config, device: Device,
|
||||
force_save: bool = False):
|
||||
album_info = await get_meta(album.id, auth_params.anonymousAccessToken, album.storefront, config.region.language)
|
||||
album_info = await get_album_info(album.id, auth_params.anonymousAccessToken, album.storefront,
|
||||
config.region.language)
|
||||
logger.info(f"Ripping Album: {album_info.data[0].attributes.artistName} - {album_info.data[0].attributes.name}")
|
||||
async with asyncio.TaskGroup() as tg:
|
||||
for track in album_info.data[0].relationships.tracks.data:
|
||||
@@ -71,21 +72,33 @@ async def rip_album(album: Album, auth_params: GlobalAuthParams, codec: str, con
|
||||
f"Album: {album_info.data[0].attributes.artistName} - {album_info.data[0].attributes.name} finished ripping")
|
||||
|
||||
|
||||
async def rip_playlist():
|
||||
pass
|
||||
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,
|
||||
config.region.language)
|
||||
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))
|
||||
logger.info(
|
||||
f"Playlist: {playlist_info.data[0].attributes.curatorName} - {playlist_info.data[0].attributes.name} finished ripping")
|
||||
|
||||
|
||||
async def rip_artist(artist: Artist, auth_params: GlobalAuthParams, codec: str, config: Config, device: Device,
|
||||
force_save: bool = False, include_participate_in_works: bool = False):
|
||||
artist_info = await get_artist_info(artist.id, artist.storefront, auth_params.anonymousAccessToken, config.region.language)
|
||||
artist_info = await get_artist_info(artist.id, artist.storefront, auth_params.anonymousAccessToken,
|
||||
config.region.language)
|
||||
logger.info(f"Ripping Artist: {artist_info.data[0].attributes.name}")
|
||||
async with asyncio.TaskGroup() as tg:
|
||||
if include_participate_in_works:
|
||||
songs = await get_songs_from_artist(artist.id, artist.storefront, auth_params.anonymousAccessToken, config.region.language)
|
||||
songs = await get_songs_from_artist(artist.id, artist.storefront, auth_params.anonymousAccessToken,
|
||||
config.region.language)
|
||||
for song_url in songs:
|
||||
tg.create_task(rip_song(Song.parse_url(song_url), auth_params, codec, config, device, force_save))
|
||||
else:
|
||||
albums = await get_albums_from_artist(artist.id, artist.storefront, auth_params.anonymousAccessToken, config.region.language)
|
||||
albums = await get_albums_from_artist(artist.id, artist.storefront, auth_params.anonymousAccessToken,
|
||||
config.region.language)
|
||||
for album_url in albums:
|
||||
tg.create_task(rip_album(Album.parse_url(album_url), auth_params, codec, config, device, force_save))
|
||||
logger.info(f"Artist: {artist_info.data[0].attributes.name} finished ripping")
|
||||
logger.info(f"Artist: {artist_info.data[0].attributes.name} finished ripping")
|
||||
|
||||
Reference in New Issue
Block a user