mirror of
https://github.com/glomatico/gamdl.git
synced 2026-06-13 04:05:14 +03:00
Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b0c5335767 | |||
| 69c2a8a063 | |||
| fb143ad1b4 | |||
| b66c06a9cb | |||
| a9e75384f0 |
+1
-1
@@ -1 +1 @@
|
||||
__version__ = "3.7.3"
|
||||
__version__ = "3.7.4"
|
||||
|
||||
@@ -93,7 +93,7 @@ class AppleMusicApi:
|
||||
)
|
||||
|
||||
index_js_uri_match = re.search(
|
||||
r"/(assets/index-legacy[~-][^/\"]+\.js)",
|
||||
r"/(assets/index[~-][^/\"]+\.js)",
|
||||
home_page,
|
||||
)
|
||||
if not index_js_uri_match:
|
||||
@@ -116,7 +116,7 @@ class AppleMusicApi:
|
||||
status_code=response.status_code if response is not None else None,
|
||||
)
|
||||
|
||||
token_match = re.search('(?=eyJh)(.*?)(?=")', index_js_page)
|
||||
token_match = re.search(r'"(eyJ[A-Za-z0-9\-_]+\.eyJ[A-Za-z0-9\-_]+\.[A-Za-z0-9\-_]+)"', index_js_page)
|
||||
if not token_match:
|
||||
raise GamdlApiResponseError("Error finding token in index.js page")
|
||||
token = token_match.group(1)
|
||||
|
||||
+15
-3
@@ -1,3 +1,6 @@
|
||||
import json
|
||||
from typing import Any
|
||||
|
||||
from ..utils import GamdlError
|
||||
|
||||
|
||||
@@ -9,7 +12,7 @@ class GamdlApiResponseError(GamdlApiError):
|
||||
def __init__(
|
||||
self,
|
||||
message: str,
|
||||
content: str | None = None,
|
||||
content: Any | None = None,
|
||||
status_code: int | None = None,
|
||||
):
|
||||
self.message = message
|
||||
@@ -19,7 +22,16 @@ class GamdlApiResponseError(GamdlApiError):
|
||||
if status_code is not None:
|
||||
message = f"{message} (Status code: {status_code})"
|
||||
|
||||
if content:
|
||||
message += f": {content}"
|
||||
if content is not None:
|
||||
if isinstance(content, str):
|
||||
content_text = content
|
||||
else:
|
||||
try:
|
||||
content_text = json.dumps(content)
|
||||
except TypeError:
|
||||
content_text = str(content)
|
||||
|
||||
if content_text:
|
||||
message += f": {content_text}"
|
||||
|
||||
super().__init__(message)
|
||||
|
||||
@@ -205,8 +205,8 @@ class AppleMusicBaseInterface:
|
||||
async def get_cover_bytes(self, cover_url: str) -> bytes | None:
|
||||
log = logger.bind(action="get_cover_bytes", cover_url=cover_url)
|
||||
|
||||
async with httpx.AsyncClient() as client:
|
||||
response = await client.get(cover_url)
|
||||
async with httpx.AsyncClient(timeout=30.0) as client:
|
||||
response = await client.get(cover_url, follow_redirects=True)
|
||||
|
||||
if response.status_code == 404:
|
||||
log.debug("cover_not_found")
|
||||
|
||||
+28
-11
@@ -191,18 +191,24 @@ class AppleMusicSongInterface:
|
||||
|
||||
return f"[{timestamp.strftime('%M:%S.%f')[:-4]}]{text}"
|
||||
|
||||
def _get_m3u8_from_playback(self, playback: dict) -> str | None:
|
||||
return playback["songList"][0].get("hls-playlist-url")
|
||||
def _switch_m3u8_master_url_to_default(self, m3u8_master_url: str) -> str:
|
||||
return re.sub(
|
||||
r"(P\d+)_[^/]+(\.m3u8)",
|
||||
r"\1_default\2",
|
||||
m3u8_master_url,
|
||||
)
|
||||
|
||||
async def get_m3u8_master_url(
|
||||
self,
|
||||
playback: dict | None,
|
||||
song_metadata: dict | None,
|
||||
) -> str | None:
|
||||
if playback:
|
||||
return self._get_m3u8_from_playback(playback)
|
||||
else:
|
||||
return await self._get_m3u8_master_url_from_metadata(song_metadata)
|
||||
def _get_m3u8_from_playback(self, playback: dict) -> str | None:
|
||||
log = logger.bind(action="get_m3u8_master_url_from_playback")
|
||||
|
||||
m3u8_master_url = playback["songList"][0].get("hls-playlist-url")
|
||||
|
||||
if m3u8_master_url:
|
||||
m3u8_master_url = self._switch_m3u8_master_url_to_default(m3u8_master_url)
|
||||
log.debug("success", m3u8_master_url=m3u8_master_url)
|
||||
return m3u8_master_url
|
||||
|
||||
log.debug("no_m3u8_master_url")
|
||||
|
||||
async def _get_m3u8_master_url_from_metadata(
|
||||
self,
|
||||
@@ -227,6 +233,7 @@ class AppleMusicSongInterface:
|
||||
enhanced = song_metadata["attributes"]["extendedAssetUrls"].get("enhancedHls")
|
||||
|
||||
if enhanced:
|
||||
enhanced = self._switch_m3u8_master_url_to_default(enhanced)
|
||||
log.debug("success", m3u8_master_url=enhanced)
|
||||
return enhanced
|
||||
|
||||
@@ -234,6 +241,16 @@ class AppleMusicSongInterface:
|
||||
|
||||
return None
|
||||
|
||||
async def get_m3u8_master_url(
|
||||
self,
|
||||
playback: dict | None,
|
||||
song_metadata: dict | None,
|
||||
) -> str | None:
|
||||
if playback:
|
||||
return self._get_m3u8_from_playback(playback)
|
||||
else:
|
||||
return await self._get_m3u8_master_url_from_metadata(song_metadata)
|
||||
|
||||
async def get_stream_info(
|
||||
self,
|
||||
media_id: str,
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "gamdl"
|
||||
version = "3.7.3"
|
||||
version = "3.7.4"
|
||||
description = "A command-line app for downloading Apple Music songs, music videos and post videos."
|
||||
readme = "README.md"
|
||||
license = "MIT"
|
||||
|
||||
Reference in New Issue
Block a user