mirror of
https://github.com/oskvr37/tiddl.git
synced 2026-06-13 04:05:08 +03:00
🐛 Fixed video downloading (#235)
* rename `VideoQuality` to `StreamVideoQuality` * remove bad logic from predicting video quality * print info when skipping video * bump to 3.1.1 alpha
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
from pathlib import Path
|
||||
|
||||
from tiddl.core.api.models.base import StreamVideoQuality
|
||||
from tiddl.core.metadata import add_video_metadata
|
||||
from tiddl.core.api.models.base import VideoQuality
|
||||
from tiddl.core.utils import get_video_stream_data
|
||||
from tiddl.core.utils.ffmpeg import convert_to_mp4, is_ffmpeg_installed
|
||||
|
||||
@@ -10,7 +10,7 @@ from .fetch_api import api
|
||||
|
||||
# Old Town Road by Lil Nas X
|
||||
VIDEO_ID = 113483426
|
||||
QUALITY: VideoQuality = "HIGH"
|
||||
QUALITY: StreamVideoQuality = "HIGH"
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("fetching video_stream")
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "tiddl"
|
||||
version = "3.1.0"
|
||||
version = "3.1.1a1"
|
||||
description = "Download Tidal tracks with CLI downloader."
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.13"
|
||||
|
||||
@@ -162,13 +162,8 @@ def download_callback(
|
||||
return TRACK_QUALITY
|
||||
|
||||
elif isinstance(item, Video):
|
||||
if item.quality == "LOW":
|
||||
return "sd"
|
||||
|
||||
if item.quality == "MEDIUM":
|
||||
if VIDEO_QUALITY == "hd":
|
||||
return "hd"
|
||||
return "fhd"
|
||||
# TODO add missing Video.quality literals so this function can work properly
|
||||
return VIDEO_QUALITY
|
||||
|
||||
raise TypeError("Unsupported item type")
|
||||
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
import shutil
|
||||
import asyncio
|
||||
import aiohttp
|
||||
import aiofiles
|
||||
|
||||
import shutil
|
||||
from logging import getLogger
|
||||
|
||||
from pathlib import Path
|
||||
from tempfile import NamedTemporaryFile
|
||||
|
||||
from tiddl.core.api.models import TrackQuality, VideoQuality, Track, Video
|
||||
from tiddl.core.api import TidalAPI, ApiError
|
||||
import aiofiles
|
||||
import aiohttp
|
||||
|
||||
from tiddl.cli.config import VIDEOS_FILTER_LITERAL
|
||||
from tiddl.cli.utils.download import get_existing_track_filename
|
||||
from tiddl.core.api import ApiError, TidalAPI
|
||||
from tiddl.core.api.models import StreamVideoQuality, Track, TrackQuality, Video
|
||||
from tiddl.core.utils import parse_track_stream, parse_video_stream
|
||||
from tiddl.core.utils.ffmpeg import convert_to_mp4, extract_flac
|
||||
from tiddl.core.utils.const import (
|
||||
TRACK_QUALITY_LITERAL,
|
||||
VIDEO_QUALITY_LITERAL,
|
||||
track_qualities,
|
||||
video_qualities,
|
||||
)
|
||||
from tiddl.cli.config import VIDEOS_FILTER_LITERAL
|
||||
from tiddl.cli.utils.download import get_existing_track_filename
|
||||
from tiddl.core.utils.ffmpeg import convert_to_mp4, extract_flac
|
||||
|
||||
from .output import RichOutput
|
||||
|
||||
@@ -34,7 +33,7 @@ track_qualities_color: dict[TrackQuality, str] = {
|
||||
"HI_RES_LOSSLESS": "[yellow]",
|
||||
}
|
||||
|
||||
video_qualities_color: dict[VideoQuality, str] = {
|
||||
video_qualities_color: dict[StreamVideoQuality, str] = {
|
||||
"LOW": "[gray]360p",
|
||||
"MEDIUM": "[cyan]720p",
|
||||
"HIGH": "[yellow]1080p",
|
||||
@@ -46,7 +45,7 @@ class Downloader:
|
||||
rich_output: RichOutput
|
||||
semaphore: asyncio.Semaphore
|
||||
track_quality: TrackQuality
|
||||
video_quality: VideoQuality
|
||||
video_quality: StreamVideoQuality
|
||||
videos_filter: VIDEOS_FILTER_LITERAL
|
||||
skip_existing: bool
|
||||
download_path: Path
|
||||
@@ -121,7 +120,10 @@ class Downloader:
|
||||
elif (isinstance(item, Video) and self.videos_filter == "none") or (
|
||||
isinstance(item, Track) and self.videos_filter == "only"
|
||||
):
|
||||
log.info(f"skipping {item.id} due to {self.videos_filter=}")
|
||||
log.debug(f"skipping {item.id} due to {self.videos_filter=}")
|
||||
self.rich_output.console.print(
|
||||
f"Skipping '{item.title}' due to video filter set to '{self.videos_filter}'"
|
||||
)
|
||||
return None, False
|
||||
|
||||
should_extract_flac = False
|
||||
|
||||
+14
-15
@@ -1,34 +1,33 @@
|
||||
from requests_cache import DO_NOT_CACHE, EXPIRE_IMMEDIATELY
|
||||
|
||||
from typing import Literal, TypeAlias
|
||||
|
||||
from requests_cache import DO_NOT_CACHE, EXPIRE_IMMEDIATELY
|
||||
|
||||
from .client import TidalClient
|
||||
from .models.resources import (
|
||||
Album,
|
||||
Artist,
|
||||
Playlist,
|
||||
Track,
|
||||
Video,
|
||||
TrackQuality,
|
||||
VideoQuality,
|
||||
)
|
||||
from .models.base import (
|
||||
AlbumItems,
|
||||
AlbumItemsCredits,
|
||||
ArtistAlbumsItems,
|
||||
ArtistVideosItems,
|
||||
Favorites,
|
||||
TrackLyrics,
|
||||
PlaylistItems,
|
||||
MixItems,
|
||||
PlaylistItems,
|
||||
Search,
|
||||
SessionResponse,
|
||||
TrackLyrics,
|
||||
TrackStream,
|
||||
VideoStream,
|
||||
)
|
||||
from .models.resources import (
|
||||
Album,
|
||||
Artist,
|
||||
Playlist,
|
||||
StreamVideoQuality,
|
||||
Track,
|
||||
TrackQuality,
|
||||
Video,
|
||||
)
|
||||
from .models.review import AlbumReview
|
||||
|
||||
|
||||
ID: TypeAlias = str | int
|
||||
|
||||
|
||||
@@ -243,7 +242,7 @@ class TidalAPI:
|
||||
expire_after=3600,
|
||||
)
|
||||
|
||||
def get_video_stream(self, video_id: ID, quality: VideoQuality):
|
||||
def get_video_stream(self, video_id: ID, quality: StreamVideoQuality):
|
||||
return self.client.fetch(
|
||||
VideoStream,
|
||||
f"videos/{video_id}/playbackinfopostpaywall",
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
from .resources import Album, Artist, Playlist, Track, Video, TrackQuality, VideoQuality
|
||||
from .base import (
|
||||
AlbumItems,
|
||||
AlbumItemsCredits,
|
||||
ArtistAlbumsItems,
|
||||
Favorites,
|
||||
TrackLyrics,
|
||||
PlaylistItems,
|
||||
MixItems,
|
||||
PlaylistItems,
|
||||
Search,
|
||||
SessionResponse,
|
||||
TrackLyrics,
|
||||
TrackStream,
|
||||
VideoStream,
|
||||
)
|
||||
from .resources import (
|
||||
Album,
|
||||
Artist,
|
||||
Playlist,
|
||||
StreamVideoQuality,
|
||||
Track,
|
||||
TrackQuality,
|
||||
Video,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"Album",
|
||||
@@ -20,7 +28,7 @@ __all__ = [
|
||||
"Track",
|
||||
"Video",
|
||||
"TrackQuality",
|
||||
"VideoQuality",
|
||||
"StreamVideoQuality",
|
||||
"AlbumItems",
|
||||
"AlbumItemsCredits",
|
||||
"ArtistAlbumsItems",
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional, List, Literal, Union
|
||||
from typing import List, Literal, Optional, Union
|
||||
|
||||
from .resources import Album, Artist, Playlist, Track, TrackQuality, Video, VideoQuality
|
||||
from pydantic import BaseModel
|
||||
|
||||
from .resources import (
|
||||
Album,
|
||||
Artist,
|
||||
Playlist,
|
||||
StreamVideoQuality,
|
||||
Track,
|
||||
TrackQuality,
|
||||
Video,
|
||||
)
|
||||
|
||||
|
||||
class SessionResponse(BaseModel):
|
||||
@@ -133,7 +142,7 @@ class VideoStream(BaseModel):
|
||||
videoId: int
|
||||
streamType: Literal["ON_DEMAND"]
|
||||
assetPresentation: Literal["FULL"]
|
||||
videoQuality: VideoQuality
|
||||
videoQuality: StreamVideoQuality
|
||||
# streamingSessionId: str # only in web?
|
||||
manifestMimeType: Literal["application/dash+xml", "application/vnd.tidal.emu"]
|
||||
manifestHash: str
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
from pydantic import BaseModel
|
||||
from datetime import datetime
|
||||
from typing import Optional, List, Literal, Dict, Any
|
||||
from typing import Any, Dict, List, Literal, Optional
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
TrackQuality = Literal["LOW", "HIGH", "LOSSLESS", "HI_RES_LOSSLESS"]
|
||||
|
||||
# audio_only is not stable
|
||||
VideoQuality = Literal["AUDIO_ONLY", "LOW", "MEDIUM", "HIGH"]
|
||||
StreamVideoQuality = Literal["AUDIO_ONLY", "LOW", "MEDIUM", "HIGH"]
|
||||
|
||||
MediaMetadataTags = Literal["LOSSLESS", "HIRES_LOSSLESS", "DOLBY_ATMOS"]
|
||||
|
||||
@@ -83,7 +84,7 @@ class Video(BaseModel):
|
||||
imageId: str
|
||||
vibrantColor: Optional[str] = None
|
||||
duration: int
|
||||
quality: VideoQuality
|
||||
quality: Literal["MP4_1080P"] | str
|
||||
streamReady: bool
|
||||
adSupportedStreamReady: bool
|
||||
djReady: bool
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from typing import Literal
|
||||
|
||||
from tiddl.core.api.models import TrackQuality, VideoQuality
|
||||
|
||||
from tiddl.core.api.models import StreamVideoQuality, TrackQuality
|
||||
|
||||
TRACK_QUALITY_LITERAL = Literal["low", "normal", "high", "max"]
|
||||
VIDEO_QUALITY_LITERAL = Literal["sd", "hd", "fhd"]
|
||||
@@ -13,7 +12,7 @@ track_qualities: dict[TRACK_QUALITY_LITERAL, TrackQuality] = {
|
||||
"max": "HI_RES_LOSSLESS",
|
||||
}
|
||||
|
||||
video_qualities: dict[VIDEO_QUALITY_LITERAL, VideoQuality] = {
|
||||
video_qualities: dict[VIDEO_QUALITY_LITERAL, StreamVideoQuality] = {
|
||||
"sd": "LOW",
|
||||
"hd": "MEDIUM",
|
||||
"fhd": "HIGH",
|
||||
|
||||
Reference in New Issue
Block a user