feat: more exactly url match

pull/8/head
WorldObservationLog 4 months ago
parent dc64c6a1bb
commit 5885262fe8
  1. 12
      src/api.py
  2. 8
      src/cmd.py
  3. 13
      src/url.py

@ -39,7 +39,7 @@ async def get_m3u8_from_api(endpoint: str, song_id: str, wait_and_retry: bool =
if resp == "no_found":
if wait_and_retry and recursion_times <= 5:
await asyncio.sleep(5)
return await get_m3u8_from_api(endpoint, song_id, recursion_times=recursion_times+1)
return await get_m3u8_from_api(endpoint, song_id, recursion_times=recursion_times + 1)
return ""
return resp
@ -246,3 +246,13 @@ async def download_m3u8(m3u8_url: str) -> str:
async with request_lock:
resp = await client.get(m3u8_url)
return resp.text
@alru_cache
@retry(retry=retry_if_exception_type(
(httpx.TimeoutException, httpcore.ConnectError, SSLError, FileNotFoundError, httpcore.RemoteProtocolError)),
stop=stop_after_attempt(5),
before_sleep=before_sleep_log(logger, logging.WARN))
async def get_real_url(url: str):
req = await client.get(url, follow_redirects=True, headers={"User-Agent": user_agent_browser})
return str(req.url)

@ -9,7 +9,7 @@ from prompt_toolkit import PromptSession, print_formatted_text, ANSI
from prompt_toolkit.patch_stdout import patch_stdout
from src.adb import Device
from src.api import get_token, init_client_and_lock, upload_m3u8_to_api, get_song_info
from src.api import get_token, init_client_and_lock, upload_m3u8_to_api, get_song_info, get_real_url
from src.config import Config
from src.rip import rip_song, rip_album, rip_artist, rip_playlist
from src.types import GlobalAuthParams
@ -91,6 +91,12 @@ class NewInteractiveShell:
async def do_download(self, raw_url: str, codec: str, force_download: bool, include: bool = False):
url = AppleMusicURL.parse_url(raw_url)
if not url:
real_url = await get_real_url(raw_url)
url = AppleMusicURL.parse_url(real_url)
if not url:
logger.error("Illegal URL!")
return
available_device = await self._get_available_device(url.storefront)
global_auth_param = GlobalAuthParams.from_auth_params_and_token(available_device.get_auth_params(),
self.anonymous_access_token)

@ -1,5 +1,6 @@
from urllib.parse import urlparse, parse_qs
import regex
from pydantic import BaseModel
@ -18,17 +19,19 @@ class AppleMusicURL(BaseModel):
@classmethod
def parse_url(cls, url: str):
if not regex.match(r"https://music.apple.com/(.{2})/(song|album|playlist|artist).*/(pl.*|\d*)", url):
return None
parsed_url = urlparse(url)
paths = parsed_url.path.split("/")
storefront = paths[1]
url_type = paths[2]
match url_type:
case URLType.Song:
url_id = paths[4]
url_id = paths[-1]
return Song(url=url, storefront=storefront, id=url_id, type=URLType.Song)
case URLType.Album:
if not parsed_url.query:
url_id = paths[4]
url_id = paths[-1]
return Album(url=url, storefront=storefront, id=url_id, type=URLType.Album)
else:
url_query = parse_qs(parsed_url.query)
@ -36,13 +39,13 @@ class AppleMusicURL(BaseModel):
url_id = url_query.get("i")[0]
return Song(url=url, storefront=storefront, id=url_id, type=URLType.Song)
else:
url_id = paths[4]
url_id = paths[-1]
return Album(url=url, storefront=storefront, id=url_id, type=URLType.Album)
case URLType.Artist:
url_id = paths[4]
url_id = paths[-1]
return Artist(url=url, storefront=storefront, id=url_id, type=URLType.Artist)
case URLType.Playlist:
url_id = paths[4]
url_id = paths[-1]
return Playlist(url=url, storefront=storefront, id=url_id, type=URLType.Playlist)

Loading…
Cancel
Save