[BACKEND] Update music video example with url download strategy (#312)

* [DOCS] document file __preset__

* [REFACTOR] Use `download` type in examples

* TODO: download strategy docs, validate fixtures, fix playlist test

* playlist fixed, fixtures look good

* download strategy docs, fix tests

* better docs

* lint

* yt fixed

* split chapters fixed

* fix video

* better docs

* lint
This commit is contained in:
Jesse Bannon
2022-11-11 08:54:07 -08:00
committed by GitHub
parent 7458814a36
commit 10b58264ea
56 changed files with 339 additions and 528 deletions

View File

@@ -12,6 +12,7 @@ clean:
build/ \
dist/ \
src/ytdl_sub.egg-info/ \
docs/_html/ \
.coverage \
coverage.xml

View File

@@ -36,69 +36,18 @@ download_strategy
Download strategies dictate what is getting downloaded from a source. Each
download strategy has its own set of parameters.
youtube
'''''''
Download strategies for downloading videos (or audio if you configure `ytdl_options`_ correctly) from Youtube. See
Download strategies for downloading music from Soundcloud. See
:class:`Youtube Variables <ytdl_sub.entries.variables.youtube_variables>`
for available source variables to use.
.. _url:
channel
_______
.. autoclass:: ytdl_sub.downloaders.youtube.channel.YoutubeChannelDownloaderOptions()
:members: channel_url, channel_avatar_path, channel_banner_path
:member-order: bysource
:exclude-members: get_date_range
.. autofunction:: ytdl_sub.downloaders.youtube.channel.YoutubeChannelDownloader.ytdl_option_defaults()
-------------------------------------------------------------------------------
.. _YouTube Playlist:
playlist
________
.. autoclass:: ytdl_sub.downloaders.youtube.playlist.YoutubePlaylistDownloaderOptions()
:members: playlist_url, playlist_thumbnail_name
url
'''
.. autoclass:: ytdl_sub.downloaders.generic.url.UrlDownloadOptions()
:members: url, playlist_thumbnails, source_thumbnails
:member-order: bysource
.. autofunction:: ytdl_sub.downloaders.youtube.playlist.YoutubePlaylistDownloader.ytdl_option_defaults()
-------------------------------------------------------------------------------
video
_____
.. autoclass:: ytdl_sub.downloaders.youtube.video.YoutubeVideoDownloaderOptions()
:members: video_url
:member-order: bysource
.. autofunction:: ytdl_sub.downloaders.youtube.video.YoutubeVideoDownloader.ytdl_option_defaults()
-------------------------------------------------------------------------------
merge_playlist
______________
.. autoclass:: ytdl_sub.downloaders.youtube.merge_playlist.YoutubeMergePlaylistDownloaderOptions()
:members: playlist_url, add_chapters
:member-order: bysource
.. autofunction:: ytdl_sub.downloaders.youtube.merge_playlist.YoutubeMergePlaylistDownloader.ytdl_option_defaults()
-------------------------------------------------------------------------------
soundcloud
''''''''''
Download strategies for downloading music from Soundcloud. See
:class:`Soundcloud Variables <ytdl_sub.entries.variables.soundcloud_variables>`
for available source variables to use.
albums_and_singles
__________________
.. autoclass:: ytdl_sub.downloaders.soundcloud.albums_and_singles.SoundcloudAlbumsAndSinglesDownloadOptions()
:members: url, skip_premiere_tracks
:member-order: bysource
.. autofunction:: ytdl_sub.downloaders.soundcloud.albums_and_singles.SoundcloudAlbumsAndSinglesDownloader.ytdl_option_defaults()
multi_url
'''''''''
.. autoclass:: ytdl_sub.downloaders.generic.multi_url.MultiUrlDownloadOptions()
:members: urls, variables
-------------------------------------------------------------------------------
@@ -171,6 +120,7 @@ audio_extract
.. autoclass:: ytdl_sub.plugins.audio_extract.AudioExtractOptions()
:members:
:member-order: bysource
:exclude-members: partial_validate
-------------------------------------------------------------------------------
@@ -179,6 +129,7 @@ chapters
.. autoclass:: ytdl_sub.plugins.chapters.ChaptersOptions()
:members:
:member-order: bysource
:exclude-members: partial_validate
-------------------------------------------------------------------------------
@@ -187,12 +138,14 @@ date_range
.. autoclass:: ytdl_sub.plugins.date_range.DateRangeOptions()
:members:
:member-order: bysource
:exclude-members: partial_validate
file_convert
''''''''''''
.. autoclass:: ytdl_sub.plugins.file_convert.FileConvertOptions()
:members:
:member-order: bysource
:exclude-members: partial_validate
-------------------------------------------------------------------------------
@@ -200,6 +153,7 @@ music_tags
''''''''''
.. autoclass:: ytdl_sub.plugins.music_tags.MusicTagsOptions()
:members:
:exclude-members: partial_validate
-------------------------------------------------------------------------------
@@ -208,6 +162,7 @@ nfo_tags
.. autoclass:: ytdl_sub.plugins.nfo_tags.NfoTagsOptions()
:members: nfo_name, nfo_root, tags, kodi_safe
:member-order: bysource
:exclude-members: partial_validate
-------------------------------------------------------------------------------
@@ -216,6 +171,7 @@ output_directory_nfo_tags
.. autoclass:: ytdl_sub.plugins.output_directory_nfo_tags.OutputDirectoryNfoTagsOptions()
:members: nfo_name, nfo_root, tags, kodi_safe
:member-order: bysource
:exclude-members: partial_validate
-------------------------------------------------------------------------------
@@ -227,6 +183,7 @@ regex
.. autoclass:: ytdl_sub.plugins.regex.SourceVariableRegex()
:members: match, capture_group_names, capture_group_defaults
:member-order: bysource
:exclude-members: partial_validate
-------------------------------------------------------------------------------
@@ -235,6 +192,7 @@ split_by_chapters
.. autoclass:: ytdl_sub.plugins.split_by_chapters.SplitByChaptersOptions()
:members: when_no_chapters
:member-order: bysource
:exclude-members: partial_validate
-------------------------------------------------------------------------------
@@ -243,6 +201,7 @@ subtitles
.. autoclass:: ytdl_sub.plugins.subtitles.SubtitleOptions()
:members: subtitles_name, subtitles_type, embed_subtitles, languages, allow_auto_generated_subtitles
:member-order: bysource
:exclude-members: partial_validate
-------------------------------------------------------------------------------
@@ -250,6 +209,7 @@ video_tags
''''''''''
.. autoclass:: ytdl_sub.plugins.video_tags.VideoTagsOptions()
:members:
:exclude-members: partial_validate
-------------------------------------------------------------------------------

View File

@@ -1,59 +0,0 @@
# 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_playlist"
# Since our preset download strategy is set to 'playlist', set the playlist url
youtube:
playlist_url: "https://youtube.com/playlist?list=UCsvn_Po0SmunchJYtttWpOxMg"
# Overrides can be defined per-subscription. If you noticed, we used {artist}
# and {artist_sanitized} 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
# - preset
# Use the music video preset, not the playlist preset
# - youtube.video_url
# The video url to download
#
# Of course, defining yaml configuration to download a single video once
# and never again seems weird. Instead, we can perform this download via
# command:
#
# ytdl-sub dl \
# --preset "yt_music_video" \
# --youtube.video_url "https://youtube.com/watch?v=QhY6r6oAErg" \
# --overrides.artist "John Smith and the Instrument Players"
#
john_smith_one_hit_wonder:
preset: "yt_music_video"
youtube:
video_url: "https://youtube.com/watch?v=QhY6r6oAErg"
overrides:
artist: "John Smith and the Instrument Players"

View File

@@ -3,14 +3,14 @@ configuration:
working_directory: '.ytdl-sub-downloads'
presets:
yt_song:
youtube:
download_strategy: "video"
song:
download:
download_strategy: "url"
url: "{url}"
output_options:
output_directory: "{music_directory}"
file_name: "{custom_track_name_sanitized}.{ext}"
info_json_name: "{custom_track_name_sanitized}.{info_json_ext}"
audio_extract:
codec: "mp3"
@@ -34,15 +34,13 @@ presets:
custom_track_number: "1"
# TODO: make a playlist of individual songs into an album. Need playlist_title
yt_song_playlist:
preset: yt_song
youtube:
download_strategy: "playlist"
song_playlist:
preset: "song"
overrides:
custom_track_number: "{playlist_index}"
yt_album_as_chapters:
preset: "yt_song"
album_from_chapters:
preset: "song"
output_options:
file_name: "{custom_album_name_sanitized}/{chapter_index_padded} - {custom_track_name_sanitized}.{ext}"
thumbnail_name: "{custom_album_name_sanitized}/folder.{thumbnail_ext}"

View File

@@ -1,12 +1,13 @@
# 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:
# This example shows how to download and format a music video OR playlist
# of music videos to display in Kodi as a music video. The format will
# look like:
#
# /path/to/Music Videos
# Elton John/
# Elton John - Rocketman-thumb.jpg
# Elton John - Rocketman.mp4
# Elton John - Rocketman.nfo
# System of a Down/
# System of a Down - Chop Suey-thumb.jpg
# System of a Down - Chop Suey.mp4
# System of a Down - Chop Suey.nfo
@@ -16,20 +17,21 @@ configuration:
working_directory: '.ytdl-sub-downloads'
presets:
yt_music_video:
# A single YouTube video is our source/download strategy. However, this
# can be overwritten to download music videos from a "playlist", as we
# will see in a preset below
youtube:
download_strategy: "video"
music_video:
# Set the download details
download:
# We will only use a single URL to download music video(s).
# Make {url} an override variable to set later.
download_strategy: "url"
url: "{url}"
# For advanced YTDL users only; any YTDL parameter can be set here.
# To download age-restricted videos, you will need to set your cookie
# file here as a ytdl parameter. For more info, see
# https://ytdl-sub.readthedocs.io/en/latest/faq.html#download-age-restricted-youtube-videos
#
# ytdl_options:
# cookiefile: "path/to/cookie_file.txt
ytdl_options:
# cookiefile: "path/to/cookie_file.txt
break_on_existing: True # Stop downloads if it already exists
# 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
@@ -39,6 +41,7 @@ presets:
file_name: "{music_video_name}.{ext}"
thumbnail_name: "{music_video_name}-thumb.jpg"
info_json_name: "{music_video_name}.{info_json_ext}"
maintain_download_archive: True
# 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
@@ -55,23 +58,10 @@ presets:
# Overrides is a section where we can define our own variables, and use them in
# any other section. We define our music video directory and episode file name
# here, which gets reused above for the video, thumbnail, and NFO file.
# Recommended to override the artist variable.
# Recommended to override the artist variable since {channel} is not always
# the artist's exact name.
overrides:
music_video_directory: "path/to/Music Videos"
music_video_name: "{artist_sanitized} - {title_sanitized}"
music_video_name: "{artist_sanitized}/{artist_sanitized} - {title_sanitized}"
artist: "{channel}"
# 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 above
# to download a single video instead.
yt_music_video_playlist:
preset: "yt_music_video"
youtube:
download_strategy: "playlist"
# Setting maintain_download_archive=True is generally a good thing to enable
# with playlists and channels because it will store previously downloaded
# video ids to tell YTDL not to re-download them on a successive invocation.
output_options:
maintain_download_archive: True

View File

@@ -0,0 +1,24 @@
###############################################################################
# DOWNLOAD MUSIC VIDEO PLAYLIST
john_smith:
preset: "music_video"
overrides:
url: "https://youtube.com/playlist?list=UCsvn_Po0SmunchJYtttWpOxMg"
artist: "John Smith and the Instrument Players"
###############################################################################
# DOWNLOAD SINGLE MUSIC VIDEO VIA CLI
# 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.
#
# Of course, defining yaml configuration to download a single video once
# and never again seems weird. Instead, we can perform this download via
# command-line:
#
# ytdl-sub dl \
# --preset "music_video" \
# --override.url "https://youtube.com/watch?v=QhY6r6oAErg" \
# --overrides.artist "John Smith and the Instrument Players"
#

View File

@@ -134,6 +134,12 @@ class DownloadArgsParser:
next_dict[arg_name_split[-1]] = arg_value
# TODO: handle ints/floats
if arg_value == "True":
next_dict[arg_name_split[-1]] = True
elif arg_value == "False":
next_dict[arg_name_split[-1]] = False
return argument_dict
@classmethod

View File

@@ -51,20 +51,20 @@ class ConfigOptions(StrictDictValidator):
configuration:
dl_aliases:
mv: "--preset yt_music_video"
v: "--youtube.video_url"
mv: "--preset music_video"
u: "--download.url"
Simplifies
.. code-block:: bash
ytdl-sub dl --preset "yt_music_video" --youtube.video_url "youtube.com/watch?v=a1b2c3"
ytdl-sub dl --preset "music_video" --download.url "youtube.com/watch?v=a1b2c3"
to
.. code-block:: bash
ytdl-sub dl --mv --v "youtube.com/watch?v=a1b2c3"
ytdl-sub dl --mv --u "youtube.com/watch?v=a1b2c3"
"""
if self._dl_aliases:
return self._dl_aliases.dict

View File

@@ -550,7 +550,7 @@ class Downloader(DownloadArchiver, Generic[DownloaderOptionsT], ABC):
) -> Iterable[Entry] | Iterable[Tuple[Entry, FileMetadata]]:
"""The function to perform the download of all media entries"""
# download the bottom-most urls first since they are top-priority
for collection_url in reversed(self.collection.collection_urls.list):
for collection_url in reversed(self.collection.urls.list):
parents, orphan_entries = self._download_url_metadata(collection_url=collection_url)
collection_url_entries: List[Entry] = []

View File

@@ -71,9 +71,9 @@ class UrlValidator(StrictDictValidator):
@property
def url(self) -> OverridesStringFormatterValidator:
"""
URL to download from, listed in priority from lowest (top) to highest (bottom). If a
download exists in more than one URL, it will resolve to the bottom-most one and inherit
those variables.
Required. URL to download from, listed in priority from lowest (top) to highest (bottom).
If a download exists in more than one URL, it will resolve to the bottom-most one and
inherit those variables.
"""
return self._url
@@ -85,30 +85,13 @@ class UrlValidator(StrictDictValidator):
"""
return self._variables
@property
def source_thumbnails(self) -> Optional[UrlThumbnailListValidator]:
"""
Thumbnails to download from the source, if any exist. The hierarchy is defined as
source -> playlist -> entry.
Usage:
.. code-block:: yaml
source_thumbnails:
- name: "poster.jpg"
uid: "avatar_uncropped"
UID is the yt-dlp thumbnail ID or can specify ``latest_entry`` to use the last entry's
thumbnail that was downloaded.
"""
return self._source_thumbnails
@property
def playlist_thumbnails(self) -> Optional[UrlThumbnailListValidator]:
"""
Thumbnails to download from the source, if any exist. The hierarchy is defined as
source -> playlist -> entry.
Thumbnails to download from the playlist, if any exist. Playlist is the ``yt-dlp`` naming
convention for a set that contains multiple entries. For example, the URL
``https://www.youtube.com/c/RickastleyCoUkOfficial`` would have ``playlist`` refer to the
channel.
Usage:
@@ -117,12 +100,40 @@ class UrlValidator(StrictDictValidator):
playlist_thumbnails:
- name: "poster.jpg"
uid: "avatar_uncropped"
- name: "fanart.jpg"
uid: "banner_uncropped"
UID is the yt-dlp thumbnail ID or can specify ``latest_entry`` to use the last entry's
thumbnail that was downloaded.
``name`` is the file name relative to the output directory to store the thumbnail.
``uid`` is the yt-dlp thumbnail ID. Can specify ``latest_entry`` to use the latest entry's
thumbnail.
"""
return self._playlist_thumbnails
@property
def source_thumbnails(self) -> Optional[UrlThumbnailListValidator]:
"""
Thumbnails to download from the source, if any exist. Source in this context refers to the
set of sets. For example, the URL
``https://www.youtube.com/c/RickastleyCoUkOfficial/playlists``
would have ``playlist`` refer to each individual playlist, whereas ``source`` refers
to the channel.
Usage:
.. code-block:: yaml
source_thumbnails:
- name: "poster.jpg"
uid: "avatar_uncropped"
- name: "fanart.jpg"
uid: "banner_uncropped"
``name`` is the file name relative to the output directory to store the thumbnail.
``uid`` is the yt-dlp thumbnail ID. Can specify ``latest_entry`` to use the latest entry's
thumbnail.
"""
return self._source_thumbnails
class UrlListValidator(ListValidator[UrlValidator]):
_inner_list_type = UrlValidator
@@ -173,12 +184,22 @@ class MultiUrlValidator(StrictDictValidator, AddsVariablesMixin):
self._urls = self._validate_key(key="urls", validator=UrlListValidator)
@property
def collection_urls(self) -> UrlListValidator:
def urls(self) -> UrlListValidator:
"""
Required. The Soundcloud user's url, i.e. ``soundcloud.com/the_username``
Required. A list of :ref:`url` with the addition of the ``variables`` attribute.
"""
return self._urls
@property
def variables(self) -> DictFormatterValidator:
"""
Optional. Source variables to add to each entry downloaded from its respective :ref:`url`.
The top-most :ref:`url` must define all possible variables. Other :ref:`url` entries can
redefine all of them or a subset of the top-most variables.
"""
# keep for readthedocs documentation
return self._urls.list[0].variables
def added_source_variables(self) -> List[str]:
"""
Returns
@@ -205,7 +226,7 @@ class MultiUrlValidator(StrictDictValidator, AddsVariablesMixin):
)
# Apply formatting to each new source variable, ensure it resolves
for collection_url in self.collection_urls.list:
for collection_url in self.urls.list:
for (
source_var_name,
source_var_formatter_str,

View File

@@ -144,7 +144,7 @@ class YoutubeMergePlaylistDownloader(Downloader[YoutubeMergePlaylistDownloaderOp
def download(self) -> List[Tuple[Entry, FileMetadata]]:
"""Download a single Youtube video, then split it into multiple videos"""
url = self.overrides.apply_formatter(self.collection.collection_urls.list[0].url)
url = self.overrides.apply_formatter(self.collection.urls.list[0].url)
entry_dict = self.extract_info(url=url)
merged_video = self._to_merged_video(entry_dict=entry_dict)

View File

@@ -63,7 +63,7 @@ def preset_dict_to_dl_args(preset_dict: Dict) -> str:
def _recursive_preset_args(cli_key: str, current_value: Dict | Any) -> List[str]:
if isinstance(current_value, dict):
preset_args: List[str] = []
for v_key, v_value in current_value.items():
for v_key, v_value in sorted(current_value.items()):
preset_args.extend(
_recursive_preset_args(
cli_key=f"{cli_key}.{v_key}" if cli_key else v_key, current_value=v_value

View File

@@ -14,7 +14,7 @@ from ytdl_sub.utils.file_handler import FileHandlerTransactionLog
@pytest.fixture()
def music_video_config_path():
return "examples/kodi_music_videos_config.yaml"
return "examples/music_videos_config.yaml"
@pytest.fixture()
@@ -34,7 +34,7 @@ def soundcloud_discography_config():
@pytest.fixture()
def youtube_audio_config_path():
return "examples/youtube_extract_and_tag_audio.yaml"
return "examples/music_audio_from_videos.yaml"
@pytest.fixture()

View File

@@ -8,8 +8,8 @@ from ytdl_sub.subscriptions.subscription import Subscription
@pytest.fixture
def single_song_preset_dict(output_directory):
return {
"preset": "yt_song",
"youtube": {"video_url": "https://www.youtube.com/watch?v=2lAe1cqCOXo"},
"preset": "song",
"download": {"url": "https://www.youtube.com/watch?v=2lAe1cqCOXo"},
"output_options": {"output_directory": output_directory},
# download the worst format so it is fast
"ytdl_options": {
@@ -22,8 +22,8 @@ def single_song_preset_dict(output_directory):
@pytest.fixture
def multiple_songs_preset_dict(output_directory):
return {
"preset": "yt_song_playlist",
"youtube": {"playlist_url": "https://youtube.com/playlist?list=PL5BC0FC26BECA5A35"},
"preset": "song_playlist",
"download": {"url": "https://youtube.com/playlist?list=PL5BC0FC26BECA5A35"},
"output_options": {"output_directory": output_directory},
"audio_extract": {"codec": "vorbis", "quality": 140},
# download the worst format so it is fast
@@ -34,6 +34,7 @@ def multiple_songs_preset_dict(output_directory):
}
# TODO: Test album from chapters
class TestAudioExtract:
@pytest.mark.parametrize("dry_run", [True, False])
def test_audio_extract_single_song(

View File

@@ -8,8 +8,8 @@ from ytdl_sub.subscriptions.subscription import Subscription
@pytest.fixture
def single_video_sponsorblock_and_embedded_subs_preset_dict(output_directory):
return {
"preset": "yt_music_video",
"youtube": {"video_url": "https://www.youtube.com/watch?v=-wJOUAuKZm8"},
"preset": "music_video",
"download": {"url": "https://www.youtube.com/watch?v=-wJOUAuKZm8"},
# override the output directory with our fixture-generated dir
"output_options": {"output_directory": output_directory},
"subtitles": {

View File

@@ -8,8 +8,8 @@ from ytdl_sub.subscriptions.subscription import Subscription
@pytest.fixture
def preset_dict(output_directory):
return {
"preset": "yt_music_video",
"youtube": {"video_url": "https://www.youtube.com/watch?v=2zYF9JLHDmA"},
"preset": "music_video",
"download": {"url": "https://www.youtube.com/watch?v=2zYF9JLHDmA"},
"output_options": {"output_directory": output_directory},
# download the worst format so it is fast
"ytdl_options": {

View File

@@ -7,8 +7,8 @@ from ytdl_sub.subscriptions.subscription import Subscription
@pytest.fixture
def subscription_dict(output_directory):
return {
"preset": "yt_music_video",
"youtube": {"video_url": "https://www.youtube.com/shorts/ucYmEqmlhFw"},
"preset": "music_video",
"download": {"url": "https://www.youtube.com/shorts/ucYmEqmlhFw"},
# override the output directory with our fixture-generated dir
"output_options": {"output_directory": output_directory},
# download the worst format so it is fast

View File

@@ -13,8 +13,8 @@ from ytdl_sub.utils.exceptions import ValidationException
@pytest.fixture
def regex_subscription_dict(output_directory):
return {
"preset": "yt_music_video_playlist",
"youtube": {"playlist_url": "https://youtube.com/playlist?list=PL5BC0FC26BECA5A35"},
"preset": "music_video",
"download": {"url": "https://youtube.com/playlist?list=PL5BC0FC26BECA5A35"},
# override the output directory with our fixture-generated dir
"output_options": {"output_directory": output_directory},
# download the worst format so it is fast

View File

@@ -12,8 +12,8 @@ from ytdl_sub.utils.exceptions import ValidationException
@pytest.fixture
def yt_album_as_chapters_preset_dict(output_directory):
return {
"preset": "yt_album_as_chapters",
"youtube": {"video_url": "https://www.youtube.com/watch?v=zeR2_YjlXWA"},
"preset": "album_from_chapters",
"download": {"url": "https://www.youtube.com/watch?v=zeR2_YjlXWA"},
# override the output directory with our fixture-generated dir
"output_options": {"output_directory": output_directory},
# download the worst format so it is fast
@@ -128,7 +128,7 @@ class TestSplitByChapters:
mergedeep.merge(
yt_album_as_chapters_with_regex_preset_dict,
{
"youtube": {"video_url": "https://youtube.com/watch?v=HKTNxEqsN3Q"},
"download": {"url": "https://youtube.com/watch?v=HKTNxEqsN3Q"},
"split_by_chapters": {"when_no_chapters": when_no_chapters},
},
)

View File

@@ -8,8 +8,8 @@ from ytdl_sub.subscriptions.subscription import Subscription
@pytest.fixture
def single_video_subs_embed_preset_dict(output_directory):
return {
"preset": "yt_music_video",
"youtube": {"video_url": "https://www.youtube.com/watch?v=2lAe1cqCOXo"},
"preset": "music_video",
"download": {"url": "https://www.youtube.com/watch?v=2lAe1cqCOXo"},
# override the output directory with our fixture-generated dir
"output_options": {"output_directory": output_directory},
"subtitles": {

View File

@@ -1,95 +0,0 @@
import pytest
from expected_download import assert_expected_downloads
from expected_transaction_log import assert_transaction_log_matches
from ytdl_sub.config.config_file import ConfigFile
from ytdl_sub.config.preset import Preset
from ytdl_sub.subscriptions.subscription import Subscription
@pytest.fixture
def config_path():
return "examples/kodi_music_videos_config.yaml"
@pytest.fixture
def subscription_name():
return "jmc"
@pytest.fixture
def config(config_path):
return ConfigFile.from_file_path(config_path=config_path)
@pytest.fixture
def subscription_dict(output_directory, subscription_name):
return {
"preset": "yt_music_video_playlist",
"youtube": {
"download_strategy": "merge_playlist",
"playlist_url": "https://youtube.com/playlist?list=PL5BC0FC26BECA5A35",
"add_chapters": True,
},
# override the output directory with our fixture-generated dir
"output_options": {"output_directory": output_directory},
# download the worst format so it is fast
"ytdl_options": {
"format": "best[height<=480]",
"postprocessor_args": {"ffmpeg": ["-bitexact"]}, # Must add this for reproducibility
},
"overrides": {"artist": "JMC"},
}
####################################################################################################
# PLAYLIST FIXTURES
@pytest.fixture
def playlist_subscription(config, subscription_name, subscription_dict):
playlist_preset = Preset.from_dict(
config=config,
preset_name=subscription_name,
preset_dict=subscription_dict,
)
return Subscription.from_preset(
preset=playlist_preset,
config=config,
)
# @pytest.fixture
# def expected_playlist_download():
# # fmt: off
# return ExpectedDownloads(
# expected_downloads=[
# ExpectedDownloadFile(path=Path("JMC - Jesse's Minecraft Server-thumb.jpg"), md5="a3f1910f9c51f6442f845a528e190829"),
# ExpectedDownloadFile(path=Path("JMC - Jesse's Minecraft Server.mkv")), # not bitexact TODO: check size
# ExpectedDownloadFile(path=Path("JMC - Jesse's Minecraft Server.nfo"), md5="10df5dcdb65ab18ecf21b3503c77e48b"),
# ]
# )
# # fmt: on
class TestYoutubeMergePlaylist:
"""
Downloads my old minecraft youtube channel, pretends they are music videos. Ensure the above
files exist and have the expected md5 file hashes.
"""
@pytest.mark.parametrize("dry_run", [True, False])
def test_merge_playlist_download(self, playlist_subscription, output_directory, dry_run):
transaction_log = playlist_subscription.download(dry_run=dry_run)
assert_transaction_log_matches(
output_directory=output_directory,
transaction_log=transaction_log,
transaction_log_summary_file_name="youtube/test_merge_playlist.txt",
)
assert_expected_downloads(
output_directory=output_directory,
dry_run=dry_run,
ignore_md5_hashes_for=["JMC - Jesse's Minecraft Server.mkv"], # TODO, better test here
expected_download_summary_file_name="youtube/test_merge_playlist.json",
)

View File

@@ -11,10 +11,10 @@ from ytdl_sub.subscriptions.subscription import Subscription
@pytest.fixture
def playlist_preset_dict(output_directory):
return {
"preset": "yt_music_video_playlist",
"youtube": {
"playlist_url": "https://youtube.com/playlist?list=PL5BC0FC26BECA5A35",
"playlist_thumbnail_name": "poster.jpg",
"preset": "music_video",
"download": {
"url": "https://youtube.com/playlist?list=PL5BC0FC26BECA5A35",
"playlist_thumbnails": {"name": "poster.jpg", "uid": "latest_entry"},
},
# override the output directory with our fixture-generated dir
"output_options": {"output_directory": output_directory},

View File

@@ -10,10 +10,13 @@ from ytdl_sub.subscriptions.subscription import Subscription
@pytest.fixture
def single_video_preset_dict(output_directory):
return {
"preset": "yt_music_video",
"youtube": {"video_url": "https://youtube.com/watch?v=HKTNxEqsN3Q"},
"preset": "music_video",
"download": {"url": "https://youtube.com/watch?v=HKTNxEqsN3Q"},
# override the output directory with our fixture-generated dir
"output_options": {"output_directory": output_directory},
"output_options": {
"output_directory": output_directory,
"maintain_download_archive": False,
},
# download the worst format so it is fast
"ytdl_options": {
"format": "worst[ext=mp4]",
@@ -79,10 +82,10 @@ class TestYoutubeVideo:
assert_transaction_log_matches(
output_directory=output_directory,
transaction_log=transaction_log,
transaction_log_summary_file_name="youtube/test_video.txt",
transaction_log_summary_file_name="youtube/test_video_cli.txt",
)
assert_expected_downloads(
output_directory=output_directory,
dry_run=dry_run,
expected_download_summary_file_name="youtube/test_video.json",
expected_download_summary_file_name="youtube/test_video_cli.json",
)

View File

@@ -1,6 +1,7 @@
{
"Beyond The Guitar - When you hear Hugh Jackman is returning as Wolverine in Deadpool 3-thumb.jpg": "662fcaadf6e80d63591bac19a5fdffb0",
"Beyond The Guitar - When you hear Hugh Jackman is returning as Wolverine in Deadpool 3.info.json": "c5f4cdadcf89a60811e733f84edc8996",
"Beyond The Guitar - When you hear Hugh Jackman is returning as Wolverine in Deadpool 3.mp4": "390177bcc076e309d1534b8bb5afdcc7",
"Beyond The Guitar - When you hear Hugh Jackman is returning as Wolverine in Deadpool 3.nfo": "cacf09ab38f9b3085da9c5af516cf22a"
".ytdl-sub-file_convert_test-download-archive.json": "65aa49c7345f9fc201e42ddc4a96b19b",
"Beyond The Guitar/Beyond The Guitar - When you hear Hugh Jackman is returning as Wolverine in Deadpool 3-thumb.jpg": "662fcaadf6e80d63591bac19a5fdffb0",
"Beyond The Guitar/Beyond The Guitar - When you hear Hugh Jackman is returning as Wolverine in Deadpool 3.info.json": "30b444dbe693b1483904698ad1b19090",
"Beyond The Guitar/Beyond The Guitar - When you hear Hugh Jackman is returning as Wolverine in Deadpool 3.mp4": "390177bcc076e309d1534b8bb5afdcc7",
"Beyond The Guitar/Beyond The Guitar - When you hear Hugh Jackman is returning as Wolverine in Deadpool 3.nfo": "cacf09ab38f9b3085da9c5af516cf22a"
}

View File

@@ -1,15 +1,4 @@
{
"01. Intro (Feat. Racheal Ofori & Barney Artist).info.json": "c13b562993dd1507e0be88ac003f36fe",
"02. Answers (Feat. Rick David & Kaya Thomas - Dyke).info.json": "d66fde52ecb4613f517db1546e9d866e",
"03. Blaze (Feat. Kaya Thomas - Dyke).info.json": "ce72fff01376252cba06e6baa761c7db",
"04. What If (Interlude).info.json": "d862af9c67c6433024cfb7f295f62718",
"05. No Peace (Feat. Tom Misch).info.json": "aa779527de1e3d439d9abc3424b7f4c9",
"06. Closer (Feat. Lester Duval).info.json": "35c99e4f14f8329fb77d6319f376f7ec",
"07. Delusions Rumination (Interlude) (Feat. Racheal Ofori).info.json": "bd823154833b1389ed91154a2d734903",
"08. Dreams (Feat. Carmody).info.json": "2b89e85a878cf81c7c480ab5b069f940",
"09. Dreaming (Interlude) (Feat. Racheal Ofori).info.json": "126bd7301438748a77d94303d3ffec77",
"10. Hopeful (Feat. Jordan Rakei).info.json": "3d13233826e965264ac2f8d28f2149f9",
"11. Sunrise (Pillows) (Feat. Emmavie).info.json": "8671fee720b686eb9f79db63b8341eed",
"Alfa Mist - Nocturne [Full Album]/01 - 01. Intro (Feat. Racheal Ofori & Barney Artist).mp3": "1ede8775719b99d05c89d6d0a2a74df5",
"Alfa Mist - Nocturne [Full Album]/02 - 02. Answers (Feat. Rick David & Kaya Thomas - Dyke).mp3": "2430b44a6c15050f7e2ee09274c26600",
"Alfa Mist - Nocturne [Full Album]/03 - 03. Blaze (Feat. Kaya Thomas - Dyke).mp3": "8dbb8d15109955c4540dfe3c015157b8",

View File

@@ -1,5 +1,4 @@
{
"Oblivion Mod Falcor p.1.info.json": "0819dc20f5803f8c91a8c8d2d9f7b211",
"Oblivion Mod Falcor p.1/01 - Oblivion Mod Falcor p.1.mp3": "6d570f225f6c3a14de0ba4c912995641",
"Oblivion Mod Falcor p.1/folder.jpg": "fb95b510681676e81c321171fc23143e"
}

View File

@@ -1,13 +1,4 @@
{
"Answers (Feat. Rick David & Kaya Thomas - Dyke).info.json": "fc16b2772425a226a6d4202c1f32968e",
"Blaze (Feat. Kaya Thomas - Dyke).info.json": "5c7b118a2bd620bd8a2e9f3654bdbcf6",
"Closer (Feat. Lester Duval).info.json": "3565218771e9366378a0b7d740ccc73c",
"Delusions Rumination (Interlude) (Feat. Racheal Ofori).info.json": "a78f4db52e9d1c68b800d8714d209c9f",
"Dreaming (Interlude) (Feat. Racheal Ofori).info.json": "2c66fdeabbc20599455da7e5cc26a269",
"Dreams (Feat. Carmody).info.json": "ce220d509238eec57b2c48682a139643",
"Hopeful (Feat. Jordan Rakei).info.json": "90ce01e9e8a3f4d4db71db0971cdd5f8",
"Intro (Feat. Racheal Ofori & Barney Artist).info.json": "763400e50f187dad3260dcdac2b02542",
"No Peace (Feat. Tom Misch).info.json": "f3991884b296795e048bd023b64d4b99",
"Nocturne/01 - Intro (Feat. Racheal Ofori & Barney Artist).mp3": "b2e2a9834f03d1928e0c8a0602899d4d",
"Nocturne/02 - Answers (Feat. Rick David & Kaya Thomas - Dyke).mp3": "8fe76edcc77c5d8db0f7b5b8577a4cf6",
"Nocturne/03 - Blaze (Feat. Kaya Thomas - Dyke).mp3": "fd45453753a783ec4f26ef399a8ecece",
@@ -19,7 +10,5 @@
"Nocturne/09 - Dreaming (Interlude) (Feat. Racheal Ofori).mp3": "e50182fa81d56bb9261654e1906d18af",
"Nocturne/10 - Hopeful (Feat. Jordan Rakei).mp3": "d2f9958553262c4bee4f82f98f1d42c7",
"Nocturne/11 - Sunrise (Pillows) (Feat. Emmavie).mp3": "767dc4f27cc0a57d5391baf7b242d3f0",
"Nocturne/folder.jpg": "bd3685acc53072e591bae2505ecb0648",
"Sunrise (Pillows) (Feat. Emmavie).info.json": "9d01ca8f301334d118772f2b389fb9e4",
"What If (Interlude).info.json": "848b11d8d6fa51defc4cbda6a7b3e218"
"Nocturne/folder.jpg": "bd3685acc53072e591bae2505ecb0648"
}

View File

@@ -1,8 +1,5 @@
{
"Jesse's Minecraft Server [Trailer - Feb.1].info.json": "4214f8fac3333eb6baa73ea9648f86b4",
"Jesse's Minecraft Server [Trailer - Feb.1].ogg": "afb2264e271e3c464d0fe9ba0db37f88",
"Jesse's Minecraft Server [Trailer - Feb.27].info.json": "5dcc4ad1ccccb69c5054d497fad41884",
"Jesse's Minecraft Server [Trailer - Feb.27].ogg": "6f322d842a1e43b4c9981b42423d9b4c",
"Jesse's Minecraft Server [Trailer - Mar.21].info.json": "5a491a80875794abee3ee7da60b9d51b",
"Jesse's Minecraft Server [Trailer - Mar.21].ogg": "fe1dc3361a102661c27020d5b95a2a81"
}

View File

@@ -1,4 +1,3 @@
{
"YouTube Rewind 2019 For the Record #YouTubeRewind.info.json": "de578129ce495c2ee4bf8f15212e1bb2",
"YouTube Rewind 2019 For the Record #YouTubeRewind.mp3": "d3687bf6c13a2a5f3a8a05fbce9be28c"
}

View File

@@ -1,6 +1,7 @@
{
"JMC - This GPU SLIDES into this Case! - Silverstone SUGO 16 ITX Case-thumb.jpg": "b5353a824a4800cc26f884e3025ed969",
"JMC - This GPU SLIDES into this Case! - Silverstone SUGO 16 ITX Case.info.json": "d4ceb53039697fbb08a9479a4b1e97fd",
"JMC - This GPU SLIDES into this Case! - Silverstone SUGO 16 ITX Case.mp4": "97f74f4796ba5a5977bbb4fb0b21ae93",
"JMC - This GPU SLIDES into this Case! - Silverstone SUGO 16 ITX Case.nfo": "b9bd35e4f260c728774d8dd31f83637c"
".ytdl-sub-chapters_from_timestamps_with_subs-download-archive.json": "40abc64a8fe93a10406bff1548a2cbe2",
"JMC/JMC - This GPU SLIDES into this Case! - Silverstone SUGO 16 ITX Case-thumb.jpg": "b5353a824a4800cc26f884e3025ed969",
"JMC/JMC - This GPU SLIDES into this Case! - Silverstone SUGO 16 ITX Case.info.json": "c37c5f70f422a806eed1dd11a4c43d34",
"JMC/JMC - This GPU SLIDES into this Case! - Silverstone SUGO 16 ITX Case.mp4": "97f74f4796ba5a5977bbb4fb0b21ae93",
"JMC/JMC - This GPU SLIDES into this Case! - Silverstone SUGO 16 ITX Case.nfo": "b9bd35e4f260c728774d8dd31f83637c"
}

View File

@@ -1,6 +1,7 @@
{
"JMC - This GPU SLIDES into this Case! - Silverstone SUGO 16 ITX Case-thumb.jpg": "b5353a824a4800cc26f884e3025ed969",
"JMC - This GPU SLIDES into this Case! - Silverstone SUGO 16 ITX Case.info.json": "f4ecde8a60ad02c83b02a951ef28f60f",
"JMC - This GPU SLIDES into this Case! - Silverstone SUGO 16 ITX Case.mp4": "ba555c6a13869f3557b724b6ef2fbb6e",
"JMC - This GPU SLIDES into this Case! - Silverstone SUGO 16 ITX Case.nfo": "b9bd35e4f260c728774d8dd31f83637c"
".ytdl-sub-sponsorblock_with_embedded_subs_test-download-archive.json": "40abc64a8fe93a10406bff1548a2cbe2",
"JMC/JMC - This GPU SLIDES into this Case! - Silverstone SUGO 16 ITX Case-thumb.jpg": "b5353a824a4800cc26f884e3025ed969",
"JMC/JMC - This GPU SLIDES into this Case! - Silverstone SUGO 16 ITX Case.info.json": "bc7bb4272d0d30edc87725f8aa64a25a",
"JMC/JMC - This GPU SLIDES into this Case! - Silverstone SUGO 16 ITX Case.mp4": "ba555c6a13869f3557b724b6ef2fbb6e",
"JMC/JMC - This GPU SLIDES into this Case! - Silverstone SUGO 16 ITX Case.nfo": "b9bd35e4f260c728774d8dd31f83637c"
}

View File

@@ -1,6 +1,7 @@
{
"JMC - YouTube Rewind 2019 For the Record #YouTubeRewind-thumb.jpg": "50ee47c80f679029f5d3503bb91b045a",
"JMC - YouTube Rewind 2019 For the Record #YouTubeRewind.info.json": "22585d06ef862a4b923db4e2665f0d79",
"JMC - YouTube Rewind 2019 For the Record #YouTubeRewind.mp4": "1f1f91f85b162c20596a2413e704b809",
"JMC - YouTube Rewind 2019 For the Record #YouTubeRewind.nfo": "c64964fab07574080e5da3242e3bfd48"
".ytdl-sub-subtitles_embedded_test-download-archive.json": "1aa35c1d2663ac721f33f8374c00af1a",
"JMC/JMC - YouTube Rewind 2019 For the Record #YouTubeRewind-thumb.jpg": "50ee47c80f679029f5d3503bb91b045a",
"JMC/JMC - YouTube Rewind 2019 For the Record #YouTubeRewind.info.json": "fe08fcd1b68f00715e041bd98bec0570",
"JMC/JMC - YouTube Rewind 2019 For the Record #YouTubeRewind.mp4": "1f1f91f85b162c20596a2413e704b809",
"JMC/JMC - YouTube Rewind 2019 For the Record #YouTubeRewind.nfo": "c64964fab07574080e5da3242e3bfd48"
}

View File

@@ -1,8 +1,9 @@
{
"JMC - YouTube Rewind 2019 For the Record #YouTubeRewind-thumb.jpg": "50ee47c80f679029f5d3503bb91b045a",
"JMC - YouTube Rewind 2019 For the Record #YouTubeRewind.de.srt": "b343c3bb9257b7ee7ba38f570a115b37",
"JMC - YouTube Rewind 2019 For the Record #YouTubeRewind.en.srt": "fe8c6ee92cae6e059fd80fd61691adbe",
"JMC - YouTube Rewind 2019 For the Record #YouTubeRewind.info.json": "089845553911c366198932b30bca5d00",
"JMC - YouTube Rewind 2019 For the Record #YouTubeRewind.mp4": "1f1f91f85b162c20596a2413e704b809",
"JMC - YouTube Rewind 2019 For the Record #YouTubeRewind.nfo": "c64964fab07574080e5da3242e3bfd48"
".ytdl-sub-subtitles_embedded_and_file_test-download-archive.json": "fb48a287b1af0c78d7f79749c0cec9d7",
"JMC/JMC - YouTube Rewind 2019 For the Record #YouTubeRewind-thumb.jpg": "50ee47c80f679029f5d3503bb91b045a",
"JMC/JMC - YouTube Rewind 2019 For the Record #YouTubeRewind.de.srt": "b343c3bb9257b7ee7ba38f570a115b37",
"JMC/JMC - YouTube Rewind 2019 For the Record #YouTubeRewind.en.srt": "fe8c6ee92cae6e059fd80fd61691adbe",
"JMC/JMC - YouTube Rewind 2019 For the Record #YouTubeRewind.info.json": "759e958c5911de5df6ac25887f8e1c6a",
"JMC/JMC - YouTube Rewind 2019 For the Record #YouTubeRewind.mp4": "1f1f91f85b162c20596a2413e704b809",
"JMC/JMC - YouTube Rewind 2019 For the Record #YouTubeRewind.nfo": "c64964fab07574080e5da3242e3bfd48"
}

View File

@@ -1,32 +1,32 @@
{
".ytdl-sub-jb-download-archive.json": "1114f07090dfb35eea6848efeaf9755a",
"j_b/[2021] Baby Santana's Dorian Groove/01 - Baby Santana's Dorian Groove.info.json": "5b1cd3c76846b216eeb5cc3566b0f0a8",
"j_b/[2021] Baby Santana's Dorian Groove/01 - Baby Santana's Dorian Groove.info.json": "b95796948d30558e057a3f2c794c650c",
"j_b/[2021] Baby Santana's Dorian Groove/01 - Baby Santana's Dorian Groove.mp3": "bffbd558e12c6a9e029dc136a88342c4",
"j_b/[2021] Baby Santana's Dorian Groove/folder.jpg": "967892be44b8c47e1be73f055a7c6f08",
"j_b/[2021] Purple Clouds/01 - Purple Clouds.info.json": "2207ed41f248ce72ffe6263df804dd24",
"j_b/[2021] Purple Clouds/01 - Purple Clouds.info.json": "e4d6f7da57a8bc18f82332778ac9b1f0",
"j_b/[2021] Purple Clouds/01 - Purple Clouds.mp3": "038db58aebe2ba875b733932b42a94d6",
"j_b/[2021] Purple Clouds/folder.jpg": "967892be44b8c47e1be73f055a7c6f08",
"j_b/[2022] Acoustic Treats/01 - 20160426 184214.info.json": "d90d8a19209fd3ef9f441c5e9c75a32f",
"j_b/[2022] Acoustic Treats/01 - 20160426 184214.info.json": "4294a791c9e295dcbcb536528215ab2e",
"j_b/[2022] Acoustic Treats/01 - 20160426 184214.mp3": "e145f0a2f6012768280c38655ca58065",
"j_b/[2022] Acoustic Treats/02 - 20160502 123150.info.json": "c4df2eb9a4eecb06f425c73f8dfb98f3",
"j_b/[2022] Acoustic Treats/02 - 20160502 123150.info.json": "9fcdd8984dd286b03d07900240325468",
"j_b/[2022] Acoustic Treats/02 - 20160502 123150.mp3": "60c8b8817a197a13e4bb90903af612c5",
"j_b/[2022] Acoustic Treats/03 - 20160504 143832.info.json": "a4943268aa5a534548c21873f1ed17b8",
"j_b/[2022] Acoustic Treats/03 - 20160504 143832.info.json": "6a3ca21f1cb2f43227fc95355dcaf7ab",
"j_b/[2022] Acoustic Treats/03 - 20160504 143832.mp3": "8265b7e4f79878af877bc6ecd9757efe",
"j_b/[2022] Acoustic Treats/04 - 20160601 221234.info.json": "c5a3e933fef9f041946e3fd58cc40cc5",
"j_b/[2022] Acoustic Treats/04 - 20160601 221234.info.json": "accc54dbf191095e7bf39ab954fc5fa4",
"j_b/[2022] Acoustic Treats/04 - 20160601 221234.mp3": "accf46b76891d2954b893d0f91d82816",
"j_b/[2022] Acoustic Treats/05 - 20160601 222440.info.json": "a46f108c700f577392145a6e58d3766a",
"j_b/[2022] Acoustic Treats/05 - 20160601 222440.info.json": "6c3dff44838b403d67a1229879edd51a",
"j_b/[2022] Acoustic Treats/05 - 20160601 222440.mp3": "e1f584f523336160d5c1104a61de77f3",
"j_b/[2022] Acoustic Treats/06 - 20170604 190236.info.json": "6a78bdb0ed2958f0083ace1c166a363f",
"j_b/[2022] Acoustic Treats/06 - 20170604 190236.info.json": "b37323719f632e5a607e3fe93a220c9b",
"j_b/[2022] Acoustic Treats/06 - 20170604 190236.mp3": "f6885b25901177f0357649afe97328cc",
"j_b/[2022] Acoustic Treats/07 - 20170612 193646.info.json": "84cd8697d8d6876b19ceb35f4b60bcf0",
"j_b/[2022] Acoustic Treats/07 - 20170612 193646.info.json": "af3b911d3d24adfa11810676d50c055c",
"j_b/[2022] Acoustic Treats/07 - 20170612 193646.mp3": "fa057f221cbe4cf2442cd2fdb960743e",
"j_b/[2022] Acoustic Treats/08 - 20170628 215206.info.json": "e5669e3802c0d35ab14435b34929d61a",
"j_b/[2022] Acoustic Treats/08 - 20170628 215206.info.json": "208280c591da9bcc4570b58c36452e23",
"j_b/[2022] Acoustic Treats/08 - 20170628 215206.mp3": "7794ae812c64580e2ac8fc457d5cc85f",
"j_b/[2022] Acoustic Treats/09 - Finding Home.info.json": "5de4bd28ba1f4e67e895f1e4a37fccdd",
"j_b/[2022] Acoustic Treats/09 - Finding Home.info.json": "23ebe28b09ceaac0a8ef64a324d86f76",
"j_b/[2022] Acoustic Treats/09 - Finding Home.mp3": "adbf02eddb2090c008eb497d13ff84b9",
"j_b/[2022] Acoustic Treats/10 - Shallow Water WIP.info.json": "ddb35f4fc41551b68d58b5df62d73bf4",
"j_b/[2022] Acoustic Treats/10 - Shallow Water WIP.info.json": "d1c383d73b067ac6f7888dbb39393263",
"j_b/[2022] Acoustic Treats/10 - Shallow Water WIP.mp3": "65bb10c84366c71498161734f953e93d",
"j_b/[2022] Acoustic Treats/11 - Untold History.info.json": "489da77a730183b0185d262ad4639085",
"j_b/[2022] Acoustic Treats/11 - Untold History.info.json": "edc39b25c8eb95807ab5523272d8c2d6",
"j_b/[2022] Acoustic Treats/11 - Untold History.mp3": "6904b2918e5dc38d9a9f72d967eb74bf",
"j_b/[2022] Acoustic Treats/folder.jpg": "967892be44b8c47e1be73f055a7c6f08"
}

View File

@@ -1,17 +1,17 @@
{
".ytdl-sub-music_video_playlist_test-download-archive.json": "25b8e44961343116436584e341c7fe9b",
"JMC - Jesse's Minecraft Server [Trailer - Feb.1]-thumb.jpg": "b232d253df621aa770b780c1301d364d",
"JMC - Jesse's Minecraft Server [Trailer - Feb.1].info.json": "c73232e03c9e14b62145917cca3a242c",
"JMC - Jesse's Minecraft Server [Trailer - Feb.1].mp4": "7bfa1475504a7c8a4aaa8c89f9306331",
"JMC - Jesse's Minecraft Server [Trailer - Feb.1].nfo": "de6f9a17a5ebf92aa02b14f7342b8d36",
"JMC - Jesse's Minecraft Server [Trailer - Feb.27]-thumb.jpg": "d17c379ea8b362f5b97c6b213b0342cb",
"JMC - Jesse's Minecraft Server [Trailer - Feb.27].info.json": "56ab3eddea58572ffdc33d0945f083b2",
"JMC - Jesse's Minecraft Server [Trailer - Feb.27].mp4": "04ab5cb3cc12325d0c96a7cd04a8b91d",
"JMC - Jesse's Minecraft Server [Trailer - Feb.27].nfo": "9a4a57bb91f1ac97b588fdf66bac4c9b",
"JMC - Jesse's Minecraft Server [Trailer - Mar.21]-thumb.jpg": "e7830aa8a64b0cde65ba3f7e5fc56530",
"JMC - Jesse's Minecraft Server [Trailer - Mar.21].info.json": "f45f60467a0d7a82282ad7e1a481ede2",
"JMC - Jesse's Minecraft Server [Trailer - Mar.21].mp4": "025de6099a5c98e6397153c7a62d517d",
"JMC - Jesse's Minecraft Server [Trailer - Mar.21].nfo": "b98f1fa3e76b4592aeeaed4f6e220809",
".ytdl-sub-music_video_playlist_test-download-archive.json": "e7f7c35e33c132a96d1f12b18f388b35",
"JMC/JMC - Jesse's Minecraft Server [Trailer - Feb.1]-thumb.jpg": "b232d253df621aa770b780c1301d364d",
"JMC/JMC - Jesse's Minecraft Server [Trailer - Feb.1].info.json": "0cfc2ecee75f6f33efac020d0fab44fa",
"JMC/JMC - Jesse's Minecraft Server [Trailer - Feb.1].mp4": "7bfa1475504a7c8a4aaa8c89f9306331",
"JMC/JMC - Jesse's Minecraft Server [Trailer - Feb.1].nfo": "de6f9a17a5ebf92aa02b14f7342b8d36",
"JMC/JMC - Jesse's Minecraft Server [Trailer - Feb.27]-thumb.jpg": "d17c379ea8b362f5b97c6b213b0342cb",
"JMC/JMC - Jesse's Minecraft Server [Trailer - Feb.27].info.json": "6d3d49a3ba25746f786678838a64b485",
"JMC/JMC - Jesse's Minecraft Server [Trailer - Feb.27].mp4": "04ab5cb3cc12325d0c96a7cd04a8b91d",
"JMC/JMC - Jesse's Minecraft Server [Trailer - Feb.27].nfo": "9a4a57bb91f1ac97b588fdf66bac4c9b",
"JMC/JMC - Jesse's Minecraft Server [Trailer - Mar.21]-thumb.jpg": "e7830aa8a64b0cde65ba3f7e5fc56530",
"JMC/JMC - Jesse's Minecraft Server [Trailer - Mar.21].info.json": "19c04838f1aac493ba1eb2b9e933ba1f",
"JMC/JMC - Jesse's Minecraft Server [Trailer - Mar.21].mp4": "025de6099a5c98e6397153c7a62d517d",
"JMC/JMC - Jesse's Minecraft Server [Trailer - Mar.21].nfo": "b98f1fa3e76b4592aeeaed4f6e220809",
"poster.jpg": "e7830aa8a64b0cde65ba3f7e5fc56530",
"tvshow.nfo": "e4123860532466ed5e0ebf2c9e44eb18"
}

View File

@@ -1,6 +1,6 @@
{
"JMC - Oblivion Mod Falcor p.1-thumb.jpg": "fb95b510681676e81c321171fc23143e",
"JMC - Oblivion Mod Falcor p.1.info.json": "7e370795027d99f4db007d84d45cbc43",
"JMC - Oblivion Mod Falcor p.1.mp4": "3744c49f2e447bd7712a5aad5ed36be2",
"JMC - Oblivion Mod Falcor p.1.nfo": "24cc4e17d2bebc89b2759ce5471d403e"
"JMC/JMC - Oblivion Mod Falcor p.1-thumb.jpg": "fb95b510681676e81c321171fc23143e",
"JMC/JMC - Oblivion Mod Falcor p.1.info.json": "1651175b28db7c315df2758e6b66d353",
"JMC/JMC - Oblivion Mod Falcor p.1.mp4": "3744c49f2e447bd7712a5aad5ed36be2",
"JMC/JMC - Oblivion Mod Falcor p.1.nfo": "24cc4e17d2bebc89b2759ce5471d403e"
}

View File

@@ -0,0 +1,6 @@
{
"JMC/JMC - Oblivion Mod Falcor p.1-thumb.jpg": "fb95b510681676e81c321171fc23143e",
"JMC/JMC - Oblivion Mod Falcor p.1.info.json": "8d1bfe968d6eae87462850be79abe13a",
"JMC/JMC - Oblivion Mod Falcor p.1.mp4": "3744c49f2e447bd7712a5aad5ed36be2",
"JMC/JMC - Oblivion Mod Falcor p.1.nfo": "24cc4e17d2bebc89b2759ce5471d403e"
}

View File

@@ -1,6 +1,8 @@
Files created:
----------------------------------------
{output_directory}
.ytdl-sub-file_convert_test-download-archive.json
{output_directory}/Beyond The Guitar
Beyond The Guitar - When you hear Hugh Jackman is returning as Wolverine in Deadpool 3-thumb.jpg
Beyond The Guitar - When you hear Hugh Jackman is returning as Wolverine in Deadpool 3.info.json
Beyond The Guitar - When you hear Hugh Jackman is returning as Wolverine in Deadpool 3.mp4

View File

@@ -1,6 +1,40 @@
Files created:
----------------------------------------
{output_directory}
.ytdl-sub-kodi_safe_xml-download-archive.json
test.nfo
NFO tags:
kodi_safe_root 🎸:
kodi_safe_multi_title 🎸:
- value 1 🎸
- value 2 🎸
kodi_safe_multi_title_with_attrs:
-
attributes:
🎸?:
value
newlines 🎸
tag:
the
tag 1 🎸🎸
-
attributes:
🎸?:
value
newlines 🎸
tag:
the
tag 2 🎸🎸
kodi_safe_title 🎸: kodi_safe_value 🎸
kodi_safe_title_with_attrs:
attributes:
🎸?:
value
newlines 🎸
tag:
the
tag 🎸🎸
{output_directory}/Rick Beato
Rick Beato - Can you hear the difference 🎸🔥 #shorts-thumb.jpg
Rick Beato - Can you hear the difference 🎸🔥 #shorts.info.json
Rick Beato - Can you hear the difference 🎸🔥 #shorts.mp4
@@ -39,36 +73,4 @@ Files created:
the
tag 🎸🎸
title: Can you hear the difference? 🎸🔥 #shorts
year: 2022
test.nfo
NFO tags:
kodi_safe_root 🎸:
kodi_safe_multi_title 🎸:
- value 1 🎸
- value 2 🎸
kodi_safe_multi_title_with_attrs:
-
attributes:
🎸?:
value
newlines 🎸
tag:
the
tag 1 🎸🎸
-
attributes:
🎸?:
value
newlines 🎸
tag:
the
tag 2 🎸🎸
kodi_safe_title 🎸: kodi_safe_value 🎸
kodi_safe_title_with_attrs:
attributes:
🎸?:
value
newlines 🎸
tag:
the
tag 🎸🎸
year: 2022

View File

@@ -1,6 +1,40 @@
Files created:
----------------------------------------
{output_directory}
.ytdl-sub-kodi_safe_xml-download-archive.json
test.nfo
NFO tags:
kodi_safe_root □:
kodi_safe_multi_title □:
- value 1 □
- value 2 □
kodi_safe_multi_title_with_attrs:
-
attributes:
□?:
value
newlines □
tag:
the
tag 1 □□
-
attributes:
□?:
value
newlines □
tag:
the
tag 2 □□
kodi_safe_title □: kodi_safe_value □
kodi_safe_title_with_attrs:
attributes:
□?:
value
newlines □
tag:
the
tag □□
{output_directory}/Rick Beato
Rick Beato - Can you hear the difference 🎸🔥 #shorts-thumb.jpg
Rick Beato - Can you hear the difference 🎸🔥 #shorts.info.json
Rick Beato - Can you hear the difference 🎸🔥 #shorts.mp4
@@ -39,36 +73,4 @@ Files created:
the
tag □□
title: Can you hear the difference? □□ #shorts
year: 2022
test.nfo
NFO tags:
kodi_safe_root □:
kodi_safe_multi_title □:
- value 1 □
- value 2 □
kodi_safe_multi_title_with_attrs:
-
attributes:
□?:
value
newlines □
tag:
the
tag 1 □□
-
attributes:
□?:
value
newlines □
tag:
the
tag 2 □□
kodi_safe_title □: kodi_safe_value □
kodi_safe_title_with_attrs:
attributes:
□?:
value
newlines □
tag:
the
tag □□
year: 2022

View File

@@ -1,17 +1,5 @@
Files created:
----------------------------------------
{output_directory}
01. Intro (Feat. Racheal Ofori & Barney Artist).info.json
02. Answers (Feat. Rick David & Kaya Thomas - Dyke).info.json
03. Blaze (Feat. Kaya Thomas - Dyke).info.json
04. What If (Interlude).info.json
05. No Peace (Feat. Tom Misch).info.json
06. Closer (Feat. Lester Duval).info.json
07. Delusions Rumination (Interlude) (Feat. Racheal Ofori).info.json
08. Dreams (Feat. Carmody).info.json
09. Dreaming (Interlude) (Feat. Racheal Ofori).info.json
10. Hopeful (Feat. Jordan Rakei).info.json
11. Sunrise (Pillows) (Feat. Emmavie).info.json
{output_directory}/Alfa Mist - Nocturne [Full Album]
01 - 01. Intro (Feat. Racheal Ofori & Barney Artist).mp3
From Chapter Split:

View File

@@ -1,17 +1,5 @@
Files created:
----------------------------------------
{output_directory}
01. Intro (Feat. Racheal Ofori & Barney Artist).info.json
02. Answers (Feat. Rick David & Kaya Thomas - Dyke).info.json
03. Blaze (Feat. Kaya Thomas - Dyke).info.json
04. What If (Interlude).info.json
05. No Peace (Feat. Tom Misch).info.json
06. Closer (Feat. Lester Duval).info.json
07. Delusions Rumination (Interlude) (Feat. Racheal Ofori).info.json
08. Dreams (Feat. Carmody).info.json
09. Dreaming (Interlude) (Feat. Racheal Ofori).info.json
10. Hopeful (Feat. Jordan Rakei).info.json
11. Sunrise (Pillows) (Feat. Emmavie).info.json
{output_directory}/Alfa Mist - Nocturne [Full Album]
01 - 01. Intro (Feat. Racheal Ofori & Barney Artist).mp3
From Chapter Split:

View File

@@ -1,7 +1,5 @@
Files created:
----------------------------------------
{output_directory}
Oblivion Mod Falcor p.1.info.json
{output_directory}/Oblivion Mod Falcor p.1
01 - Oblivion Mod Falcor p.1.mp3
Music Tags:

View File

@@ -1,17 +1,5 @@
Files created:
----------------------------------------
{output_directory}
Answers (Feat. Rick David & Kaya Thomas - Dyke).info.json
Blaze (Feat. Kaya Thomas - Dyke).info.json
Closer (Feat. Lester Duval).info.json
Delusions Rumination (Interlude) (Feat. Racheal Ofori).info.json
Dreaming (Interlude) (Feat. Racheal Ofori).info.json
Dreams (Feat. Carmody).info.json
Hopeful (Feat. Jordan Rakei).info.json
Intro (Feat. Racheal Ofori & Barney Artist).info.json
No Peace (Feat. Tom Misch).info.json
Sunrise (Pillows) (Feat. Emmavie).info.json
What If (Interlude).info.json
{output_directory}/Nocturne
01 - Intro (Feat. Racheal Ofori & Barney Artist).mp3
From Chapter Split:

View File

@@ -1,17 +1,5 @@
Files created:
----------------------------------------
{output_directory}
Answers (Feat. Rick David & Kaya Thomas - Dyke).info.json
Blaze (Feat. Kaya Thomas - Dyke).info.json
Closer (Feat. Lester Duval).info.json
Delusions Rumination (Interlude) (Feat. Racheal Ofori).info.json
Dreaming (Interlude) (Feat. Racheal Ofori).info.json
Dreams (Feat. Carmody).info.json
Hopeful (Feat. Jordan Rakei).info.json
Intro (Feat. Racheal Ofori & Barney Artist).info.json
No Peace (Feat. Tom Misch).info.json
Sunrise (Pillows) (Feat. Emmavie).info.json
What If (Interlude).info.json
{output_directory}/Nocturne
01 - Intro (Feat. Racheal Ofori & Barney Artist).mp3
From Chapter Split:

View File

@@ -1,7 +1,6 @@
Files created:
----------------------------------------
{output_directory}
Jesse's Minecraft Server [Trailer - Feb.1].info.json
Jesse's Minecraft Server [Trailer - Feb.1].ogg
Music Tags:
album: Singles
@@ -11,7 +10,6 @@ Files created:
title: Jesse's Minecraft Server [Trailer - Feb.1]
track: 3
year: 2011
Jesse's Minecraft Server [Trailer - Feb.27].info.json
Jesse's Minecraft Server [Trailer - Feb.27].ogg
Music Tags:
album: Singles
@@ -21,7 +19,6 @@ Files created:
title: Jesse's Minecraft Server [Trailer - Feb.27]
track: 2
year: 2011
Jesse's Minecraft Server [Trailer - Mar.21].info.json
Jesse's Minecraft Server [Trailer - Mar.21].ogg
Music Tags:
album: Singles

View File

@@ -1,7 +1,6 @@
Files created:
----------------------------------------
{output_directory}
YouTube Rewind 2019 For the Record #YouTubeRewind.info.json
YouTube Rewind 2019 For the Record #YouTubeRewind.mp3
Music Tags:
album: Singles

View File

@@ -1,6 +1,8 @@
Files created:
----------------------------------------
{output_directory}
.ytdl-sub-chapters_from_timestamps_with_subs-download-archive.json
{output_directory}/JMC
JMC - This GPU SLIDES into this Case! - Silverstone SUGO 16 ITX Case-thumb.jpg
JMC - This GPU SLIDES into this Case! - Silverstone SUGO 16 ITX Case.info.json
JMC - This GPU SLIDES into this Case! - Silverstone SUGO 16 ITX Case.mp4

View File

@@ -1,6 +1,8 @@
Files created:
----------------------------------------
{output_directory}
.ytdl-sub-sponsorblock_with_embedded_subs_test-download-archive.json
{output_directory}/JMC
JMC - This GPU SLIDES into this Case! - Silverstone SUGO 16 ITX Case-thumb.jpg
JMC - This GPU SLIDES into this Case! - Silverstone SUGO 16 ITX Case.info.json
JMC - This GPU SLIDES into this Case! - Silverstone SUGO 16 ITX Case.mp4

View File

@@ -2,6 +2,7 @@ Files created:
----------------------------------------
{output_directory}
.ytdl-sub-regex_capture_playlist_test-download-archive.json
{output_directory}/Project Zombie
Project Zombie - Jesse's Minecraft Server [Trailer - Feb.1]-thumb.jpg
Project Zombie - Jesse's Minecraft Server [Trailer - Feb.1].info.json
Project Zombie - Jesse's Minecraft Server [Trailer - Feb.1].mp4

View File

@@ -1,6 +1,8 @@
Files created:
----------------------------------------
{output_directory}
.ytdl-sub-subtitles_embedded_test-download-archive.json
{output_directory}/JMC
JMC - YouTube Rewind 2019 For the Record #YouTubeRewind-thumb.jpg
JMC - YouTube Rewind 2019 For the Record #YouTubeRewind.info.json
JMC - YouTube Rewind 2019 For the Record #YouTubeRewind.mp4

View File

@@ -1,6 +1,8 @@
Files created:
----------------------------------------
{output_directory}
.ytdl-sub-subtitles_embedded_and_file_test-download-archive.json
{output_directory}/JMC
JMC - YouTube Rewind 2019 For the Record #YouTubeRewind-thumb.jpg
JMC - YouTube Rewind 2019 For the Record #YouTubeRewind.de.srt
JMC - YouTube Rewind 2019 For the Record #YouTubeRewind.en.srt

View File

@@ -2,6 +2,14 @@ Files created:
----------------------------------------
{output_directory}
.ytdl-sub-music_video_playlist_test-download-archive.json
poster.jpg
tvshow.nfo
NFO tags:
test:
playlist_description: Trailers, Updates, etc
playlist_title: Jesse's Minecraft Server
playlist_uploader: Project Zombie
{output_directory}/JMC
JMC - Jesse's Minecraft Server [Trailer - Feb.1]-thumb.jpg
JMC - Jesse's Minecraft Server [Trailer - Feb.1].info.json
JMC - Jesse's Minecraft Server [Trailer - Feb.1].mp4
@@ -37,11 +45,4 @@ Files created:
playlist_count: 3
playlist_index: 1
title: Jesse's Minecraft Server [Trailer - Mar.21]
year: 2011
poster.jpg
tvshow.nfo
NFO tags:
test:
playlist_description: Trailers, Updates, etc
playlist_title: Jesse's Minecraft Server
playlist_uploader: Project Zombie
year: 2011

View File

@@ -1,6 +1,6 @@
Files created:
----------------------------------------
{output_directory}
{output_directory}/JMC
JMC - Oblivion Mod Falcor p.1-thumb.jpg
JMC - Oblivion Mod Falcor p.1.info.json
JMC - Oblivion Mod Falcor p.1.mp4

View File

@@ -0,0 +1,15 @@
Files created:
----------------------------------------
{output_directory}/JMC
JMC - Oblivion Mod Falcor p.1-thumb.jpg
JMC - Oblivion Mod Falcor p.1.info.json
JMC - Oblivion Mod Falcor p.1.mp4
Video Tags:
title: Oblivion Mod "Falcor" p.1
JMC - Oblivion Mod Falcor p.1.nfo
NFO tags:
musicvideo:
album: Music Videos
artist: JMC
title: Oblivion Mod "Falcor" p.1
year: 2010

View File

@@ -44,9 +44,9 @@ class TestDownloadArgsParser:
"aliases, cmd, expected_sub_dict",
[
(
{"mv": "--preset yt_music_video", "v": "--youtube.video_url"},
{"mv": "--preset music_video", "v": "--download.url"},
"dl --mv --v 123abc",
{"preset": "yt_music_video", "youtube": {"video_url": "123abc"}},
{"preset": "music_video", "download": {"url": "123abc"}},
),
(
{