mirror of
https://github.com/oskvr37/tiddl.git
synced 2026-06-13 12:15:13 +03:00
✨ Added mix downloading
This commit is contained in:
@@ -17,6 +17,12 @@ class TestTidalResource(unittest.TestCase):
|
||||
("playlist/12345678", "playlist", "12345678"),
|
||||
("https://tidal.com/browse/artist/12345678", "artist", "12345678"),
|
||||
("artist/12345678", "artist", "12345678"),
|
||||
(
|
||||
"https://tidal.com/browse/mix/f93b015796bf93b015796b",
|
||||
"mix",
|
||||
"f93b015796bf93b015796b",
|
||||
),
|
||||
("mix/f93b015796bf93b015796b", "mix", "f93b015796bf93b015796b"),
|
||||
]
|
||||
|
||||
for resource, expected_type, expected_id in positive_cases:
|
||||
|
||||
@@ -27,6 +27,7 @@ from tiddl.models.api import (
|
||||
Video,
|
||||
VideoStream,
|
||||
Lyrics,
|
||||
MixItems,
|
||||
)
|
||||
|
||||
from tiddl.models.constants import TrackQuality
|
||||
@@ -53,6 +54,7 @@ class Limits:
|
||||
ALBUM_ITEMS = 10
|
||||
ALBUM_ITEMS_MAX = 100
|
||||
PLAYLIST = 50
|
||||
MIX_ITEMS = 100
|
||||
|
||||
|
||||
class TidalApi:
|
||||
@@ -175,6 +177,23 @@ class TidalApi:
|
||||
expire_after=3600,
|
||||
)
|
||||
|
||||
def getMix(
|
||||
self,
|
||||
mix_id: str | int,
|
||||
limit=LIMITS.MIX_ITEMS,
|
||||
offset=0,
|
||||
):
|
||||
return self.fetch(
|
||||
MixItems,
|
||||
f"mixes/{mix_id}/items",
|
||||
{
|
||||
"countryCode": self.country_code,
|
||||
"limit": limit,
|
||||
"offset": offset,
|
||||
},
|
||||
expire_after=3600,
|
||||
)
|
||||
|
||||
def getFavorites(self):
|
||||
return self.fetch(
|
||||
Favorites,
|
||||
|
||||
@@ -405,6 +405,16 @@ def DownloadCommand(
|
||||
|
||||
downloadAlbum(album)
|
||||
|
||||
case "mix":
|
||||
mix = api.getMix(resource.id)
|
||||
|
||||
for mix_item in mix.items:
|
||||
filename = formatResource(
|
||||
TEMPLATE or ctx.obj.config.template.track, mix_item.item
|
||||
)
|
||||
|
||||
submitItem(mix_item.item, filename)
|
||||
|
||||
case "artist":
|
||||
artist = api.getArtist(resource.id)
|
||||
logging.info(f"Artist {artist.name!r}")
|
||||
|
||||
@@ -102,6 +102,13 @@ class PlaylistItems(Items):
|
||||
items: List[Union[PlaylistTrackItem, PlaylistVideoItem]]
|
||||
|
||||
|
||||
class MixItems(Items):
|
||||
class MixItem(BaseModel):
|
||||
item: Track
|
||||
type: ItemType = "track"
|
||||
|
||||
items: List[MixItem]
|
||||
|
||||
class Favorites(BaseModel):
|
||||
PLAYLIST: List[str]
|
||||
ALBUM: List[str]
|
||||
|
||||
+9
-2
@@ -14,7 +14,7 @@ from typing import Literal, Union, get_args
|
||||
from tiddl.models.constants import TrackQuality, QUALITY_TO_ARG
|
||||
from tiddl.models.resource import Track, Video
|
||||
|
||||
ResourceTypeLiteral = Literal["track", "video", "album", "playlist", "artist"]
|
||||
ResourceTypeLiteral = Literal["track", "video", "album", "playlist", "artist", "mix"]
|
||||
|
||||
|
||||
class TidalResource(BaseModel):
|
||||
@@ -41,7 +41,14 @@ class TidalResource(BaseModel):
|
||||
if resource_type not in get_args(ResourceTypeLiteral):
|
||||
raise ValueError(f"Invalid resource type: {resource_type}")
|
||||
|
||||
if not resource_id.isdigit() and resource_type != "playlist":
|
||||
digit_resource_types: list[ResourceTypeLiteral] = [
|
||||
"track",
|
||||
"album",
|
||||
"video",
|
||||
"artist",
|
||||
]
|
||||
|
||||
if resource_type in digit_resource_types and not resource_id.isdigit():
|
||||
raise ValueError(f"Invalid resource id: {resource_id}")
|
||||
|
||||
return cls(type=resource_type, id=resource_id) # type: ignore
|
||||
|
||||
Reference in New Issue
Block a user