mirror of
https://github.com/zhaarey/AppleMusicDecrypt.git
synced 2025-10-23 15:11:06 +00:00
Merge pull request #8 from TypesTse/master
Some fixes to crush, tags missing and explicit tag support
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -161,3 +161,5 @@ cython_debug/
|
|||||||
#.idea/
|
#.idea/
|
||||||
|
|
||||||
config.toml
|
config.toml
|
||||||
|
.python-version
|
||||||
|
.vscode/*
|
||||||
|
|||||||
@@ -73,10 +73,10 @@ afterDownloaded = ""
|
|||||||
# title, artist, album, album_artist, composer,
|
# title, artist, album, album_artist, composer,
|
||||||
# genre, created, track, tracknum, disk,
|
# genre, created, track, tracknum, disk,
|
||||||
# record_company, upc, isrc, copyright,
|
# record_company, upc, isrc, copyright,
|
||||||
# lyrics, cover
|
# lyrics, cover, ratings(rtng)
|
||||||
embedMetadata = ["title", "artist", "album", "album_artist", "composer",
|
embedMetadata = ["title", "artist", "album", "album_artist", "composer",
|
||||||
"genre", "created", "track", "tracknum", "disk", "lyrics", "cover", "copyright",
|
"genre", "created", "track", "tracknum", "disk", "lyrics", "cover", "copyright",
|
||||||
"record_company", "upc", "isrc"]
|
"record_company", "upc", "isrc","rtng"]
|
||||||
|
|
||||||
[mitm]
|
[mitm]
|
||||||
# The host proxy server listens on
|
# The host proxy server listens on
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ async def get_cover(url: str, cover_format: str, cover_size: str):
|
|||||||
async def get_song_info(song_id: str, token: str, storefront: str, lang: str):
|
async def get_song_info(song_id: str, token: str, storefront: str, lang: str):
|
||||||
async with request_lock:
|
async with request_lock:
|
||||||
req = await client.get(f"https://amp-api.music.apple.com/v1/catalog/{storefront}/songs/{song_id}",
|
req = await client.get(f"https://amp-api.music.apple.com/v1/catalog/{storefront}/songs/{song_id}",
|
||||||
params={"extend": "extendedAssetUrls", "include": "albums", "l": lang},
|
params={"extend": "extendedAssetUrls", "include": "albums,explicit", "l": lang},
|
||||||
headers={"Authorization": f"Bearer {token}", "User-Agent": user_agent_itunes,
|
headers={"Authorization": f"Bearer {token}", "User-Agent": user_agent_itunes,
|
||||||
"Origin": "https://music.apple.com"})
|
"Origin": "https://music.apple.com"})
|
||||||
song_data_obj = SongData.model_validate(req.json())
|
song_data_obj = SongData.model_validate(req.json())
|
||||||
|
|||||||
@@ -41,6 +41,12 @@ class SongMetadata(BaseModel):
|
|||||||
lrc = ttml_convent_to_lrc(value)
|
lrc = ttml_convent_to_lrc(value)
|
||||||
tags.append(f"{key}={lrc}")
|
tags.append(f"{key}={lrc}")
|
||||||
continue
|
continue
|
||||||
|
if key.lower() in ('upc', 'isrc'):
|
||||||
|
tags.append(f"WM/{key.lower()}={value}")
|
||||||
|
continue
|
||||||
|
if key == 'composer':
|
||||||
|
tags.append(f"writer={value}")
|
||||||
|
continue
|
||||||
tags.append(f"{key}={value}")
|
tags.append(f"{key}={value}")
|
||||||
return ":".join(tags)
|
return ":".join(tags)
|
||||||
|
|
||||||
@@ -55,7 +61,8 @@ class SongMetadata(BaseModel):
|
|||||||
copyright=song_data.relationships.albums.data[0].attributes.copyright,
|
copyright=song_data.relationships.albums.data[0].attributes.copyright,
|
||||||
record_company=song_data.relationships.albums.data[0].attributes.recordLabel,
|
record_company=song_data.relationships.albums.data[0].attributes.recordLabel,
|
||||||
upc=song_data.relationships.albums.data[0].attributes.upc,
|
upc=song_data.relationships.albums.data[0].attributes.upc,
|
||||||
isrc=song_data.attributes.isrc
|
isrc=song_data.attributes.isrc,
|
||||||
|
rtng=1 if song_data.attributes.contentRating and song_data.attributes.contentRating == 'explicit' else 0
|
||||||
)
|
)
|
||||||
|
|
||||||
def set_lyrics(self, lyrics: str):
|
def set_lyrics(self, lyrics: str):
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ class Datum1(BaseModel):
|
|||||||
type: Optional[str] = None
|
type: Optional[str] = None
|
||||||
href: Optional[str] = None
|
href: Optional[str] = None
|
||||||
attributes: Attributes1
|
attributes: Attributes1
|
||||||
relationships: Relationships1
|
relationships: Optional[Relationships1] = None
|
||||||
|
|
||||||
|
|
||||||
class Tracks(BaseModel):
|
class Tracks(BaseModel):
|
||||||
@@ -148,12 +148,22 @@ class Relationships(BaseModel):
|
|||||||
record_labels: RecordLabels = Field(..., alias='record-labels')
|
record_labels: RecordLabels = Field(..., alias='record-labels')
|
||||||
|
|
||||||
|
|
||||||
|
class ContentVersion(BaseModel):
|
||||||
|
MZ_INDEXER: Optional[int] = None
|
||||||
|
RTCI: Optional[int] = None
|
||||||
|
|
||||||
|
|
||||||
|
class Meta(BaseModel):
|
||||||
|
contentVersion: ContentVersion
|
||||||
|
|
||||||
|
|
||||||
class Datum(BaseModel):
|
class Datum(BaseModel):
|
||||||
id: Optional[str] = None
|
id: Optional[str] = None
|
||||||
type: Optional[str] = None
|
type: Optional[str] = None
|
||||||
href: Optional[str] = None
|
href: Optional[str] = None
|
||||||
attributes: Attributes
|
attributes: Attributes
|
||||||
relationships: Relationships
|
relationships: Relationships
|
||||||
|
meta: Meta
|
||||||
|
|
||||||
|
|
||||||
class AlbumMeta(BaseModel):
|
class AlbumMeta(BaseModel):
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ class Attributes(BaseModel):
|
|||||||
previews: List[Preview]
|
previews: List[Preview]
|
||||||
artistName: Optional[str] = None
|
artistName: Optional[str] = None
|
||||||
extendedAssetUrls: ExtendedAssetUrls
|
extendedAssetUrls: ExtendedAssetUrls
|
||||||
|
contentRating: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
class Artwork1(BaseModel):
|
class Artwork1(BaseModel):
|
||||||
|
|||||||
23
src/utils.py
23
src/utils.py
@@ -13,6 +13,8 @@ from src.exceptions import NotTimeSyncedLyricsException
|
|||||||
from src.models import PlaylistInfo
|
from src.models import PlaylistInfo
|
||||||
from src.types import *
|
from src.types import *
|
||||||
|
|
||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
|
|
||||||
def check_url(url):
|
def check_url(url):
|
||||||
pattern = regex.compile(
|
pattern = regex.compile(
|
||||||
@@ -82,6 +84,8 @@ def ttml_convent_to_lrc(ttml: str) -> str:
|
|||||||
lyric_time: str = lyric.get("begin")
|
lyric_time: str = lyric.get("begin")
|
||||||
if not lyric_time:
|
if not lyric_time:
|
||||||
raise NotTimeSyncedLyricsException
|
raise NotTimeSyncedLyricsException
|
||||||
|
if lyric_time.find('.') == -1:
|
||||||
|
lyric_time += '.000'
|
||||||
match lyric_time.count(":"):
|
match lyric_time.count(":"):
|
||||||
case 0:
|
case 0:
|
||||||
split_time = lyric_time.split(".")
|
split_time = lyric_time.split(".")
|
||||||
@@ -146,17 +150,26 @@ def playlist_metadata_to_params(playlist: PlaylistInfo):
|
|||||||
return {"playlistName": playlist.data[0].attributes.name,
|
return {"playlistName": playlist.data[0].attributes.name,
|
||||||
"playlistCuratorName": playlist.data[0].attributes.curatorName}
|
"playlistCuratorName": playlist.data[0].attributes.curatorName}
|
||||||
|
|
||||||
|
def get_path_safe_dict(param: dict):
|
||||||
|
new_param = deepcopy(param)
|
||||||
|
for key, val in new_param.items():
|
||||||
|
if isinstance(val, str):
|
||||||
|
new_param[key] = get_valid_filename(str(val))
|
||||||
|
return new_param
|
||||||
|
|
||||||
def get_song_name_and_dir_path(codec: str, config: Download, metadata, playlist: PlaylistInfo = None):
|
def get_song_name_and_dir_path(codec: str, config: Download, metadata, playlist: PlaylistInfo = None):
|
||||||
if playlist:
|
if playlist:
|
||||||
|
safe_meta = get_path_safe_dict(metadata.model_dump())
|
||||||
|
safe_pl_meta = get_path_safe_dict(playlist_metadata_to_params(playlist))
|
||||||
song_name = config.playlistSongNameFormat.format(codec=codec, playlistSongIndex=metadata.playlistIndex,
|
song_name = config.playlistSongNameFormat.format(codec=codec, playlistSongIndex=metadata.playlistIndex,
|
||||||
**metadata.model_dump())
|
**safe_meta)
|
||||||
dir_path = Path(config.playlistDirPathFormat.format(codec=codec,
|
dir_path = Path(config.playlistDirPathFormat.format(codec=codec,
|
||||||
**metadata.model_dump(),
|
**safe_meta,
|
||||||
**playlist_metadata_to_params(playlist)))
|
**safe_pl_meta))
|
||||||
else:
|
else:
|
||||||
song_name = config.songNameFormat.format(codec=codec, **metadata.model_dump())
|
safe_meta = get_path_safe_dict(metadata.model_dump())
|
||||||
dir_path = Path(config.dirPathFormat.format(codec=codec, **metadata.model_dump()))
|
song_name = config.songNameFormat.format(codec=codec, **safe_meta)
|
||||||
|
dir_path = Path(config.dirPathFormat.format(codec=codec, **safe_meta))
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
song_name = get_valid_filename(song_name)
|
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])
|
dir_path = Path(*[get_valid_filename(part) if ":\\" not in part else part for part in dir_path.parts])
|
||||||
|
|||||||
Reference in New Issue
Block a user