add metadata and covers

This commit is contained in:
oskvr37
2025-01-24 22:32:52 +01:00
parent ba1f9ef1e6
commit f7d35e5faf
2 changed files with 112 additions and 2 deletions
+12 -2
View File
@@ -10,6 +10,7 @@ from ..ctx import Context, passContext
from tiddl.download import downloadTrackStream
from tiddl.models import TrackArg, ARG_TO_QUALITY, Track, PlaylistTrack, Album
from tiddl.utils import formatTrack, trackExists
from tiddl.metadata import addMetadata, Cover
@click.command("download")
@@ -33,7 +34,7 @@ def DownloadCommand(
api = ctx.obj.getApi()
def downloadTrack(track: Track, file_name: str) -> None:
def downloadTrack(track: Track, file_name: str, cover_data=b"") -> None:
if not track.allowStreaming:
click.echo(
f"{click.style('', 'yellow')} Track {click.style(file_name, 'yellow')} does not allow streaming"
@@ -66,12 +67,21 @@ def DownloadCommand(
with full_path.open("wb") as f:
f.write(stream_data)
# TODO: add track credits fetching to fill more metadata
if not cover_data and track.album.cover:
cover_data = Cover(track.album.cover).content
addMetadata(full_path, track, cover_data)
def downloadAlbum(album: Album):
click.echo(f"★ Album {album.title}")
# TODO: fetch all items
album_items = api.getAlbumItems(album.id, limit=100)
cover_data = Cover(album.cover).content if album.cover else b""
for item in album_items.items:
if isinstance(item.item, Track):
track = item.item
@@ -82,7 +92,7 @@ def DownloadCommand(
album_artist=album.artist.name,
)
downloadTrack(track=track, file_name=file_name)
downloadTrack(track=track, file_name=file_name, cover_data=cover_data)
for resource in ctx.obj.resources:
match resource.type:
+100
View File
@@ -0,0 +1,100 @@
import logging
import requests
from pathlib import Path
from mutagen.flac import FLAC as MutagenFLAC, Picture
from mutagen.easymp4 import EasyMP4 as MutagenEasyMP4
from mutagen.mp4 import MP4Cover, MP4 as MutagenMP4
from tiddl.models import Track
logger = logging.getLogger(__name__)
def addMetadata(track_path: Path, track: Track, cover_data=b""):
extension = track_path.suffix
if extension == ".flac":
metadata = MutagenFLAC(track_path)
if cover_data:
picture = Picture()
picture.data = cover_data
picture.mime = "image/jpeg"
metadata.add_picture(picture)
elif extension == ".m4a":
if cover_data:
metadata = MutagenMP4(track_path)
metadata["covr"] = [MP4Cover(cover_data, imageformat=MP4Cover.FORMAT_JPEG)]
metadata.save(track_path)
metadata = MutagenEasyMP4(track_path)
else:
raise ValueError(f"Unknown file extension: {extension}")
new_metadata: dict[str, str] = {
"title": track.title,
"trackNumber": str(track.trackNumber),
"discnumber": str(track.volumeNumber),
"copyright": track.copyright,
"albumartist": track.artist.name if track.artist else "",
"artist": ";".join([artist.name.strip() for artist in track.artists]),
"album": track.album.title,
"date": str(track.streamStartDate) if track.streamStartDate else "",
}
metadata.update(new_metadata)
try:
metadata.save(track_path)
except Exception as e:
logger.error(f"Failed to set metadata for {extension}: {e}")
class Cover:
def __init__(self, uid: str, size=1280) -> None:
if size > 1280:
logger.warning(
f"can not set cover size higher than 1280 (user set: {size})"
)
size = 1280
self.uid = uid
formatted_uid = uid.replace("-", "/")
self.url = (
f"https://resources.tidal.com/images/{formatted_uid}/{size}x{size}.jpg"
)
logger.debug((self.uid, self.url))
self.content = self._get()
def _get(self) -> bytes:
req = requests.get(self.url)
if req.status_code != 200:
logger.error(f"could not download cover. ({req.status_code}) {self.url}")
return b""
logger.debug(f"got cover: {self.uid}")
return req.content
def save(self, directory_path: Path):
if not self.content:
logger.error("cover file content is empty")
return
file = directory_path / "cover.jpg"
if file.exists():
logger.debug(f"cover already exists ({file})")
return
try:
with file.open("wb") as f:
f.write(self.content)
except FileNotFoundError as e:
logger.error(f"could not save cover. {file} -> {e}")