tests passing
This commit is contained in:
parent
3098a96f31
commit
4d64d488a7
7 changed files with 48 additions and 31 deletions
|
|
@ -92,6 +92,7 @@ class YoutubePlaylistDownloader(
|
||||||
# Re-download the contents even if it's a dry-run as a single video. At this time,
|
# Re-download the contents even if it's a dry-run as a single video. At this time,
|
||||||
# playlists do not download subtitles or subtitle metadata
|
# playlists do not download subtitles or subtitle metadata
|
||||||
as_single_video_dict = self.extract_info_with_retry(
|
as_single_video_dict = self.extract_info_with_retry(
|
||||||
|
is_downloaded_fn=None if self.is_dry_run else video.is_downloaded,
|
||||||
ytdl_options_overrides={"writeinfojson": False, "skip_download": self.is_dry_run},
|
ytdl_options_overrides={"writeinfojson": False, "skip_download": self.is_dry_run},
|
||||||
url=video.kwargs("webpage_url"),
|
url=video.kwargs("webpage_url"),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ from typing import final
|
||||||
|
|
||||||
from ytdl_sub.entries.base_entry import BaseEntry
|
from ytdl_sub.entries.base_entry import BaseEntry
|
||||||
from ytdl_sub.entries.variables.entry_variables import EntryVariables
|
from ytdl_sub.entries.variables.entry_variables import EntryVariables
|
||||||
|
from ytdl_sub.validators.audo_codec_validator import AUDIO_CODEC_EXTS
|
||||||
|
|
||||||
|
|
||||||
class Entry(EntryVariables, BaseEntry):
|
class Entry(EntryVariables, BaseEntry):
|
||||||
|
|
@ -65,13 +66,17 @@ class Entry(EntryVariables, BaseEntry):
|
||||||
-------
|
-------
|
||||||
True if the file and thumbnail exist locally. False otherwise.
|
True if the file and thumbnail exist locally. False otherwise.
|
||||||
"""
|
"""
|
||||||
thumbnail_exists = (
|
|
||||||
os.path.isfile(self.get_download_thumbnail_path())
|
|
||||||
or self.get_ytdlp_download_thumbnail_path() is not None
|
|
||||||
)
|
|
||||||
file_exists = os.path.isfile(self.get_download_file_path())
|
file_exists = os.path.isfile(self.get_download_file_path())
|
||||||
|
|
||||||
return file_exists and thumbnail_exists
|
# HACK: yt-dlp does not record extracted audio extensions anywhere. If the file is not
|
||||||
|
# found, try it using audio extensions
|
||||||
|
if not file_exists:
|
||||||
|
for audio_ext in AUDIO_CODEC_EXTS:
|
||||||
|
if os.path.isfile(self.get_download_file_path().removesuffix(self.ext) + audio_ext):
|
||||||
|
file_exists = True
|
||||||
|
break
|
||||||
|
|
||||||
|
return file_exists
|
||||||
|
|
||||||
@final
|
@final
|
||||||
def to_dict(self) -> Dict[str, str]:
|
def to_dict(self) -> Dict[str, str]:
|
||||||
|
|
|
||||||
|
|
@ -7,24 +7,10 @@ from ytdl_sub.entries.entry import Entry
|
||||||
from ytdl_sub.plugins.plugin import Plugin
|
from ytdl_sub.plugins.plugin import Plugin
|
||||||
from ytdl_sub.plugins.plugin import PluginOptions
|
from ytdl_sub.plugins.plugin import PluginOptions
|
||||||
from ytdl_sub.utils.exceptions import FileNotDownloadedException
|
from ytdl_sub.utils.exceptions import FileNotDownloadedException
|
||||||
from ytdl_sub.validators.string_select_validator import StringSelectValidator
|
from ytdl_sub.validators.audo_codec_validator import AUDIO_CODEC_TYPES_EXTENSION_MAPPING
|
||||||
|
from ytdl_sub.validators.audo_codec_validator import CodecTypeValidator
|
||||||
from ytdl_sub.validators.validators import FloatValidator
|
from ytdl_sub.validators.validators import FloatValidator
|
||||||
|
|
||||||
CODEC_TYPES_EXTENSION_MAPPING: Dict[str, str] = {
|
|
||||||
"aac": "aac",
|
|
||||||
"flac": "flac",
|
|
||||||
"mp3": "mp3",
|
|
||||||
"m4a": "m4a",
|
|
||||||
"opus": "opus",
|
|
||||||
"vorbis": "ogg",
|
|
||||||
"wav": "wav",
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class CodecTypeValidator(StringSelectValidator):
|
|
||||||
_expected_value_type_name = "codec"
|
|
||||||
_select_values = set(CODEC_TYPES_EXTENSION_MAPPING.keys())
|
|
||||||
|
|
||||||
|
|
||||||
class AudioExtractOptions(PluginOptions):
|
class AudioExtractOptions(PluginOptions):
|
||||||
"""
|
"""
|
||||||
|
|
@ -102,8 +88,13 @@ class AudioExtractPlugin(Plugin[AudioExtractOptions]):
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
Entry with updated 'ext' source variable
|
Entry with updated 'ext' source variable
|
||||||
|
|
||||||
|
Raises
|
||||||
|
------
|
||||||
|
FileNotDownloadedException
|
||||||
|
If the audio file is not found
|
||||||
"""
|
"""
|
||||||
new_ext = CODEC_TYPES_EXTENSION_MAPPING[self.plugin_options.codec]
|
new_ext = AUDIO_CODEC_TYPES_EXTENSION_MAPPING[self.plugin_options.codec]
|
||||||
extracted_audio_file = entry.get_download_file_path().removesuffix(entry.ext) + new_ext
|
extracted_audio_file = entry.get_download_file_path().removesuffix(entry.ext) + new_ext
|
||||||
if not self.is_dry_run:
|
if not self.is_dry_run:
|
||||||
if not os.path.isfile(extracted_audio_file):
|
if not os.path.isfile(extracted_audio_file):
|
||||||
|
|
|
||||||
22
src/ytdl_sub/validators/audo_codec_validator.py
Normal file
22
src/ytdl_sub/validators/audo_codec_validator.py
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
from typing import Dict
|
||||||
|
from typing import Set
|
||||||
|
|
||||||
|
from ytdl_sub.validators.string_select_validator import StringSelectValidator
|
||||||
|
|
||||||
|
AUDIO_CODEC_TYPES_EXTENSION_MAPPING: Dict[str, str] = {
|
||||||
|
"aac": "aac",
|
||||||
|
"flac": "flac",
|
||||||
|
"mp3": "mp3",
|
||||||
|
"m4a": "m4a",
|
||||||
|
"opus": "opus",
|
||||||
|
"vorbis": "ogg",
|
||||||
|
"wav": "wav",
|
||||||
|
}
|
||||||
|
|
||||||
|
AUDIO_CODEC_TYPES: Set[str] = set(AUDIO_CODEC_TYPES_EXTENSION_MAPPING.keys())
|
||||||
|
AUDIO_CODEC_EXTS: Set[str] = set(AUDIO_CODEC_TYPES_EXTENSION_MAPPING.values())
|
||||||
|
|
||||||
|
|
||||||
|
class CodecTypeValidator(StringSelectValidator):
|
||||||
|
_expected_value_type_name = "codec"
|
||||||
|
_select_values = AUDIO_CODEC_TYPES
|
||||||
|
|
@ -18,16 +18,14 @@ def single_song_preset_dict(output_directory):
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def multiple_songs_preset_dict(output_directory):
|
def multiple_songs_preset_dict(output_directory):
|
||||||
return {
|
return {
|
||||||
"preset": "yt_song_playlist",
|
"preset": "yt_song_playlist",
|
||||||
"youtube": {"playlist_url": "https://youtube.com/playlist?list=PL5BC0FC26BECA5A35"},
|
"youtube": {"playlist_url": "https://youtube.com/playlist?list=PL5BC0FC26BECA5A35"},
|
||||||
"output_options": {"output_directory": output_directory},
|
"output_options": {"output_directory": output_directory},
|
||||||
"audio_extract": {
|
"audio_extract": {"codec": "vorbis", "quality": 140},
|
||||||
"codec": "vorbis",
|
|
||||||
"quality": 140
|
|
||||||
},
|
|
||||||
# download the worst format so it is fast
|
# download the worst format so it is fast
|
||||||
"ytdl_options": {
|
"ytdl_options": {
|
||||||
"format": "worst[ext=mp4]",
|
"format": "worst[ext=mp4]",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"Jesse's Minecraft Server [Trailer - Feb.1].ogg": "3f701a4b2437704bc443cf07c9832dae",
|
"Jesse's Minecraft Server [Trailer - Feb.1].ogg": "67b19b495756fb6dc332f49bfa2957d3",
|
||||||
"Jesse's Minecraft Server [Trailer - Feb.27].ogg": "430d1c8ec20573a73e2149c10c9c741f",
|
"Jesse's Minecraft Server [Trailer - Feb.27].ogg": "273c96652e198171ee60345051addc7a",
|
||||||
"Jesse's Minecraft Server [Trailer - Mar.21].ogg": "11742c96e9ea3a520b2411d8b3516472"
|
"Jesse's Minecraft Server [Trailer - Mar.21].ogg": "e91db58c153f0724aaed5ce53de2a736"
|
||||||
}
|
}
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
{
|
{
|
||||||
"YouTube Rewind 2019: For the Record | #YouTubeRewind.mp3": "2b44b454ecc58f3600731a44e0c61f1b"
|
"YouTube Rewind 2019: For the Record | #YouTubeRewind.mp3": "c4ce74e2ddc4e6a0ab823b5b622e2275"
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue