variables as mixins for docs

This commit is contained in:
jbannon 2022-04-24 00:30:53 +00:00
parent 53b1923653
commit 5eeb117fca
22 changed files with 547 additions and 288 deletions

View file

@ -57,3 +57,5 @@ html_static_path = ["_static"]
# Do not show full module path in api docs
add_module_names = False
python_use_unqualified_type_names = True
napoleon_numpy_docstrings = True
napoleon_use_rtype = False

View file

@ -0,0 +1,53 @@
ytdl\_subscribe.config package
==============================
Submodules
----------
ytdl\_subscribe.config.config\_file module
------------------------------------------
.. automodule:: ytdl_subscribe.config.config_file
:members:
:undoc-members:
:show-inheritance:
ytdl\_subscribe.config.preset module
------------------------------------
.. automodule:: ytdl_subscribe.config.preset
:members:
:undoc-members:
:show-inheritance:
ytdl\_subscribe.config.preset\_class\_mappings module
-----------------------------------------------------
.. automodule:: ytdl_subscribe.config.preset_class_mappings
:members:
:undoc-members:
:show-inheritance:
ytdl\_subscribe.config.preset\_options module
---------------------------------------------
.. automodule:: ytdl_subscribe.config.preset_options
:members:
:undoc-members:
:show-inheritance:
ytdl\_subscribe.config.subscription module
------------------------------------------
.. automodule:: ytdl_subscribe.config.subscription
:members:
:undoc-members:
:show-inheritance:
Module contents
---------------
.. automodule:: ytdl_subscribe.config
:members:
:undoc-members:
:show-inheritance:

View file

@ -1,9 +1,25 @@
ytdl\_subscribe.entries package
===============================
Subpackages
-----------
.. toctree::
:maxdepth: 4
ytdl_subscribe.entries.variables
Submodules
----------
ytdl\_subscribe.entries.base\_entry module
------------------------------------------
.. automodule:: ytdl_subscribe.entries.base_entry
:members:
:undoc-members:
:show-inheritance:
ytdl\_subscribe.entries.entry module
------------------------------------

View file

@ -0,0 +1,37 @@
ytdl\_subscribe.entries.variables package
=========================================
Submodules
----------
ytdl\_subscribe.entries.variables.entry\_variables module
---------------------------------------------------------
.. automodule:: ytdl_subscribe.entries.variables.entry_variables
:members:
:undoc-members:
:show-inheritance:
ytdl\_subscribe.entries.variables.soundcloud\_variables module
--------------------------------------------------------------
.. automodule:: ytdl_subscribe.entries.variables.soundcloud_variables
:members:
:undoc-members:
:show-inheritance:
ytdl\_subscribe.entries.variables.youtube\_variables module
-----------------------------------------------------------
.. automodule:: ytdl_subscribe.entries.variables.youtube_variables
:members:
:undoc-members:
:show-inheritance:
Module contents
---------------
.. automodule:: ytdl_subscribe.entries.variables
:members:
:undoc-members:
:show-inheritance:

View file

@ -0,0 +1,53 @@
ytdl\_subscribe.plugins package
===============================
Submodules
----------
ytdl\_subscribe.plugins.convert\_thumbnail module
-------------------------------------------------
.. automodule:: ytdl_subscribe.plugins.convert_thumbnail
:members:
:undoc-members:
:show-inheritance:
ytdl\_subscribe.plugins.music\_tags module
------------------------------------------
.. automodule:: ytdl_subscribe.plugins.music_tags
:members:
:undoc-members:
:show-inheritance:
ytdl\_subscribe.plugins.nfo\_tags module
----------------------------------------
.. automodule:: ytdl_subscribe.plugins.nfo_tags
:members:
:undoc-members:
:show-inheritance:
ytdl\_subscribe.plugins.output\_directory\_nfo\_tags module
-----------------------------------------------------------
.. automodule:: ytdl_subscribe.plugins.output_directory_nfo_tags
:members:
:undoc-members:
:show-inheritance:
ytdl\_subscribe.plugins.plugin module
-------------------------------------
.. automodule:: ytdl_subscribe.plugins.plugin
:members:
:undoc-members:
:show-inheritance:
Module contents
---------------
.. automodule:: ytdl_subscribe.plugins
:members:
:undoc-members:
:show-inheritance:

