add support for single youtube video

This commit is contained in:
jbannon 2022-04-09 06:31:13 +00:00
parent c0e31a28c3
commit 764678367f
7 changed files with 81 additions and 25 deletions

View file

@ -27,7 +27,6 @@ presets:
music_videos: music_videos:
youtube: youtube:
download_strategy: "playlist"
ytdl_options: ytdl_options:
format: 'best' format: 'best'
ignoreerrors: True ignoreerrors: True

View file

@ -18,30 +18,42 @@
# artist: "DeLorra" # artist: "DeLorra"
# genre: "Synthwave / Electronic" # genre: "Synthwave / Electronic"
# #
bl00dwave: #bl00dwave:
preset: "soundcloud_with_id3_tags" # preset: "soundcloud_with_id3_tags"
soundcloud: # soundcloud:
username: bl00dwave # username: bl00dwave
output_options: # output_options:
output_directory: "/tmp/bl00dwave" # output_directory: "/tmp/bl00dwave"
overrides: # overrides:
artist: "bl00dwave" # artist: "bl00dwave"
genre: "Synthwave / Electronic" # genre: "Synthwave / Electronic"
#
#tom_petty:
# preset: "music_videos"
# youtube:
# download_strategy: "playlist"
# playlist_id: PLoopXDarluPBnuxs4PTC55Sc_2ShAXC0i
# output_options:
# output_directory: "/tmp/Tom Petty"
# overrides:
# artist: "Tom Petty and the Heartbreakers"
#
#rammstein:
# preset: "music_videos"
# youtube:
# download_strategy: "playlist"
# playlist_id: "PLVTLbc6i-h_iuhdwUfuPDLFLXG2QQnz-x"
# output_options:
# output_directory: "/tmp/Rammstein"
# overrides:
# artist: "Rammstein"
tom_petty: gogo_video_test:
preset: "music_videos" preset: "music_videos"
youtube: youtube:
playlist_id: PLoopXDarluPBnuxs4PTC55Sc_2ShAXC0i download_strategy: "video"
video_id: "2RHTiXvELNg"
output_options: output_options:
output_directory: "/tmp/Tom Petty" output_directory: "/tmp/gogos"
overrides: overrides:
artist: "Tom Petty and the Heartbreakers" artist: "The Gogos"
rammstein:
preset: "music_videos"
youtube:
playlist_id: "PLVTLbc6i-h_iuhdwUfuPDLFLXG2QQnz-x"
output_options:
output_directory: "/tmp/Rammstein"
overrides:
artist: "Rammstein"

View file

@ -18,6 +18,11 @@ class YoutubeDownloader(Downloader):
"""Returns full playlist url""" """Returns full playlist url"""
return f"https://youtube.com/playlist?list={playlist_id}" return f"https://youtube.com/playlist?list={playlist_id}"
@classmethod
def video_url(cls, video_id: str) -> str:
"""Returns full video url"""
return f"https://youtube.com/watch?v={video_id}"
def _download_with_metadata(self, url: str) -> None: def _download_with_metadata(self, url: str) -> None:
""" """
Do not get entries from the extract info, let it write to the info.json file and load Do not get entries from the extract info, let it write to the info.json file and load
@ -30,6 +35,10 @@ class YoutubeDownloader(Downloader):
} }
_ = self.extract_info(ytdl_options_overrides=ytdl_metadata_override, url=url) _ = self.extract_info(ytdl_options_overrides=ytdl_metadata_override, url=url)
def download_video(self, video_id: str) -> YoutubeVideo:
entry = self.extract_info(url=self.video_url(video_id))
return YoutubeVideo(**entry)
def download_playlist(self, playlist_id: str) -> List[YoutubeVideo]: def download_playlist(self, playlist_id: str) -> List[YoutubeVideo]:
""" """
Downloads all videos in a playlist Downloads all videos in a playlist

View file

@ -3,6 +3,9 @@ from ytdl_subscribe.subscriptions.subscription import Subscription
from ytdl_subscribe.validators.config.source_options.youtube_validators import ( from ytdl_subscribe.validators.config.source_options.youtube_validators import (
YoutubePlaylistSourceValidator, YoutubePlaylistSourceValidator,
) )
from ytdl_subscribe.validators.config.source_options.youtube_validators import (
YoutubeVideoSourceValidator,
)
class YoutubePlaylistSubscription(Subscription[YoutubePlaylistSourceValidator]): class YoutubePlaylistSubscription(Subscription[YoutubePlaylistSourceValidator]):
@ -13,3 +16,12 @@ class YoutubePlaylistSubscription(Subscription[YoutubePlaylistSourceValidator]):
for entry in entries: for entry in entries:
self.post_process_entry(entry) self.post_process_entry(entry)
class YoutubeVideoSubscription(Subscription[YoutubeVideoSourceValidator]):
def extract_info(self):
entry = self.get_downloader(YoutubeDownloader).download_video(
video_id=self.source_options.video_id.value
)
self.post_process_entry(entry)

