fix album, artist, and show parsing

This commit is contained in:
zotify 2023-04-08 22:31:29 +12:00
parent dbf05e3b50
commit 8d8d173a78
8 changed files with 48 additions and 64 deletions

View file

@ -1,4 +1,4 @@
# STILL IN DEVELOPMENT, SOME CHANGES AREN'T IMPLEMENTED AND SOME AREN'T FINAL! # STILL IN DEVELOPMENT, EVERYTHING HERE IS SUBJECT TO CHANGE!
## v1.0.0 ## v1.0.0
An unexpected reboot An unexpected reboot
@ -41,6 +41,7 @@ An unexpected reboot
- `{album_artists}` - `{album_artists}`
- !!`{duration}` - In milliseconds - !!`{duration}` - In milliseconds
- `{explicit}` - `{explicit}`
- `{explicit_symbol}` - For output format, will be \[E] if track is explicit.
- `{isrc}` - `{isrc}`
- `{licensor}` - `{licensor}`
- !!`{popularity}` - !!`{popularity}`

View file

@ -1,6 +1,6 @@
[metadata] [metadata]
name = zotify name = zotify
version = 0.9.0 version = 0.9.1
author = Zotify Contributors author = Zotify Contributors
description = A highly customizable music and podcast downloader description = A highly customizable music and podcast downloader
long_description = file: README.md long_description = file: README.md

View file

@ -7,7 +7,7 @@ from zotify.app import client
from zotify.config import CONFIG_PATHS, CONFIG_VALUES from zotify.config import CONFIG_PATHS, CONFIG_VALUES
from zotify.utils import OptionalOrFalse from zotify.utils import OptionalOrFalse
VERSION = "0.9.0" VERSION = "0.9.1"
def main(): def main():

View file

@ -170,7 +170,7 @@ class App:
self.__playable_list.append( self.__playable_list.append(
PlayableData( PlayableData(
PlayableType.TRACK, PlayableType.TRACK,
bytes_to_hex(track.gid), TrackId.from_hex(bytes_to_hex(track.gid)),
self.__config.music_library, self.__config.music_library,
self.__config.output_album, self.__config.output_album,
) )
@ -187,7 +187,7 @@ class App:
self.__playable_list.append( self.__playable_list.append(
PlayableData( PlayableData(
PlayableType.TRACK, PlayableType.TRACK,
bytes_to_hex(track.gid), TrackId.from_hex(bytes_to_hex(track.gid)),
self.__config.music_library, self.__config.music_library,
self.__config.output_album, self.__config.output_album,
) )
@ -215,7 +215,7 @@ class App:
self.__playable_list.append( self.__playable_list.append(
PlayableData( PlayableData(
PlayableType.EPISODE, PlayableType.EPISODE,
bytes_to_hex(episode.gid), EpisodeId.from_hex(bytes_to_hex(episode.gid)),
self.__config.podcast_library, self.__config.podcast_library,
self.__config.output_podcast, self.__config.output_podcast,
) )

View file

@ -138,7 +138,7 @@ CONFIG_VALUES = {
AUDIO_FORMAT: { AUDIO_FORMAT: {
"default": "vorbis", "default": "vorbis",
"type": AudioFormat, "type": AudioFormat,
"choices": [n.value for n in AudioFormat], "choices": [n.value.name for n in AudioFormat],
"arg": "--audio-format", "arg": "--audio-format",
"help": "Audio format of final track output", "help": "Audio format of final track output",
}, },
@ -335,7 +335,7 @@ class Config:
elif config_type == Path: elif config_type == Path:
return Path(value).expanduser() return Path(value).expanduser()
elif config_type == AudioFormat: elif config_type == AudioFormat:
return AudioFormat(value) return AudioFormat[value.upper()]
elif config_type == ImageSize.from_string: elif config_type == ImageSize.from_string:
return ImageSize.from_string(value) return ImageSize.from_string(value)
elif config_type == Quality.from_string: elif config_type == Quality.from_string:

View file

@ -6,7 +6,7 @@ from typing import Any
from music_tag import load_file from music_tag import load_file
from mutagen.oggvorbis import OggVorbisHeaderError from mutagen.oggvorbis import OggVorbisHeaderError
from zotify.utils import AudioFormat, ExtMap from zotify.utils import AudioFormat
# fmt: off # fmt: off
@ -18,18 +18,16 @@ class FFmpegExecutionError(OSError, TranscodingError): ...
class LocalFile: class LocalFile:
audio_format: AudioFormat
def __init__( def __init__(
self, self,
path: Path, path: Path,
audio_format: AudioFormat | None = None, audio_format: AudioFormat | None = None,
bitrate: int | None = None, bitrate: int | None = None,
): ):
self.path = path self.__path = path
self.bitrate = bitrate self.__bitrate = bitrate
if audio_format: if audio_format:
self.audio_format = audio_format self.__audio_format = audio_format
def transcode( def transcode(
self, self,
@ -48,10 +46,10 @@ class LocalFile:
ffmpeg: Location of FFmpeg binary ffmpeg: Location of FFmpeg binary
opt_args: Additional arguments to pass to ffmpeg opt_args: Additional arguments to pass to ffmpeg
""" """
if audio_format: if audio_format is not None:
new_ext = ExtMap[audio_format.value] new_ext = audio_format.value.ext
else: else:
new_ext = ExtMap[self.audio_format.value] new_ext = self.__audio_format.value.ext
cmd = [ cmd = [
ffmpeg, ffmpeg,
"-y", "-y",
@ -59,18 +57,18 @@ class LocalFile:
"-loglevel", "-loglevel",
"error", "error",
"-i", "-i",
str(self.path), str(self.__path),
] ]
newpath = self.path.parent.joinpath( newpath = self.__path.parent.joinpath(
self.path.name.rsplit(".", 1)[0] + new_ext.value self.__path.name.rsplit(".", 1)[0] + new_ext
) )
if self.path == newpath: if self.__path == newpath:
raise TargetExistsError( raise TargetExistsError(
f"Transcoding Error: Cannot overwrite source, target file is already a {self.audio_format} file." f"Transcoding Error: Cannot overwrite source, target file is already a {self.__audio_format} file."
) )
cmd.extend(["-b:a", str(bitrate) + "k"]) if bitrate else None cmd.extend(["-b:a", str(bitrate) + "k"]) if bitrate else None
cmd.extend(["-c:a", audio_format.value]) if audio_format else None cmd.extend(["-c:a", audio_format.value.name]) if audio_format else None
cmd.extend(opt_args) cmd.extend(opt_args)
cmd.append(str(newpath)) cmd.append(str(newpath))
@ -88,11 +86,11 @@ class LocalFile:
) )
if replace: if replace:
Path(self.path).unlink() self.__path.unlink()
self.path = newpath self.__path = newpath
self.bitrate = bitrate self.__bitrate = bitrate
if audio_format: if audio_format:
self.audio_format = audio_format self.__audio_format = audio_format
def write_metadata(self, metadata: dict[str, Any]) -> None: def write_metadata(self, metadata: dict[str, Any]) -> None:
""" """
@ -100,7 +98,7 @@ class LocalFile:
Args: Args:
metadata: key-value metadata dictionary metadata: key-value metadata dictionary
""" """
f = load_file(self.path) f = load_file(self.__path)
f.save() f.save()
for k, v in metadata.items(): for k, v in metadata.items():
try: try:
@ -118,7 +116,7 @@ class LocalFile:
Args: Args:
image: raw image data image: raw image data
""" """
f = load_file(self.path) f = load_file(self.__path)
f["artwork"] = image f["artwork"] = image
try: try:
f.save() f.save()

View file

@ -3,7 +3,6 @@ from pathlib import Path
from typing import Any from typing import Any
from librespot.core import PlayableContentFeeder from librespot.core import PlayableContentFeeder
from librespot.metadata import AlbumId
from librespot.util import bytes_to_hex from librespot.util import bytes_to_hex
from librespot.structure import GeneralAudioStream from librespot.structure import GeneralAudioStream
from requests import get from requests import get
@ -132,12 +131,6 @@ class Track(PlayableContentFeeder.LoadedStream, Playable):
track.metrics, track.metrics,
) )
self.__api = api self.__api = api
try:
isinstance(self.track.album.genre, str)
except AttributeError:
self.album = self.__api.get_metadata_4_album(
AlbumId.from_hex(bytes_to_hex(self.track.album.gid))
)
self.cover_images = self.album.cover_group.image self.cover_images = self.album.cover_group.image
self.metadata = self.__default_metadata() self.metadata = self.__default_metadata()
@ -155,22 +148,19 @@ class Track(PlayableContentFeeder.LoadedStream, Playable):
"artist": self.artist[0].name, "artist": self.artist[0].name,
"artists": "\0".join([a.name for a in self.artist]), "artists": "\0".join([a.name for a in self.artist]),
"date": f"{date.year}-{date.month}-{date.day}", "date": f"{date.year}-{date.month}-{date.day}",
"release_date": f"{date.year}-{date.month}-{date.day}",
"disc_number": self.disc_number, "disc_number": self.disc_number,
"duration": self.duration, "duration": self.duration,
"explicit": self.explicit, "explicit": self.explicit,
"genre": self.album.genre, "explicit_symbol": "[E]" if self.explicit else "",
"isrc": self.external_id[0].id, "isrc": self.external_id[0].id,
"licensor": self.licensor, "popularity": (self.popularity * 255) / 100,
"popularity": self.popularity, "track_number": str(self.number).zfill(2),
"track_number": self.number, # "year": self.album.date.year,
"title": self.name,
"replaygain_track_gain": self.normalization_data.track_gain_db, "replaygain_track_gain": self.normalization_data.track_gain_db,
"replaygain_track_peak": self.normalization_data.track_peak, "replaygain_track_peak": self.normalization_data.track_peak,
"replaygain_album_gain": self.normalization_data.album_gain_db, "replaygain_album_gain": self.normalization_data.album_gain_db,
"replaygain_album_prak": self.normalization_data.album_peak, "replaygain_album_peak": self.normalization_data.album_peak,
"title": self.name,
"track_title": self.name,
# "year": self.album.date.year,
} }
def get_lyrics(self) -> Lyrics: def get_lyrics(self) -> Lyrics:

View file

@ -2,6 +2,7 @@ from argparse import Action, ArgumentError
from enum import Enum, IntEnum from enum import Enum, IntEnum
from re import IGNORECASE, sub from re import IGNORECASE, sub
from sys import platform as PLATFORM from sys import platform as PLATFORM
from typing import NamedTuple
from librespot.audio.decoders import AudioQuality from librespot.audio.decoders import AudioQuality
from librespot.util import Base62, bytes_to_hex from librespot.util import Base62, bytes_to_hex
@ -13,26 +14,20 @@ LYRICS_URL = "https://sp" + "client.wg.sp" + "otify.com/color-lyrics/v2/track/"
BASE62 = Base62.create_instance_with_inverted_character_set() BASE62 = Base62.create_instance_with_inverted_character_set()
class AudioCodec(NamedTuple):
ext: str
name: str
class AudioFormat(Enum): class AudioFormat(Enum):
AAC = "aac" AAC = AudioCodec("aac", "m4a")
FDK_AAC = "fdk_aac" FDK_AAC = AudioCodec("fdk_aac", "m4a")
FLAC = "flac" FLAC = AudioCodec("flac", "flac")
MP3 = "mp3" MP3 = AudioCodec("mp3", "mp3")
OPUS = "opus" OPUS = AudioCodec("opus", "ogg")
VORBIS = "vorbis" VORBIS = AudioCodec("vorbis", "ogg")
WAV = "wav" WAV = AudioCodec("wav", "wav")
WV = "wavpack" WV = AudioCodec("wavpack", "wv")
class ExtMap(Enum):
AAC = "m4a"
FDK_AAC = "m4a"
FLAC = "flac"
MP3 = "mp3"
OPUS = "ogg"
VORBIS = "ogg"
WAV = "wav"
WAVPACK = "wv"
class Quality(Enum): class Quality(Enum):