View file

@ -8,9 +8,12 @@ Subpackages
:maxdepth: 4
ytdl_subscribe.cli
ytdl_subscribe.config
ytdl_subscribe.downloaders
ytdl_subscribe.entries
ytdl_subscribe.plugins
ytdl_subscribe.subscriptions
ytdl_subscribe.utils
ytdl_subscribe.validators
ytdl_subscribe.ytdl_additions

View file

@ -4,14 +4,6 @@ ytdl\_subscribe.subscriptions package
Submodules
----------
ytdl\_subscribe.subscriptions.soundcloud module
-----------------------------------------------
.. automodule:: ytdl_subscribe.subscriptions.soundcloud
:members:
:undoc-members:
:show-inheritance:
ytdl\_subscribe.subscriptions.subscription module
-------------------------------------------------
@ -20,14 +12,6 @@ ytdl\_subscribe.subscriptions.subscription module
:undoc-members:
:show-inheritance:
ytdl\_subscribe.subscriptions.youtube module
--------------------------------------------
.. automodule:: ytdl_subscribe.subscriptions.youtube
:members:
:undoc-members:
:show-inheritance:
Module contents
---------------

View file

@ -0,0 +1,21 @@
ytdl\_subscribe.utils package
=============================
Submodules
----------
ytdl\_subscribe.utils.exceptions module
---------------------------------------
.. automodule:: ytdl_subscribe.utils.exceptions
:members:
:undoc-members:
:show-inheritance:
Module contents
---------------
.. automodule:: ytdl_subscribe.utils
:members:
:undoc-members:
:show-inheritance:

View file

@ -1,22 +1,53 @@
ytdl\_subscribe.validators package
==================================
Subpackages
-----------
.. toctree::
:maxdepth: 4
ytdl_subscribe.validators.base
ytdl_subscribe.validators.config
Submodules
----------
ytdl\_subscribe.validators.exceptions module
ytdl\_subscribe.validators.date\_range\_validator module
--------------------------------------------------------
.. automodule:: ytdl_subscribe.validators.date_range_validator
:members:
:undoc-members:
:show-inheritance:
ytdl\_subscribe.validators.strict\_dict\_validator module
---------------------------------------------------------
.. automodule:: ytdl_subscribe.validators.strict_dict_validator
:members:
:undoc-members:
:show-inheritance:
ytdl\_subscribe.validators.string\_datetime module
--------------------------------------------------
.. automodule:: ytdl_subscribe.validators.string_datetime
:members:
:undoc-members:
:show-inheritance:
ytdl\_subscribe.validators.string\_formatter\_validators module
---------------------------------------------------------------
.. automodule:: ytdl_subscribe.validators.string_formatter_validators
:members:
:undoc-members:
:show-inheritance:
ytdl\_subscribe.validators.string\_select\_validator module
-----------------------------------------------------------
.. automodule:: ytdl_subscribe.validators.string_select_validator
:members:
:undoc-members:
:show-inheritance:
ytdl\_subscribe.validators.validators module
--------------------------------------------
.. automodule:: ytdl_subscribe.validators.exceptions
.. automodule:: ytdl_subscribe.validators.validators
:members:
:undoc-members:
:show-inheritance:

View file

@ -75,6 +75,7 @@ def mock_entry_to_dict(
uid,
title,
ext,
extractor,
upload_date,
upload_year,
thumbnail_ext,
@ -87,6 +88,7 @@ def mock_entry_to_dict(
"title": title,
"sanitized_title": title,
"ext": ext,
"extractor": extractor,
"upload_date": upload_date,
"upload_date_standardized": f"{upload_year}-{_pad(upload_month)}-{_pad(upload_day)}",
"upload_year": upload_year,
@ -134,15 +136,11 @@ def validate_entry_properties(
def _validate_entry_properties(entry: Entry):
assert entry.uid == uid
assert entry.title == title
# Title does not require sanitizing, so should be the same
assert entry.sanitized_title == title
assert entry.upload_date == upload_date
assert entry.upload_year == upload_year
assert entry.ext == ext
assert entry.thumbnail_ext == thumbnail_ext
assert entry.download_file_name == download_file_name
assert entry.download_thumbnail_name == download_thumbnail_name
assert entry.playlist_metadata is None
assert entry.extractor == extractor
return True

View file

@ -40,7 +40,6 @@ def mock_soundcloud_track_to_dict(
"album": title,
"sanitized_album": title,
"album_year": upload_year,
"is_premiere": is_premiere,
}
)
@ -71,7 +70,8 @@ def validate_soundcloud_track_properties(
assert soundcloud_track.album == title
assert soundcloud_track.sanitized_album == title
assert soundcloud_track.album_year == upload_year
assert soundcloud_track.is_premiere == is_premiere
assert soundcloud_track.is_premiere() == is_premiere
return True

View file

@ -0,0 +1,53 @@
from abc import ABC
from dataclasses import dataclass
from typing import Any
from typing import Dict
from typing import Optional
@dataclass
class PlaylistMetadata:
"""
Metadata for storing playlist information.
"""
playlist_index: int
playlist_id: str
playlist_extractor: str
class BaseEntry(ABC):
"""
Abstract entry object to represent anything download from ytdl (playlist metadata, media, etc).
"""
def __init__(self, entry_dict: Dict, working_directory: Optional[str] = None):
"""
Initialize the entry using ytdl metadata
Parameters
----------
entry_dict
Entry metadata
working_directory
Optional. Directory that the entry is downloaded to
"""
self._working_directory = working_directory
self._kwargs = entry_dict
def kwargs_contains(self, key: str) -> bool:
"""Returns whether internal kwargs contains the specified key"""
return key in self._kwargs
def kwargs(self, key) -> Any:
"""Returns an internal kwarg value supplied from ytdl"""
if not self.kwargs_contains(key):
raise KeyError(f"Expected '{key}' in {self.__class__.__name__} but does not exist.")
return self._kwargs[key]
def working_directory(self) -> str:
if self._working_directory is None:
raise ValueError(
"Entry working directory is not set when trying to access its download file path"
)
return self._working_directory

View file

@ -1,193 +1,29 @@
from abc import ABC
from dataclasses import dataclass
from pathlib import Path
from typing import Any
from typing import Dict
from typing import Optional
from typing import final
from yt_dlp.utils import sanitize_filename
from ytdl_subscribe.entries.base_entry import BaseEntry
from ytdl_subscribe.entries.variables.entry_variables import EntryVariables
@dataclass
class PlaylistMetadata:
"""
Metadata for storing playlist information.
"""
playlist_index: int
playlist_id: str
playlist_extractor: str
class BaseEntry(ABC):
"""
Abstract entry object to represent anything download from ytdl (playlist metadata, media, etc).
"""
def __init__(self, entry_dict: Dict, working_directory: Optional[str] = None):
"""
Initialize the entry using ytdl metadata
Parameters
----------
entry_dict
Entry metadata
working_directory
Optional. Directory that the entry is downloaded to
"""
self._working_directory = working_directory
self._kwargs = entry_dict
def kwargs_contains(self, key: str) -> bool:
"""Returns whether internal kwargs contains the specified key"""
return key in self._kwargs
def kwargs(self, key) -> Any:
"""Returns an internal kwarg value supplied from ytdl"""
if not self.kwargs_contains(key):
raise KeyError(f"Expected '{key}' in {self.__class__.__name__} but does not exist.")
return self._kwargs[key]
@property
def working_directory(self) -> str:
if self._working_directory is None:
raise ValueError(
"Entry working directory is not set when trying to access its download file path"
)
return self._working_directory
@property
def uid(self) -> str:
"""Returns the entry's unique id"""
return self.kwargs("id")
@property
def extractor(self) -> str:
"""
:return: The ytdl extrator name
"""
return self.kwargs("extractor")
@property
def playlist_metadata(self) -> Optional[PlaylistMetadata]:
"""
Reserved for any child entry class that resides in a playlist.
:return: Playlist metadata for this entry
"""
return None
def to_dict(self) -> Dict[str, str]:
"""Returns the entry's values as a dictionary"""
return {
"uid": self.uid,
}
class Entry(BaseEntry):
class Entry(EntryVariables, BaseEntry):
"""
Entry object to represent a single media object returned from yt-dlp.
"""
@property
def title(self) -> str:
"""Returns the entry's title"""
return self.kwargs("title")
@property
def sanitized_title(self) -> str:
"""Returns the entry's sanitized title"""
return sanitize_filename(self.title)
@property
def ext(self) -> str:
"""Returns the entry's file extension"""
return self.kwargs("ext")
@property
def upload_date(self) -> str:
"""Returns the entry's upload date"""
return self.kwargs("upload_date")
@property
def upload_year(self) -> int:
"""Returns the entry's upload year"""
return int(self.upload_date[:4])
@property
def upload_month_padded(self) -> str:
"""Returns the entry's upload month, padded"""
return self.upload_date[4:6]
@property
def upload_day_padded(self) -> str:
"""Returns the entry's upload day, padded"""
return self.upload_date[6:8]
@property
def upload_month(self) -> int:
"""Returns the entry's upload month as an int"""
return int(self.upload_month_padded.lstrip("0"))
@property
def upload_day(self) -> int:
"""Returns the entry's upload month as an int"""
return int(self.upload_day_padded.lstrip("0"))
@property
def upload_date_standardized(self) -> str:
"""
:return: upload date as YYYY-MM-DD
"""
return f"{self.upload_year}-{self.upload_month_padded}-{self.upload_day_padded}"
@property
def description(self) -> str:
return self.kwargs("description")
@property
def download_file_name(self) -> str:
"""Returns the entry's file name when downloaded locally"""
return f"{self.uid}.{self.ext}"
@property
def download_file_path(self) -> str:
def get_download_file_path(self) -> str:
"""Returns the entry's file path to where it was downloaded"""
return str(Path(self.working_directory) / self.download_file_name)
return str(Path(self.working_directory()) / f"{self.uid}.{self.ext}")
@property
def thumbnail_ext(self) -> str:
"""
:return: The entry's thumbnail extension
"""
return self.kwargs("thumbnail").split(".")[-1]
@property
def download_thumbnail_name(self) -> str:
"""Returns the thumbnail's file name when downloaded locally"""
return f"{self.uid}.{self.thumbnail_ext}"
@property
def download_thumbnail_path(self) -> str:
def get_download_thumbnail_path(self) -> str:
"""Returns the entry's thumbnail's file path to where it was downloaded"""
return str(Path(self.working_directory) / self.download_thumbnail_name)
return str(Path(self.working_directory()) / f"{self.uid}.{self.thumbnail_ext}")
def to_dict(self) -> Dict:
"""Returns the entry's values as a dictionary"""
return dict(
super().to_dict(),
**{
"title": self.title,
"sanitized_title": self.sanitized_title,
"description": self.description,
"ext": self.ext,
"thumbnail_ext": self.thumbnail_ext,
"upload_date": self.upload_date,
"upload_date_standardized": self.upload_date_standardized,
"upload_year": self.upload_year,
"upload_month": self.upload_month,
"upload_month_padded": self.upload_month_padded,
"upload_day": self.upload_day,
"upload_day_padded": self.upload_day_padded,
},
)
@final
def to_dict(self) -> Dict[str, str]:
"""
Returns
-------
The variables in dictionary format
"""
return self._to_dict()

View file

@ -1,45 +1,17 @@
from typing import Dict
from typing import List
from typing import Optional
from yt_dlp.utils import sanitize_filename
from ytdl_subscribe.entries.base_entry import PlaylistMetadata
from ytdl_subscribe.entries.entry import Entry
from ytdl_subscribe.entries.entry import PlaylistMetadata
from ytdl_subscribe.entries.variables.soundcloud_variables import SoundcloudVariables
class SoundcloudTrack(Entry):
class SoundcloudTrack(SoundcloudVariables, Entry):
"""
Entry object to represent a Soundcloud track yt-dlp that is a single, which implies
it does not belong to an album.
"""
@property
def track_number(self) -> int:
"""Returns the entry's track number. Since this is a single, it will always be 1"""
return 1
@property
def track_number_padded(self) -> str:
"""Returns the entry's padded track number, to the tens-place"""
return f"{self.track_number:02d}"
@property
def album(self) -> str:
"""Returns the entry's album name. Since this is a single, set the album to the title"""
return self.title
@property
def sanitized_album(self) -> str:
"""Returns the entry's sanitized album name"""
return sanitize_filename(self.album)
@property
def album_year(self) -> int:
"""Returns the entry's album year. Since this is a single, use the upload year"""
return self.upload_year
@property
def is_premiere(self) -> bool:
"""
Returns whether the entry is a premier track. Check this by seeing if the track's url is
@ -47,20 +19,6 @@ class SoundcloudTrack(Entry):
"""
return "/preview/" in self.kwargs("url")
def to_dict(self) -> Dict:
"""Returns the entry's values as a dictionary."""
return dict(
super().to_dict(),
**{
"track_number": self.track_number,
"track_number_padded": self.track_number_padded,
"album": self.album,
"sanitized_album": self.sanitized_album,
"album_year": self.album_year,
"is_premiere": self.is_premiere,
},
)
class SoundcloudAlbumTrack(SoundcloudTrack):
"""
@ -83,10 +41,6 @@ class SoundcloudAlbumTrack(SoundcloudTrack):
self._album_year = album_year
self._playlist_metadata = playlist_metadata
@property
def playlist_metadata(self) -> Optional[PlaylistMetadata]:
return self._playlist_metadata
@property
def track_number(self) -> int:
"""Returns the entry's track number"""
@ -112,7 +66,7 @@ class SoundcloudAlbumTrack(SoundcloudTrack):
) -> "SoundcloudAlbumTrack":
return SoundcloudAlbumTrack(
entry_dict=soundcloud_track._kwargs, # pylint: disable=protected-access
working_directory=soundcloud_track.working_directory,
working_directory=soundcloud_track.working_directory(),
album=album,
album_year=album_year,
playlist_metadata=playlist_metadata,
@ -143,7 +97,7 @@ class SoundcloudAlbum(Entry):
tracks = [
track
for track in self._single_tracks
if not (skip_premiere_tracks and track.is_premiere)
if not (skip_premiere_tracks and track.is_premiere())
]
album_tracks = [

View file

@ -0,0 +1,156 @@
from typing import Dict
from typing import final
from yt_dlp.utils import sanitize_filename
from ytdl_subscribe.entries.base_entry import BaseEntry
# This file contains mixins to a BaseEntry subclass. Ignore pylint's "no kwargs member" suggestion
# pylint: disable=no-member
class BaseEntryVariables:
"""
Abstract entry object to represent usable variables for formatting presets and subscriptions
"""
@property
def uid(self: BaseEntry) -> str:
"""
Returns
-------
The entry's unique ID
"""
return self.kwargs("id")
@property
def extractor(self: BaseEntry) -> str:
"""
Returns
-------
The ytdl extractor name
"""
return self.kwargs("extractor")
@final
def _to_dict(self) -> Dict[str, str]:
"""
Returns
-------
Dictionary containing all variables
"""
cls = self.__class__
property_names = [prop for prop in dir(cls) if isinstance(getattr(cls, prop), property)]
return {property_name: getattr(self, property_name) for property_name in property_names}
class EntryVariables(BaseEntryVariables):
@property
def title(self: BaseEntry) -> str:
"""
Returns
-------
The title of the entry
"""
return self.kwargs("title")
@property
def sanitized_title(self) -> str:
"""
Returns
-------
The sanitized title of the entry, which is safe to use for Unix and Windows file names.
"""
return sanitize_filename(self.title)
@property
def ext(self: BaseEntry) -> str:
"""
Returns
-------
The downloaded entry's file extension
"""
return self.kwargs("ext")
@property
def thumbnail_ext(self: BaseEntry) -> str:
"""
Returns
-------
The download entry's thumbnail extension
"""
# TODO: Always return jpg
return self.kwargs("thumbnail").split(".")[-1]
@property
def upload_date(self: BaseEntry) -> str:
"""
Returns
-------
The entry's uploaded date, in YYYYMMDD format.
"""
return self.kwargs("upload_date")
@property
def upload_year(self) -> int:
"""
Returns
-------
The entry's upload year
"""
return int(self.upload_date[:4])
@property
def upload_month_padded(self) -> str:
"""
Returns
-------
The entry's upload month padded to two digits, i.e. March returns "03"
"""
return self.upload_date[4:6]
@property
def upload_day_padded(self) -> str:
"""
Returns
-------
The entry's upload day padded to two digits, i.e. the fifth returns "05"
"""
return self.upload_date[6:8]
@property
def upload_month(self) -> int:
"""
Returns
-------
The upload month as an integer (no padding).
"""
return int(self.upload_month_padded.lstrip("0"))
@property
def upload_day(self) -> int:
"""
Returns
-------
The upload day as an integer (no padding).
"""
return int(self.upload_day_padded.lstrip("0"))
@property
def upload_date_standardized(self) -> str:
"""
Returns
-------
The uploaded date formatted as YYYY-MM-DD
"""
return f"{self.upload_year}-{self.upload_month_padded}-{self.upload_day_padded}"
@property
def description(self: BaseEntry) -> str:
"""
Returns
-------
The description of the entry.
"""
return self.kwargs("description")

View file

@ -0,0 +1,54 @@
from yt_dlp.utils import sanitize_filename
from ytdl_subscribe.entries.variables.entry_variables import EntryVariables
# This file contains mixins to a BaseEntry subclass. Ignore pylint's "no kwargs member" suggestion
# pylint: disable=no-member
class SoundcloudVariables(EntryVariables):
@property
def track_number(self) -> int:
"""
Returns
-------
The entry's track number within an album. For singles, it will always be 1.
"""
return 1
@property
def track_number_padded(self) -> str:
"""
Returns
-------
The entry's track number, padded two digits.
"""
return f"{self.track_number:02d}"
@property
def album(self) -> str:
"""
Returns
-------
The entry's album name. For singles, it will be the same as the title.
"""
return self.title
@property
def sanitized_album(self) -> str:
"""
Returns
-------
The entry's sanitized album name, which is safe to use for Unix and Windows file names.
"""
return sanitize_filename(self.album)
@property
def album_year(self) -> int:
"""
Returns
-------
The entry's album year, which is determined by the latest year amongst all tracks in the
album.
"""
return self.upload_year

View file

@ -0,0 +1,20 @@
from ytdl_subscribe.entries.base_entry import BaseEntry
from ytdl_subscribe.entries.variables.entry_variables import EntryVariables
# This file contains mixins to a BaseEntry subclass. Ignore pylint's "no kwargs member" suggestion
# pylint: disable=no-member
class YoutubeVideoVariables(EntryVariables):
@property
def track_title(self: BaseEntry) -> str:
"""
Returns
-------
The track title of a music video if it is available, otherwise it falls back to the title.
"""
# Try to get the track, fall back on title
if self.kwargs_contains("track"):
return self.kwargs("track")
return super().title

View file

@ -2,27 +2,15 @@ import os.path
from pathlib import Path
from ytdl_subscribe.entries.entry import Entry
from ytdl_subscribe.entries.variables.youtube_variables import YoutubeVideoVariables
class YoutubeVideo(Entry):
class YoutubeVideo(YoutubeVideoVariables, Entry):
"""
Entry object to represent a Youtube video.
"""
@property
def title(self) -> str:
"""
Returns the title of the youtube video. Tries to get the track name if it is available,
otherwise it falls back to the title.
"""
# Try to get the track, fall back on title
if self.kwargs_contains("track"):
return self.kwargs("track")
return super().title
@property
def download_thumbnail_path(self) -> str:
def get_download_thumbnail_path(self) -> str:
"""
Returns
-------
@ -30,7 +18,7 @@ class YoutubeVideo(Entry):
thumbnail entry is not the actual thumbnail it downloaded. So check all the possible
extensions that it may have downloaded, and see if that thumbnail's extension exists.
TODO: move this into the init so the thumbnail_ext variable can be set accordingly
TODO: always make thumbnails jpg
"""
thumbnails = self.kwargs("thumbnails")
possible_thumbnail_exts = set()
@ -38,8 +26,8 @@ class YoutubeVideo(Entry):
possible_thumbnail_exts.add(thumbnail["url"].split(".")[-1])
for ext in possible_thumbnail_exts:
possible_thumbnail_path = str(Path(self.working_directory) / f"{self.uid}.{ext}")
possible_thumbnail_path = str(Path(self.working_directory()) / f"{self.uid}.{ext}")
if os.path.isfile(possible_thumbnail_path):
return possible_thumbnail_path
return super().download_thumbnail_path
return super().get_download_thumbnail_path()

View file

@ -31,14 +31,14 @@ class ConvertThumbnailPlugin(Plugin[ConvertThumbnailOptions]):
Convert the source thumbnail to the desired type. Leave the original file name and
extension intact to let output_options deal with renaming it.
"""
if not os.path.isfile(entry.download_thumbnail_path):
if not os.path.isfile(entry.get_download_thumbnail_path()):
raise ValueError("Thumbnail not found")
image: Image = pil_open(entry.download_thumbnail_path).convert("RGB")
image: Image = pil_open(entry.get_download_thumbnail_path()).convert("RGB")
# Pillow likes the formal 'jpeg' name and not 'jpg'
thumbnail_format = self.plugin_options.convert_to.value
if thumbnail_format == "jpg":
thumbnail_format = "jpeg"
image.save(fp=entry.download_thumbnail_path, format=thumbnail_format)
image.save(fp=entry.get_download_thumbnail_path(), format=thumbnail_format)

View file

@ -28,7 +28,7 @@ class MusicTagsPlugin(Plugin[MusicTagsOptions]):
"""
Tags the entry's audio file using values defined in the metadata options
"""
audio_file = music_tag.load_file(entry.download_file_path)
audio_file = music_tag.load_file(entry.get_download_file_path())
for tag, tag_formatter in self.plugin_options.tags.dict.items():
audio_file[tag] = self.overrides.apply_formatter(formatter=tag_formatter, entry=entry)
audio_file.save()

View file

@ -108,7 +108,7 @@ class Subscription:
)
self._enhanced_download_archive.mapping.add_entry(entry, output_file_name)
self._copy_file_to_output_directory(
source_file_path=entry.download_file_path, output_file_name=output_file_name
source_file_path=entry.get_download_file_path(), output_file_name=output_file_name
)
if self.output_options.thumbnail_name:
@ -117,7 +117,7 @@ class Subscription:
)
self._enhanced_download_archive.mapping.add_entry(entry, output_thumbnail_name)
self._copy_file_to_output_directory(
source_file_path=entry.download_thumbnail_path,
source_file_path=entry.get_download_thumbnail_path(),
output_file_name=output_thumbnail_name,
)