View file

@ -13,6 +13,9 @@ from ytdl_subscribe.validators.config.source_options.source_validators import So
from ytdl_subscribe.validators.config.source_options.youtube_validators import ( from ytdl_subscribe.validators.config.source_options.youtube_validators import (
YoutubePlaylistSourceValidator, YoutubePlaylistSourceValidator,
) )
from ytdl_subscribe.validators.config.source_options.youtube_validators import (
YoutubeVideoSourceValidator,
)
class DownloadStrategyValidator(StrictDictValidator, ABC): class DownloadStrategyValidator(StrictDictValidator, ABC):
@ -61,4 +64,7 @@ class SoundcloudDownloadStrategyValidator(DownloadStrategyValidator):
class YoutubeDownloadStrategyValidator(DownloadStrategyValidator): class YoutubeDownloadStrategyValidator(DownloadStrategyValidator):
_download_strategy_to_source_mapping = {"playlist": YoutubePlaylistSourceValidator} _download_strategy_to_source_mapping = {
"playlist": YoutubePlaylistSourceValidator,
"video": YoutubeVideoSourceValidator,
}

View file

@ -8,3 +8,11 @@ class YoutubePlaylistSourceValidator(YoutubeSourceValidator):
def __init__(self, name, value): def __init__(self, name, value):
super().__init__(name, value) super().__init__(name, value)
self.playlist_id = self._validate_key("playlist_id", StringValidator) self.playlist_id = self._validate_key("playlist_id", StringValidator)
class YoutubeVideoSourceValidator(YoutubeSourceValidator):
_required_keys = {"video_id"}
def __init__(self, name, value):
super().__init__(name, value)
self.video_id = self._validate_key("video_id", StringValidator)

View file

@ -1,6 +1,8 @@
import copy import copy
from typing import Any from typing import Any
from typing import List from typing import List
from typing import Optional
from typing import Type
import yaml import yaml
from mergedeep import mergedeep from mergedeep import mergedeep
@ -8,6 +10,7 @@ from mergedeep import mergedeep
from ytdl_subscribe.subscriptions.soundcloud import SoundcloudAlbumsAndSinglesSubscription from ytdl_subscribe.subscriptions.soundcloud import SoundcloudAlbumsAndSinglesSubscription
from ytdl_subscribe.subscriptions.subscription import Subscription from ytdl_subscribe.subscriptions.subscription import Subscription
from ytdl_subscribe.subscriptions.youtube import YoutubePlaylistSubscription from ytdl_subscribe.subscriptions.youtube import YoutubePlaylistSubscription
from ytdl_subscribe.subscriptions.youtube import YoutubeVideoSubscription
from ytdl_subscribe.validators.base.strict_dict_validator import StrictDictValidator from ytdl_subscribe.validators.base.strict_dict_validator import StrictDictValidator
from ytdl_subscribe.validators.base.validators import StringValidator from ytdl_subscribe.validators.base.validators import StringValidator
from ytdl_subscribe.validators.config.config_file_validator import ConfigFileValidator from ytdl_subscribe.validators.config.config_file_validator import ConfigFileValidator
@ -21,6 +24,9 @@ from ytdl_subscribe.validators.config.source_options.soundcloud_validators impor
from ytdl_subscribe.validators.config.source_options.youtube_validators import ( from ytdl_subscribe.validators.config.source_options.youtube_validators import (
YoutubePlaylistSourceValidator, YoutubePlaylistSourceValidator,
) )
from ytdl_subscribe.validators.config.source_options.youtube_validators import (
YoutubeVideoSourceValidator,
)
class SubscriptionValidator(StrictDictValidator): class SubscriptionValidator(StrictDictValidator):
@ -65,11 +71,15 @@ class SubscriptionValidator(StrictDictValidator):
) )
def to_subscription(self) -> Subscription: def to_subscription(self) -> Subscription:
subscription_class: Optional[Type[Subscription]] = None
if isinstance(self.preset.subscription_source, SoundcloudAlbumsAndSinglesSourceValidator): if isinstance(self.preset.subscription_source, SoundcloudAlbumsAndSinglesSourceValidator):
subscription_class = SoundcloudAlbumsAndSinglesSubscription subscription_class = SoundcloudAlbumsAndSinglesSubscription
elif isinstance(self.preset.subscription_source, YoutubePlaylistSourceValidator): elif isinstance(self.preset.subscription_source, YoutubePlaylistSourceValidator):
subscription_class = YoutubePlaylistSubscription subscription_class = YoutubePlaylistSubscription
else: elif isinstance(self.preset.subscription_source, YoutubeVideoSourceValidator):
subscription_class = YoutubeVideoSubscription
if subscription_class is None:
raise ValueError("subscription source class not found") raise ValueError("subscription source class not found")
return subscription_class( return subscription_class(