mirror of
https://github.com/zhaarey/AppleMusicDecrypt.git
synced 2025-10-23 15:11:06 +00:00
feat: specify language
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
[language]
|
[language]
|
||||||
language = "zh-CN"
|
language = "zh_CN"
|
||||||
languageForGenre = "en_US"
|
|
||||||
|
|
||||||
[[devices]]
|
[[devices]]
|
||||||
host = "127.0.0.1"
|
host = "127.0.0.1"
|
||||||
|
|||||||
14
src/api.py
14
src/api.py
@@ -39,7 +39,7 @@ async def download_song(url: str) -> bytes:
|
|||||||
@retry(retry=retry_if_exception_type((httpx.TimeoutException, httpcore.ConnectError, SSLError, FileNotFoundError)),
|
@retry(retry=retry_if_exception_type((httpx.TimeoutException, httpcore.ConnectError, SSLError, FileNotFoundError)),
|
||||||
stop=stop_after_attempt(5),
|
stop=stop_after_attempt(5),
|
||||||
before_sleep=before_sleep_log(logger, logging.WARN))
|
before_sleep=before_sleep_log(logger, logging.WARN))
|
||||||
async def get_meta(album_id: str, token: str, storefront: str):
|
async def get_meta(album_id: str, token: str, storefront: str, lang: str):
|
||||||
if "pl." in album_id:
|
if "pl." in album_id:
|
||||||
mtype = "playlists"
|
mtype = "playlists"
|
||||||
else:
|
else:
|
||||||
@@ -48,7 +48,7 @@ async def get_meta(album_id: str, token: str, storefront: str):
|
|||||||
params={"omit[resource]": "autos", "include": "tracks,artists,record-labels",
|
params={"omit[resource]": "autos", "include": "tracks,artists,record-labels",
|
||||||
"include[songs]": "artists", "fields[artists]": "name",
|
"include[songs]": "artists", "fields[artists]": "name",
|
||||||
"fields[albums:albums]": "artistName,artwork,name,releaseDate,url",
|
"fields[albums:albums]": "artistName,artwork,name,releaseDate,url",
|
||||||
"fields[record-labels]": "name"},
|
"fields[record-labels]": "name", "l": lang},
|
||||||
headers={"Authorization": f"Bearer {token}", "User-Agent": user_agent_browser,
|
headers={"Authorization": f"Bearer {token}", "User-Agent": user_agent_browser,
|
||||||
"Origin": "https://music.apple.com"})
|
"Origin": "https://music.apple.com"})
|
||||||
if mtype == "albums":
|
if mtype == "albums":
|
||||||
@@ -61,7 +61,8 @@ async def get_meta(album_id: str, token: str, storefront: str):
|
|||||||
while True:
|
while True:
|
||||||
page += 100
|
page += 100
|
||||||
page_req = await client.get(
|
page_req = await client.get(
|
||||||
f"https://amp-api.music.apple.com/v1/catalog/{storefront}/{mtype}/{album_id}/tracks?offset={page}",
|
f"https://amp-api.music.apple.com/v1/catalog/{storefront}/{mtype}/{album_id}/tracks",
|
||||||
|
params={"offset": page, "l": lang},
|
||||||
headers={"Authorization": f"Bearer {token}", "User-Agent": user_agent_browser,
|
headers={"Authorization": f"Bearer {token}", "User-Agent": user_agent_browser,
|
||||||
"Origin": "https://music.apple.com"})
|
"Origin": "https://music.apple.com"})
|
||||||
page_result = TracksMeta.model_validate(page_req.json())
|
page_result = TracksMeta.model_validate(page_req.json())
|
||||||
@@ -84,9 +85,9 @@ async def get_cover(url: str, cover_format: str):
|
|||||||
@retry(retry=retry_if_exception_type((httpx.TimeoutException, httpcore.ConnectError, SSLError, FileNotFoundError)),
|
@retry(retry=retry_if_exception_type((httpx.TimeoutException, httpcore.ConnectError, SSLError, FileNotFoundError)),
|
||||||
stop=stop_after_attempt(5),
|
stop=stop_after_attempt(5),
|
||||||
before_sleep=before_sleep_log(logger, logging.WARN))
|
before_sleep=before_sleep_log(logger, logging.WARN))
|
||||||
async def get_info_from_adam(adam_id: str, token: str, storefront: str):
|
async def get_info_from_adam(adam_id: str, token: str, storefront: str, lang: str):
|
||||||
req = await client.get(f"https://amp-api.music.apple.com/v1/catalog/{storefront}/songs/{adam_id}",
|
req = await client.get(f"https://amp-api.music.apple.com/v1/catalog/{storefront}/songs/{adam_id}",
|
||||||
params={"extend": "extendedAssetUrls", "include": "albums"},
|
params={"extend": "extendedAssetUrls", "include": "albums", "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())
|
||||||
@@ -99,8 +100,9 @@ async def get_info_from_adam(adam_id: str, token: str, storefront: str):
|
|||||||
@retry(retry=retry_if_exception_type((httpx.TimeoutException, httpcore.ConnectError, SSLError, FileNotFoundError)),
|
@retry(retry=retry_if_exception_type((httpx.TimeoutException, httpcore.ConnectError, SSLError, FileNotFoundError)),
|
||||||
stop=stop_after_attempt(5),
|
stop=stop_after_attempt(5),
|
||||||
before_sleep=before_sleep_log(logger, logging.WARN))
|
before_sleep=before_sleep_log(logger, logging.WARN))
|
||||||
async def get_song_lyrics(song_id: str, storefront: str, token: str, dsid: str, account_token: str) -> str:
|
async def get_song_lyrics(song_id: str, storefront: str, token: str, dsid: str, account_token: str, lang: str) -> str:
|
||||||
req = await client.get(f"https://amp-api.music.apple.com/v1/catalog/{storefront}/songs/{song_id}/lyrics",
|
req = await client.get(f"https://amp-api.music.apple.com/v1/catalog/{storefront}/songs/{song_id}/lyrics",
|
||||||
|
params={"l": lang},
|
||||||
headers={"Authorization": f"Bearer {token}", "User-Agent": user_agent_app,
|
headers={"Authorization": f"Bearer {token}", "User-Agent": user_agent_app,
|
||||||
"X-Dsid": dsid},
|
"X-Dsid": dsid},
|
||||||
cookies={f"mz_at_ssl-{dsid}": account_token})
|
cookies={f"mz_at_ssl-{dsid}": account_token})
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ from pydantic import BaseModel
|
|||||||
|
|
||||||
class Language(BaseModel):
|
class Language(BaseModel):
|
||||||
language: str
|
language: str
|
||||||
languageForGenre: str
|
|
||||||
|
|
||||||
|
|
||||||
class Device(BaseModel):
|
class Device(BaseModel):
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ async def rip_song(song: Song, auth_params: GlobalAuthParams, codec: str, config
|
|||||||
force_save: bool = False):
|
force_save: bool = False):
|
||||||
logger.debug(f"Task of song id {song.id} was created")
|
logger.debug(f"Task of song id {song.id} was created")
|
||||||
token = auth_params.anonymousAccessToken
|
token = auth_params.anonymousAccessToken
|
||||||
song_data = await get_info_from_adam(song.id, token, song.storefront)
|
song_data = await get_info_from_adam(song.id, token, song.storefront, config.language.language)
|
||||||
song_metadata = SongMetadata.parse_from_song_data(song_data)
|
song_metadata = SongMetadata.parse_from_song_data(song_data)
|
||||||
logger.info(f"Ripping song: {song_metadata.artist} - {song_metadata.title}")
|
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):
|
||||||
@@ -27,7 +27,7 @@ async def rip_song(song: Song, auth_params: GlobalAuthParams, codec: str, config
|
|||||||
await song_metadata.get_cover(config.download.coverFormat)
|
await song_metadata.get_cover(config.download.coverFormat)
|
||||||
if song_data.attributes.hasTimeSyncedLyrics:
|
if song_data.attributes.hasTimeSyncedLyrics:
|
||||||
lyrics = await get_song_lyrics(song.id, song.storefront, auth_params.accountAccessToken,
|
lyrics = await get_song_lyrics(song.id, song.storefront, auth_params.accountAccessToken,
|
||||||
auth_params.dsid, auth_params.accountToken)
|
auth_params.dsid, auth_params.accountToken, config.language.language)
|
||||||
song_metadata.lyrics = lyrics
|
song_metadata.lyrics = lyrics
|
||||||
song_uri, keys = await extract_media(song_data.attributes.extendedAssetUrls.enhancedHls, codec, song_metadata,
|
song_uri, keys = await extract_media(song_data.attributes.extendedAssetUrls.enhancedHls, codec, song_metadata,
|
||||||
config.download.codecPriority, config.download.codecAlternative)
|
config.download.codecPriority, config.download.codecAlternative)
|
||||||
@@ -46,7 +46,7 @@ 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,
|
async def rip_album(album: Album, auth_params: GlobalAuthParams, codec: str, config: Config, device: Device,
|
||||||
force_save: bool = False):
|
force_save: bool = False):
|
||||||
album_info = await get_meta(album.id, auth_params.anonymousAccessToken, album.storefront)
|
album_info = await get_meta(album.id, auth_params.anonymousAccessToken, album.storefront, config.language.language)
|
||||||
logger.info(f"Ripping Album: {album_info.data[0].attributes.artistName} - {album_info.data[0].attributes.name}")
|
logger.info(f"Ripping Album: {album_info.data[0].attributes.artistName} - {album_info.data[0].attributes.name}")
|
||||||
async with asyncio.TaskGroup() as tg:
|
async with asyncio.TaskGroup() as tg:
|
||||||
for track in album_info.data[0].relationships.tracks.data:
|
for track in album_info.data[0].relationships.tracks.data:
|
||||||
|
|||||||
Reference in New Issue
Block a user