test
This commit is contained in:
parent
fd5c48b897
commit
9a8ca7fc28
4 changed files with 261 additions and 0 deletions
67
examples/kodi_music_videos_config.yaml
Normal file
67
examples/kodi_music_videos_config.yaml
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
# This example shows how to download and format a Youtube video OR playlist
|
||||||
|
# to display in Kodi as a music video. Kodi requires music videos to be in
|
||||||
|
# a shared directory, so we will configure this to make the output directory
|
||||||
|
# formatted as:
|
||||||
|
#
|
||||||
|
# /path/to/Music Videos
|
||||||
|
# Elton John - Rocketman.jpg
|
||||||
|
# Elton John - Rocketman.mp4
|
||||||
|
# Elton John - Rocketman.nfo
|
||||||
|
# System of a Down - Chop Suey.jpg
|
||||||
|
# System of a Down - Chop Suey.mp4
|
||||||
|
# System of a Down - Chop Suey.nfo
|
||||||
|
# ...
|
||||||
|
#
|
||||||
|
configuration:
|
||||||
|
working_directory: '.ytdl-sub-downloads'
|
||||||
|
|
||||||
|
presets:
|
||||||
|
yt_music_video:
|
||||||
|
# Youtube playlists are our source/download strategy. However, this
|
||||||
|
# can be overwritten to download music videos from a 'channel' or a
|
||||||
|
# single 'video'
|
||||||
|
youtube:
|
||||||
|
download_strategy: "playlist"
|
||||||
|
|
||||||
|
# For advanced YTDL users only.
|
||||||
|
# It is wise to leave ignoreerrors=True to avoid errors for things
|
||||||
|
# like age-restricted videos in case you have not set your cookie.
|
||||||
|
ytdl_options:
|
||||||
|
ignoreerrors: True
|
||||||
|
|
||||||
|
# For each video downloaded, set the file and thumbnail name here.
|
||||||
|
# We set both with {music_video_name}, which is a variable we define in
|
||||||
|
# the overrides section further below to represent consistent naming format.
|
||||||
|
#
|
||||||
|
# Another field worth mentioning is maintain_download_archive=True. This
|
||||||
|
# is generally a good thing to enable with playlists because it will
|
||||||
|
# store previously downloaded video ids to tell YTDL not to re-download
|
||||||
|
# them on a successive invocation.
|
||||||
|
output_options:
|
||||||
|
output_directory: "path/to/Music Videos"
|
||||||
|
file_name: "{music_video_name}.{ext}"
|
||||||
|
thumbnail_name: "{music_video_name}.jpg"
|
||||||
|
maintain_download_archive: True
|
||||||
|
|
||||||
|
# Always convert the video thumbnail to jpg
|
||||||
|
# TODO: always convert all thumbnails to jpg in code
|
||||||
|
convert_thumbnail:
|
||||||
|
to: "jpg"
|
||||||
|
|
||||||
|
# For each video downloaded, add a music video NFO file for it. Populate it
|
||||||
|
# with tags that Kodi will read and use to display it in the music or music
|
||||||
|
# videos section.
|
||||||
|
nfo_tags:
|
||||||
|
nfo_name: "{music_video_name}.nfo"
|
||||||
|
nfo_root: "musicvideo"
|
||||||
|
tags:
|
||||||
|
artist: "{artist}"
|
||||||
|
title: "{title}"
|
||||||
|
album: "Music Videos"
|
||||||
|
year: "{upload_year}"
|
||||||
|
|
||||||
|
# Overrides is a section where we can define our own variables, and use them in
|
||||||
|
# any other section. We define our episode file name here, which gets reused above
|
||||||
|
# for the video, thumbnail, and NFO file.
|
||||||
|
overrides:
|
||||||
|
music_video_name: "{sanitized_artist} - {sanitized_title}"
|
||||||
84
examples/kodi_music_videos_subscriptions.yaml
Normal file
84
examples/kodi_music_videos_subscriptions.yaml
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
# This example shows how we can use the `kodi_music_videos_config.yaml` preset
|
||||||
|
# to download music videos in a few different ways. We will use made-up artists
|
||||||
|
# in each example
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# LEVEL 1 - DOWNLOAD MUSIC VIDEO PLAYLIST
|
||||||
|
|
||||||
|
# Subscription names are defined by you. We will call this one john_smith
|
||||||
|
# for simplicity, and it will download every single video in john_smith's music
|
||||||
|
# video playlist. Many artists maintain a playlist of all their music videos,
|
||||||
|
# which makes this an easy way to grab all of them.
|
||||||
|
john_smith:
|
||||||
|
# We must define a preset to use from our config. We named the one in the
|
||||||
|
# config example "yt_music_video", so set that here.
|
||||||
|
preset: "yt_music_video"
|
||||||
|
|
||||||
|
# Since our preset download strategy is set to 'playlist', set the playlist id.
|
||||||
|
youtube:
|
||||||
|
playlist_id: "UCsvn_Po0SmunchJYtttWpOxMg"
|
||||||
|
|
||||||
|
# Overrides can be defined per-subscription. If you noticed, we used {artist}
|
||||||
|
# and {sanitized_artist} in our "yt_music_video" preset. We intended to reserve
|
||||||
|
# that variable to be defined for each individual subscription. Each override
|
||||||
|
# defined here will create a 'sanitized_' version that is safe for file systems.
|
||||||
|
#
|
||||||
|
# A note for Kodi music videos, it is important to make sure your artist name
|
||||||
|
# exactly matches how it is formatted in Kodi itself, otherwise it will be
|
||||||
|
# read in as a new artist
|
||||||
|
overrides:
|
||||||
|
artist: "John Smith and the Instrument Players"
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# LEVEL 2 - DOWNLOAD SINGLE MUSIC VIDEO
|
||||||
|
|
||||||
|
# It is not always ideal to download all of an artist's music videos.
|
||||||
|
# Maybe you only like one song of theirs. We can reuse our preset
|
||||||
|
# to download a single video instead.
|
||||||
|
#
|
||||||
|
# The only difference between this example and the one above is
|
||||||
|
# - youtube.after
|
||||||
|
# This is saying 'only download videos in the last 14 days'
|
||||||
|
# - ytdl_options.break_on_reject
|
||||||
|
# This is getting into YTDL voodoo. By default, YTDL will try to
|
||||||
|
# download all channel videos beginning with the most recent one.
|
||||||
|
# By setting break_on_reject, we will break this full-download on
|
||||||
|
# the first video that gets rejected. Since we have youtube.after
|
||||||
|
# defined, all videos after today-14days will be rejected. Therefore,
|
||||||
|
# the first video that is out of range that it tries to download, it
|
||||||
|
# will stop there, and save a significant amount of time.
|
||||||
|
john_smith_one_hit_wonder:
|
||||||
|
preset: "yt_channel_as_tv"
|
||||||
|
youtube:
|
||||||
|
download_strategy: "video"
|
||||||
|
video_id: "QhY6r6oAErg"
|
||||||
|
overrides:
|
||||||
|
tv_show_name: "John /\ Smith"
|
||||||
|
ytdl_options:
|
||||||
|
break_on_reject: True
|
||||||
|
|
||||||
|
###############################################################################
|
||||||
|
# LEVEL 3 - ROLLING ARCHIVE
|
||||||
|
|
||||||
|
# If you put the recent archive example in a cron job, then in a year or so
|
||||||
|
# you will basically be datahoarding that channel unless you manually delete
|
||||||
|
# old videos. We automate because we are lazy. This example shows how to
|
||||||
|
# only keep the last 14-days worth of videos, and delete the rest.
|
||||||
|
#
|
||||||
|
# The only difference between this example and the one above is
|
||||||
|
# - output_options.keep_files.after
|
||||||
|
# This is saying "only keep files if they were uploaded in the last 14 days".
|
||||||
|
# All other files that this subscription had previously downloaded will be
|
||||||
|
# deleted.
|
||||||
|
john_smith_rolling_archive:
|
||||||
|
preset: "yt_channel_as_tv"
|
||||||
|
youtube:
|
||||||
|
channel_id: "UCsvn_Po0SmunchJYtttWpOxMg"
|
||||||
|
after: today-14days
|
||||||
|
overrides:
|
||||||
|
tv_show_name: "John /\ Smith"
|
||||||
|
ytdl_options:
|
||||||
|
break_on_reject: True
|
||||||
|
output_options:
|
||||||
|
keep_files:
|
||||||
|
after: today-14days
|
||||||
|
|
@ -18,3 +18,22 @@ class YoutubeVideoVariables(EntryVariables):
|
||||||
return self.kwargs("track")
|
return self.kwargs("track")
|
||||||
|
|
||||||
return super().title
|
return super().title
|
||||||
|
|
||||||
|
@property
|
||||||
|
def playlist_index(self) -> int:
|
||||||
|
"""
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
The index of the video in the playlist. For non-playlist download strategies, this will
|
||||||
|
always return 1.
|
||||||
|
"""
|
||||||
|
return 1
|
||||||
|
|
||||||
|
@property
|
||||||
|
def playlist_size(self) -> int:
|
||||||
|
"""
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
The size of the playlist. For non-playlist download strategies, this will always return 1.
|
||||||
|
"""
|
||||||
|
return 1
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import os.path
|
import os.path
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
from typing import List, Dict
|
||||||
|
|
||||||
|
from ytdl_sub.entries.base_entry import PlaylistMetadata
|
||||||
from ytdl_sub.entries.entry import Entry
|
from ytdl_sub.entries.entry import Entry
|
||||||
from ytdl_sub.entries.variables.youtube_variables import YoutubeVideoVariables
|
from ytdl_sub.entries.variables.youtube_variables import YoutubeVideoVariables
|
||||||
|
|
||||||
|
|
@ -31,3 +33,92 @@ class YoutubeVideo(YoutubeVideoVariables, Entry):
|
||||||
return possible_thumbnail_path
|
return possible_thumbnail_path
|
||||||
|
|
||||||
return super().get_download_thumbnail_path()
|
return super().get_download_thumbnail_path()
|
||||||
|
|
||||||
|
|
||||||
|
class YoutubePlaylistVideo(YoutubeVideo):
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
entry_dict: Dict,
|
||||||
|
working_directory: str,
|
||||||
|
playlist_metadata: PlaylistMetadata,
|
||||||
|
):
|
||||||
|
"""
|
||||||
|
Initialize the playlist video with playlist metadata
|
||||||
|
"""
|
||||||
|
super().__init__(entry_dict=entry_dict, working_directory=working_directory)
|
||||||
|
self._playlist_metadata = playlist_metadata
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_youtube_video(
|
||||||
|
cls,
|
||||||
|
youtube_video: YoutubeVideo,
|
||||||
|
playlist_metadata: PlaylistMetadata,
|
||||||
|
) -> "YoutubePlaylistVideo":
|
||||||
|
"""
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
youtube_video:
|
||||||
|
Video to convert to an playlist video
|
||||||
|
playlist_metadata:
|
||||||
|
Metadata for playlist ordering
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
YoutubeVideo converted to a YoutubePlaylistVideo
|
||||||
|
"""
|
||||||
|
return YoutubePlaylistVideo(
|
||||||
|
entry_dict=youtube_video._kwargs, # pylint: disable=protected-access
|
||||||
|
working_directory=youtube_video.working_directory(),
|
||||||
|
playlist_metadata=playlist_metadata,
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def playlist_index(self) -> int:
|
||||||
|
"""
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
The playlist index
|
||||||
|
"""
|
||||||
|
return self._playlist_metadata.playlist_index
|
||||||
|
|
||||||
|
@property
|
||||||
|
def playlist_size(self) -> int:
|
||||||
|
"""
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
The size of the playlist
|
||||||
|
"""
|
||||||
|
return self._playlist_metadata.playlist_count
|
||||||
|
|
||||||
|
|
||||||
|
class YoutubePlaylist(Entry):
|
||||||
|
@property
|
||||||
|
def _videos(self) -> List[YoutubeVideo]:
|
||||||
|
"""
|
||||||
|
Returns all videos in the playlist represented by non-playlist Videos. Use this to fetch any
|
||||||
|
data needed from the videos before representing it as a playlist video.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
YoutubeVideo(entry_dict=entry, working_directory=self._working_directory)
|
||||||
|
for entry in self.kwargs("entries")
|
||||||
|
]
|
||||||
|
|
||||||
|
def playlist_videos(self) -> List[YoutubePlaylistVideo]:
|
||||||
|
"""
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
All videos in the playlist represented as YoutubePlaylistVideos. This updates
|
||||||
|
playlist-specific fields like playlist_index and playlist_size with its actual value.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
YoutubePlaylistVideo.from_youtube_video(
|
||||||
|
youtube_video=video,
|
||||||
|
playlist_metadata=PlaylistMetadata(
|
||||||
|
playlist_id=self.uid,
|
||||||
|
playlist_extractor=self.extractor,
|
||||||
|
playlist_index=video.kwargs("playlist_index"),
|
||||||
|
playlist_count=self.kwargs('playlist_count'),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
for video in self._videos
|
||||||
|
]
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue