add support for single youtube video
This commit is contained in:
parent
c0e31a28c3
commit
764678367f
7 changed files with 81 additions and 25 deletions
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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"
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue