[DEV] More OutputOption unit tests (#1082)

This commit is contained in:
Jesse Bannon 2024-10-02 21:37:54 -07:00 committed by GitHub
parent ed4a2814b9
commit c0ba30b220
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
24 changed files with 663 additions and 297 deletions

View file

@ -161,7 +161,7 @@ def _download_subscription_from_cli(
extra_arguments=extra_args, config_options=config.config_options
)
subscription_args_dict = dl_args_parser.to_subscription_dict()
subscription_name = f"cli-dl-{dl_args_parser.get_args_hash()}"
subscription_name = dl_args_parser.get_dl_subscription_name()
subscription = Subscription.from_dict(
config=config, preset_name=subscription_name, preset_dict=subscription_args_dict

View file

@ -242,12 +242,13 @@ class DownloadArgsParser:
return subscription_dict
def get_args_hash(self) -> str:
def get_dl_subscription_name(self) -> str:
"""
:return: Hash of the arguments provided
Returns a deterministic name based on input args
"""
hash_string = str(sorted(self._unknown_arguments))
return hashlib.sha256(hash_string.encode()).hexdigest()[-8:]
to_hash = str(sorted(self._unknown_arguments))
hash_str = hashlib.sha256(to_hash.encode()).hexdigest()[-8:]
return f"cli-dl-{hash_str}"
@classmethod
def from_dl_override(cls, override: str, config: ConfigFile) -> "DownloadArgsParser":

View file

@ -2,7 +2,9 @@ import contextlib
import json
import logging
import os
import shlex
import shutil
import sys
import tempfile
from pathlib import Path
from typing import Any
@ -18,8 +20,10 @@ from resources import copy_file_fixture
from resources import file_fixture_path
from yt_dlp.utils import sanitize_filename
from ytdl_sub.cli.entrypoint import main
from ytdl_sub.config.config_file import ConfigFile
from ytdl_sub.entries.script.custom_functions import CustomFunctions
from ytdl_sub.subscriptions.subscription import Subscription
from ytdl_sub.subscriptions.subscription_download import SubscriptionDownload
from ytdl_sub.utils.file_handler import FileHandler
from ytdl_sub.utils.logger import Logger
@ -262,3 +266,9 @@ def default_config_path(default_config) -> str:
@pytest.fixture()
def music_subscriptions_path() -> Path:
return Path("examples/music_subscriptions.yaml")
def mock_run_from_cli(args: str) -> List[Subscription]:
args_list = ["ytdl-sub"] + shlex.split(args)
with patch.object(sys, "argv", args_list):
return main()

View file

@ -1,13 +1,7 @@
import shlex
import sys
import tempfile
from typing import List
from unittest.mock import patch
import pytest
from ytdl_sub.cli.entrypoint import main
from ytdl_sub.subscriptions.subscription import Subscription
from ytdl_sub.utils.file_handler import FileHandler
@ -31,9 +25,3 @@ def timestamps_file_path():
yield tmp.name
finally:
FileHandler.delete(tmp.name)
def mock_run_from_cli(args: str) -> List[Subscription]:
args_list = ["ytdl-sub"] + shlex.split(args)
with patch.object(sys, "argv", args_list):
return main()

View file

@ -1,7 +1,7 @@
from typing import Optional
import pytest
from e2e.conftest import mock_run_from_cli
from conftest import mock_run_from_cli
from ytdl_sub.utils.file_handler import FileMetadata

View file

@ -1,17 +1,13 @@
from pathlib import Path
from typing import Dict
import pytest
from conftest import assert_logs
from e2e.conftest import mock_run_from_cli
from expected_download import assert_expected_downloads
from expected_transaction_log import assert_transaction_log_matches
from mergedeep import mergedeep
from ytdl_sub.config.config_file import ConfigFile
from ytdl_sub.downloaders.ytdlp import YTDLP
from ytdl_sub.subscriptions.subscription import Subscription
from ytdl_sub.utils.system import IS_WINDOWS
@pytest.fixture
@ -100,50 +96,6 @@ class TestPlaylist:
files exist and have the expected md5 file hashes.
"""
@classmethod
def _ensure_subscription_migrates(
cls,
config: ConfigFile,
subscription_name: str,
subscription_dict: Dict,
output_directory: Path,
):
# Ensure download archive migrates
mergedeep.merge(
subscription_dict,
{
"output_options": {
"migrated_download_archive_name": ".ytdl-sub-{tv_show_name_sanitized}-download-archive.json"
}
},
)
migrated_subscription = Subscription.from_dict(
config=config,
preset_name=subscription_name,
preset_dict=subscription_dict,
)
transaction_log = migrated_subscription.download()
assert_transaction_log_matches(
output_directory=output_directory,
transaction_log=transaction_log,
transaction_log_summary_file_name="youtube/test_playlist_archive_migrated.txt",
)
assert_expected_downloads(
output_directory=output_directory,
dry_run=False,
expected_download_summary_file_name="youtube/test_playlist_archive_migrated.json",
)
# Ensure no changes after migration
transaction_log = migrated_subscription.download()
assert transaction_log.is_empty
assert_expected_downloads(
output_directory=output_directory,
dry_run=False,
expected_download_summary_file_name="youtube/test_playlist_archive_migrated.json",
)
@pytest.mark.parametrize("dry_run", [True, False])
def test_playlist_download(
self,
@ -186,86 +138,6 @@ class TestPlaylist:
expected_download_summary_file_name="youtube/test_playlist.json",
)
self._ensure_subscription_migrates(
config=default_config,
subscription_name="music_video_playlist_test",
subscription_dict=playlist_preset_dict,
output_directory=output_directory,
)
@pytest.mark.parametrize("dry_run", [True, False])
def test_playlist_download_from_cli_sub_no_provided_config(
self,
preset_dict_to_subscription_yaml_generator,
playlist_preset_dict,
output_directory,
dry_run,
):
# TODO: Fix CLI parsing on windows when dealing with spaces
if IS_WINDOWS:
return
# No config needed when using only prebuilt presets
with preset_dict_to_subscription_yaml_generator(
subscription_name="music_video_playlist_test", preset_dict=playlist_preset_dict
) as subscription_path:
args = "--dry-run " if dry_run else ""
args += f"sub '{subscription_path}'"
subscriptions = mock_run_from_cli(args=args)
assert len(subscriptions) == 1
transaction_log = subscriptions[0].transaction_log
assert_transaction_log_matches(
output_directory=output_directory,
transaction_log=transaction_log,
transaction_log_summary_file_name="youtube/test_playlist.txt",
)
assert_expected_downloads(
output_directory=output_directory,
dry_run=dry_run,
expected_download_summary_file_name="youtube/test_playlist.json",
)
if not dry_run:
# Ensure another invocation will hit ExistingVideoReached
with assert_logs(
logger=YTDLP.logger,
expected_message="ExistingVideoReached, stopping additional downloads",
log_level="debug",
):
transaction_log = mock_run_from_cli(args=args)[0].transaction_log
assert transaction_log.is_empty
assert_expected_downloads(
output_directory=output_directory,
dry_run=dry_run,
expected_download_summary_file_name="youtube/test_playlist.json",
)
def test_playlist_download_from_cli_sub_with_override_arg(
self,
preset_dict_to_subscription_yaml_generator,
playlist_preset_dict,
output_directory,
):
# TODO: Fix CLI parsing on windows when dealing with spaces
if IS_WINDOWS:
return
# No config needed when using only prebuilt presets
with preset_dict_to_subscription_yaml_generator(
subscription_name="music_video_playlist_test", preset_dict=playlist_preset_dict
) as subscription_path:
args = (
f"--dry-run sub '{subscription_path}' --dl-override '--date_range.after 20240101'"
)
subscriptions = mock_run_from_cli(args=args)
assert len(subscriptions) == 1
assert subscriptions[0].transaction_log.is_empty
def test_tv_show_by_date_downloads_bilateral(
self,
tv_show_by_date_bilateral_dict: Dict,

View file

@ -1,17 +1,9 @@
from unittest.mock import patch
import pytest
from conftest import preset_dict_to_dl_args
from e2e.conftest import mock_run_from_cli
from expected_download import assert_expected_downloads
from expected_transaction_log import assert_transaction_log_matches
from ytdl_sub.downloaders.ytdlp import YTDLP
from ytdl_sub.entries.entry import Entry
from ytdl_sub.subscriptions.subscription import Subscription
from ytdl_sub.utils.file_handler import FileHandler
from ytdl_sub.utils.system import IS_WINDOWS
from ytdl_sub.utils.thumbnail import try_convert_download_thumbnail
@pytest.fixture
@ -69,72 +61,3 @@ class TestYoutubeVideo:
dry_run=dry_run,
expected_download_summary_file_name="youtube/test_video.json",
)
def test_single_video_download_missing_thumbnail(
self,
default_config,
single_video_preset_dict,
working_directory,
output_directory,
):
single_video_subscription = Subscription.from_dict(
config=default_config,
preset_name="music_video_single_video_test",
preset_dict=single_video_preset_dict,
)
def delete_entry_thumb(entry: Entry) -> None:
FileHandler.delete(entry.get_download_thumbnail_path())
try_convert_download_thumbnail(entry=entry)
# Pretend the thumbnail did not download via returning nothing for its downloaded path
with (
patch.object(YTDLP, "_EXTRACT_ENTRY_NUM_RETRIES", 1),
patch.object(Entry, "try_get_ytdlp_download_thumbnail_path") as mock_ytdlp_path,
patch(
"ytdl_sub.downloaders.url.downloader.try_convert_download_thumbnail",
side_effect=delete_entry_thumb,
),
):
mock_ytdlp_path.return_value = None
transaction_log = single_video_subscription.download(dry_run=False)
assert_transaction_log_matches(
output_directory=output_directory,
transaction_log=transaction_log,
transaction_log_summary_file_name="youtube/test_video_missing_thumb.txt",
)
assert_expected_downloads(
output_directory=output_directory,
dry_run=False,
expected_download_summary_file_name="youtube/test_video_missing_thumb.json",
)
@pytest.mark.parametrize("dry_run", [True, False])
def test_single_video_download_from_cli_dl(
self,
default_config_path,
single_video_preset_dict_dl_args,
output_directory,
dry_run,
):
# TODO: Fix CLI parsing on windows when dealing with spaces
if IS_WINDOWS:
return
args = "--dry-run " if dry_run else ""
args += f"--config {default_config_path} "
args += f"dl {single_video_preset_dict_dl_args}"
subscriptions = mock_run_from_cli(args=args)
assert len(subscriptions) == 1
assert_transaction_log_matches(
output_directory=output_directory,
transaction_log=subscriptions[0].transaction_log,
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_cli.json",
)

View file

@ -0,0 +1,73 @@
from typing import Dict
from unittest.mock import patch
import pytest
from conftest import mock_run_from_cli
from conftest import preset_dict_to_dl_args
from expected_download import assert_expected_downloads
from expected_transaction_log import assert_transaction_log_matches
from ytdl_sub.cli.parsers.dl import DownloadArgsParser
from ytdl_sub.utils.system import IS_WINDOWS
@pytest.fixture
def dl_subscription_dict(output_directory) -> Dict:
return {
"preset": "Jellyfin Music Videos",
"overrides": {
"music_video_artist": "JMC",
"music_video_directory": output_directory,
"url": "https://your.name.here",
},
"nfo_tags": {"tags": {"custom_tag": "{%array_at( ['hi', 'mom'], 1 )}"}},
}
class TestCliDl:
@pytest.mark.parametrize("config_provided", [True, False])
@pytest.mark.parametrize("dry_run", [True, False])
def test_cli_dl_command(
self,
default_config_path: str,
subscription_name: str,
dl_subscription_dict: Dict,
output_directory: str,
mock_download_collection_entries,
config_provided: bool,
dry_run: bool,
):
# Skip this combo to save time and to avoid mocking working dir
if not config_provided and not dry_run:
return
# TODO: Fix CLI parsing on windows when dealing with spaces
if IS_WINDOWS:
return
args = "--dry-run " if dry_run else ""
args += f"--config {default_config_path} " if config_provided else ""
args += f"dl {preset_dict_to_dl_args(dl_subscription_dict)} "
with (
patch.object(DownloadArgsParser, "get_dl_subscription_name") as mock_subscription_name,
mock_download_collection_entries(
is_youtube_channel=False,
num_urls=1,
is_extracted_audio=False,
is_dry_run=dry_run,
),
):
mock_subscription_name.return_value = subscription_name
subscriptions = mock_run_from_cli(args=args)
assert_transaction_log_matches(
output_directory=output_directory,
transaction_log=subscriptions[0].transaction_log,
transaction_log_summary_file_name="dl/test_cli_dl_command.txt",
)
assert_expected_downloads(
output_directory=output_directory,
dry_run=dry_run,
expected_download_summary_file_name="dl/test_cli_dl_command.json",
)

View file

@ -145,6 +145,8 @@ def mock_download_collection_entries(
# Second TV URL or second soundcloud URL, which downloads first
is_second_url = "2" in kwargs["url"] or kwargs["url"].endswith("/albums")
if num_urls == 0:
return []
if num_urls == 1 or (is_second_url and num_urls > 1):
return [
mock_entry_dict_factory(

View file

@ -1,11 +1,18 @@
from pathlib import Path
from typing import Dict
from unittest.mock import patch
import pytest
from expected_download import assert_expected_downloads
from expected_transaction_log import assert_transaction_log_matches
from mergedeep import mergedeep
from ytdl_sub.config.config_file import ConfigFile
from ytdl_sub.downloaders.ytdlp import YTDLP
from ytdl_sub.entries.entry import Entry
from ytdl_sub.subscriptions.subscription import Subscription
from ytdl_sub.utils.file_handler import FileHandler
from ytdl_sub.utils.thumbnail import try_convert_download_thumbnail
@pytest.fixture
@ -27,6 +34,110 @@ def output_options_subscription_dict(output_directory) -> Dict:
class TestOutputOptions:
@classmethod
def _ensure_subscription_migrates(
cls,
config: ConfigFile,
subscription_name: str,
subscription_dict: Dict,
output_directory: Path,
):
# Ensure download archive migrates
mergedeep.merge(
subscription_dict,
{
"output_options": {
"migrated_download_archive_name": ".ytdl-sub-{tv_show_name_sanitized}-download-archive.json"
}
},
)
migrated_subscription = Subscription.from_dict(
config=config,
preset_name=subscription_name,
preset_dict=subscription_dict,
)
transaction_log = migrated_subscription.download()
assert_transaction_log_matches(
output_directory=output_directory,
transaction_log=transaction_log,
transaction_log_summary_file_name="youtube/test_playlist_archive_migrated.txt",
)
assert_expected_downloads(
output_directory=output_directory,
dry_run=False,
expected_download_summary_file_name="youtube/test_playlist_archive_migrated.json",
)
# Ensure no changes after migration
transaction_log = migrated_subscription.download()
assert transaction_log.is_empty
assert_expected_downloads(
output_directory=output_directory,
dry_run=False,
expected_download_summary_file_name="youtube/test_playlist_archive_migrated.json",
)
def test_download_archive_migration(
self,
config: ConfigFile,
subscription_name: str,
output_options_subscription_dict: Dict,
output_directory: str,
mock_download_collection_entries,
):
subscription = Subscription.from_dict(
config=config,
preset_name=subscription_name,
preset_dict=output_options_subscription_dict,
)
with mock_download_collection_entries(
is_youtube_channel=False,
num_urls=1,
is_extracted_audio=False,
is_dry_run=False,
):
transaction_log = subscription.download(dry_run=False)
assert_transaction_log_matches(
output_directory=output_directory,
transaction_log=transaction_log,
transaction_log_summary_file_name="plugins/output_options/pre_migration.txt",
)
assert_expected_downloads(
output_directory=output_directory,
dry_run=False,
expected_download_summary_file_name="plugins/output_options/pre_migration.json",
)
output_options_subscription_dict["output_options"][
"migrated_download_archive_name"
] = ".ytdl-sub-{tv_show_name_sanitized}-migrated-download-archive.json"
subscription = Subscription.from_dict(
config=config,
preset_name=subscription_name,
preset_dict=output_options_subscription_dict,
)
with mock_download_collection_entries(
is_youtube_channel=False,
num_urls=0,
):
transaction_log = subscription.download(dry_run=False)
assert_transaction_log_matches(
output_directory=output_directory,
transaction_log=transaction_log,
transaction_log_summary_file_name="plugins/output_options/post_migration.txt",
)
assert_expected_downloads(
output_directory=output_directory,
dry_run=False,
expected_download_summary_file_name="plugins/output_options/post_migration.json",
)
@pytest.mark.parametrize("dry_run", [True, False])
def test_empty_info_json_and_thumb(
self,
@ -64,3 +175,51 @@ class TestOutputOptions:
dry_run=dry_run,
expected_download_summary_file_name="plugins/output_options/empty_info_json_thumb.json",
)
def test_missing_thumbnail(
self,
config: ConfigFile,
subscription_name: str,
output_options_subscription_dict: Dict,
working_directory,
output_directory,
mock_download_collection_entries,
):
single_video_subscription = Subscription.from_dict(
config=config,
preset_name=subscription_name,
preset_dict=output_options_subscription_dict,
)
def delete_entry_thumb(entry: Entry) -> None:
FileHandler.delete(entry.get_download_thumbnail_path())
try_convert_download_thumbnail(entry=entry)
# Pretend the thumbnail did not download via returning nothing for its downloaded path
with (
mock_download_collection_entries(
is_youtube_channel=False,
num_urls=1,
is_extracted_audio=False,
is_dry_run=False,
),
patch.object(YTDLP, "_EXTRACT_ENTRY_NUM_RETRIES", 1),
patch.object(Entry, "try_get_ytdlp_download_thumbnail_path") as mock_ytdlp_path,
patch(
"ytdl_sub.downloaders.url.downloader.try_convert_download_thumbnail",
side_effect=delete_entry_thumb,
),
):
mock_ytdlp_path.return_value = None
transaction_log = single_video_subscription.download(dry_run=False)
assert_transaction_log_matches(
output_directory=output_directory,
transaction_log=transaction_log,
transaction_log_summary_file_name="plugins/output_options/test_missing_thumb.txt",
)
assert_expected_downloads(
output_directory=output_directory,
dry_run=False,
expected_download_summary_file_name="plugins/output_options/test_missing_thumb.json",
)

View file

@ -0,0 +1,19 @@
{
".ytdl-sub-subscription_test-download-archive.json": "76e202bd03ceef93daaffffee2cfa193",
"JMC/Mock Entry 20-1.info.json": "INFO_JSON",
"JMC/Mock Entry 20-1.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"JMC/Mock Entry 20-1.mp4": "dbaeb2a3bfd1de1c7e9615e8bdacb910",
"JMC/Mock Entry 20-1.nfo": "5d001a105d2380844db181911d5df5c6",
"JMC/Mock Entry 20-2.info.json": "INFO_JSON",
"JMC/Mock Entry 20-2.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"JMC/Mock Entry 20-2.mp4": "76c2c70572489c684923a51cb1b50687",
"JMC/Mock Entry 20-2.nfo": "dccdded1ca7ebb38d2c9a0e5130bea33",
"JMC/Mock Entry 20-3.info.json": "INFO_JSON",
"JMC/Mock Entry 20-3.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"JMC/Mock Entry 20-3.mp4": "7bb4f21d59a6fb91836537b27a24e776",
"JMC/Mock Entry 20-3.nfo": "7b1eab48693161e83c21203b1308b64e",
"JMC/Mock Entry 21-1.info.json": "INFO_JSON",
"JMC/Mock Entry 21-1.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"JMC/Mock Entry 21-1.mp4": "7b008531ca5660b51fb8adc83c799084",
"JMC/Mock Entry 21-1.nfo": "3b4b0e6820f80370d6738ce828f14a89"
}

View file

@ -0,0 +1,20 @@
{
".ytdl-sub-JMC-migrated-download-archive.json": "456d8882fc5e35d74f19b386d1d9a059",
"Season 2020/s2020.e000001 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Season 2020/s2020.e000001 - Mock Entry 20-3.info.json": "INFO_JSON",
"Season 2020/s2020.e000001 - Mock Entry 20-3.mp4": "7d2ee7fe8003ea63ece37dd2a441c123",
"Season 2020/s2020.e000001 - Mock Entry 20-3.nfo": "dbe61f2c8ae41041773f713ba5376726",
"Season 2020/s2020.e000002 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Season 2020/s2020.e000002 - Mock Entry 20-2.info.json": "INFO_JSON",
"Season 2020/s2020.e000002 - Mock Entry 20-2.mp4": "699017cd1b67ae216eda769bef413415",
"Season 2020/s2020.e000002 - Mock Entry 20-2.nfo": "0f071078c9fa2569bbcb998664d40681",
"Season 2020/s2020.e000003 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Season 2020/s2020.e000003 - Mock Entry 20-1.info.json": "INFO_JSON",
"Season 2020/s2020.e000003 - Mock Entry 20-1.mp4": "a16741d4fbf657d1de4c50493db14062",
"Season 2020/s2020.e000003 - Mock Entry 20-1.nfo": "837a61dca11bbe1874ea07cb8ef8a7c9",
"Season 2021/s2021.e000004 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Season 2021/s2021.e000004 - Mock Entry 21-1.info.json": "INFO_JSON",
"Season 2021/s2021.e000004 - Mock Entry 21-1.mp4": "7433153952b069a5674e2a3ed529b49b",
"Season 2021/s2021.e000004 - Mock Entry 21-1.nfo": "8ee3845c514a411425b7e9198666b61c",
"tvshow.nfo": "cccca1086b41af04d8ea004b1aa250e8"
}

View file

@ -0,0 +1,20 @@
{
".ytdl-sub-subscription_test-download-archive.json": "456d8882fc5e35d74f19b386d1d9a059",
"Season 2020/s2020.e000001 - Mock Entry 20-3-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Season 2020/s2020.e000001 - Mock Entry 20-3.info.json": "INFO_JSON",
"Season 2020/s2020.e000001 - Mock Entry 20-3.mp4": "7d2ee7fe8003ea63ece37dd2a441c123",
"Season 2020/s2020.e000001 - Mock Entry 20-3.nfo": "dbe61f2c8ae41041773f713ba5376726",
"Season 2020/s2020.e000002 - Mock Entry 20-2-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Season 2020/s2020.e000002 - Mock Entry 20-2.info.json": "INFO_JSON",
"Season 2020/s2020.e000002 - Mock Entry 20-2.mp4": "699017cd1b67ae216eda769bef413415",
"Season 2020/s2020.e000002 - Mock Entry 20-2.nfo": "0f071078c9fa2569bbcb998664d40681",
"Season 2020/s2020.e000003 - Mock Entry 20-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Season 2020/s2020.e000003 - Mock Entry 20-1.info.json": "INFO_JSON",
"Season 2020/s2020.e000003 - Mock Entry 20-1.mp4": "a16741d4fbf657d1de4c50493db14062",
"Season 2020/s2020.e000003 - Mock Entry 20-1.nfo": "837a61dca11bbe1874ea07cb8ef8a7c9",
"Season 2021/s2021.e000004 - Mock Entry 21-1-thumb.jpg": "e80c508c4818454300133fe1dc1a9cd7",
"Season 2021/s2021.e000004 - Mock Entry 21-1.info.json": "INFO_JSON",
"Season 2021/s2021.e000004 - Mock Entry 21-1.mp4": "7433153952b069a5674e2a3ed529b49b",
"Season 2021/s2021.e000004 - Mock Entry 21-1.nfo": "8ee3845c514a411425b7e9198666b61c",
"tvshow.nfo": "cccca1086b41af04d8ea004b1aa250e8"
}

View file

@ -0,0 +1,16 @@
{
".ytdl-sub-subscription_test-download-archive.json": "e049068ba7f5bdc27c474b18f4c6b402",
"Season 2020/s2020.e000001 - Mock Entry 20-3.info.json": "INFO_JSON",
"Season 2020/s2020.e000001 - Mock Entry 20-3.mp4": "7d2ee7fe8003ea63ece37dd2a441c123",
"Season 2020/s2020.e000001 - Mock Entry 20-3.nfo": "dbe61f2c8ae41041773f713ba5376726",
"Season 2020/s2020.e000002 - Mock Entry 20-2.info.json": "INFO_JSON",
"Season 2020/s2020.e000002 - Mock Entry 20-2.mp4": "699017cd1b67ae216eda769bef413415",
"Season 2020/s2020.e000002 - Mock Entry 20-2.nfo": "0f071078c9fa2569bbcb998664d40681",
"Season 2020/s2020.e000003 - Mock Entry 20-1.info.json": "INFO_JSON",
"Season 2020/s2020.e000003 - Mock Entry 20-1.mp4": "a16741d4fbf657d1de4c50493db14062",
"Season 2020/s2020.e000003 - Mock Entry 20-1.nfo": "837a61dca11bbe1874ea07cb8ef8a7c9",
"Season 2021/s2021.e000004 - Mock Entry 21-1.info.json": "INFO_JSON",
"Season 2021/s2021.e000004 - Mock Entry 21-1.mp4": "7433153952b069a5674e2a3ed529b49b",
"Season 2021/s2021.e000004 - Mock Entry 21-1.nfo": "8ee3845c514a411425b7e9198666b61c",
"tvshow.nfo": "cccca1086b41af04d8ea004b1aa250e8"
}

View file

@ -1,19 +0,0 @@
{
"JMC/.ytdl-sub-JMC-download-archive.json": "3fdab8d103e51aa70430b6da0ceb07e2",
"JMC/Season 01/s01.e11020101 - Jesse's Minecraft Server [Trailer - Feb.1]-thumb.jpg": "b232d253df621aa770b780c1301d364d",
"JMC/Season 01/s01.e11020101 - Jesse's Minecraft Server [Trailer - Feb.1].info.json": "INFO_JSON",
"JMC/Season 01/s01.e11020101 - Jesse's Minecraft Server [Trailer - Feb.1].mp4": "7fa67dd3a895da12c17669b0fa2f3763",
"JMC/Season 01/s01.e11020101 - Jesse's Minecraft Server [Trailer - Feb.1].nfo": "2a2997cbf16fb6b943d9933ad267331e",
"JMC/Season 01/s01.e11022701 - Jesse's Minecraft Server [Trailer - Feb.27]-thumb.jpg": "d17c379ea8b362f5b97c6b213b0342cb",
"JMC/Season 01/s01.e11022701 - Jesse's Minecraft Server [Trailer - Feb.27].info.json": "INFO_JSON",
"JMC/Season 01/s01.e11022701 - Jesse's Minecraft Server [Trailer - Feb.27].mp4": "5a3ffa5cee2f58f5001502ab3823d130",
"JMC/Season 01/s01.e11022701 - Jesse's Minecraft Server [Trailer - Feb.27].nfo": "da7645e8826586388ae0d8278ef6a1c1",
"JMC/Season 01/s01.e11032101 - Jesse's Minecraft Server [Trailer - Mar.21]-thumb.jpg": "e7830aa8a64b0cde65ba3f7e5fc56530",
"JMC/Season 01/s01.e11032101 - Jesse's Minecraft Server [Trailer - Mar.21].info.json": "INFO_JSON",
"JMC/Season 01/s01.e11032101 - Jesse's Minecraft Server [Trailer - Mar.21].mp4": "91f22944f797513fcda9856e244dd3b3",
"JMC/Season 01/s01.e11032101 - Jesse's Minecraft Server [Trailer - Mar.21].nfo": "c56083e2f3545fa2cafc4d67cbfdacf8",
"JMC/fanart.jpg": "129c6639b47299bc48062f0365e670ee",
"JMC/poster.jpg": "5de28eea5a921a041452ab3ce1041f73",
"JMC/season01-poster.jpg": "e7830aa8a64b0cde65ba3f7e5fc56530",
"JMC/tvshow.nfo": "e92e4a2c01522dd9a9c3423f0f9304dc"
}

View file

@ -1,6 +0,0 @@
{
"JMC/Oblivion Mod Falcor p.1.info.json": "INFO_JSON",
"JMC/Oblivion Mod Falcor p.1.jpg": "fb95b510681676e81c321171fc23143e",
"JMC/Oblivion Mod Falcor p.1.mp4": "318faf3eb1d7666491553cdfd2a2e9fb",
"JMC/Oblivion Mod Falcor p.1.nfo": "58c2be339869b5d071c1758d55c72ddb"
}

View file

@ -1,5 +0,0 @@
{
"JMC/Oblivion Mod Falcor p.1.info.json": "INFO_JSON",
"JMC/Oblivion Mod Falcor p.1.mp4": "d3bdda5ec6822ea3b4b4bd8908eb327a",
"JMC/Oblivion Mod Falcor p.1.nfo": "58c2be339869b5d071c1758d55c72ddb"
}

View file

@ -0,0 +1,81 @@
Files created:
----------------------------------------
{output_directory}
.ytdl-sub-subscription_test-download-archive.json
{output_directory}/JMC
Mock Entry 20-1.info.json
Mock Entry 20-1.jpg
Mock Entry 20-1.mp4
Video Tags:
album: Music Videos
artist: JMC
genre: ytdl-sub
premiered: 2020-08-08
title: Mock Entry 20-1
year: 2020
Mock Entry 20-1.nfo
NFO tags:
musicvideo:
album: Music Videos
artist: JMC
custom_tag: mom
genre: ytdl-sub
premiered: 2020-08-08
title: Mock Entry 20-1
Mock Entry 20-2.info.json
Mock Entry 20-2.jpg
Mock Entry 20-2.mp4
Video Tags:
album: Music Videos
artist: JMC
genre: ytdl-sub
premiered: 2020-08-08
title: Mock Entry 20-2
year: 2020
Mock Entry 20-2.nfo
NFO tags:
musicvideo:
album: Music Videos
artist: JMC
custom_tag: mom
genre: ytdl-sub
premiered: 2020-08-08
title: Mock Entry 20-2
Mock Entry 20-3.info.json
Mock Entry 20-3.jpg
Mock Entry 20-3.mp4
Video Tags:
album: Music Videos
artist: JMC
genre: ytdl-sub
premiered: 2020-08-07
title: Mock Entry 20-3
year: 2020
Mock Entry 20-3.nfo
NFO tags:
musicvideo:
album: Music Videos
artist: JMC
custom_tag: mom
genre: ytdl-sub
premiered: 2020-08-07
title: Mock Entry 20-3
Mock Entry 21-1.info.json
Mock Entry 21-1.jpg
Mock Entry 21-1.mp4
Video Tags:
album: Music Videos
artist: JMC
genre: ytdl-sub
premiered: 2021-08-08
title: Mock Entry 21-1
year: 2021
Mock Entry 21-1.nfo
NFO tags:
musicvideo:
album: Music Videos
artist: JMC
custom_tag: mom
genre: ytdl-sub
premiered: 2021-08-08
title: Mock Entry 21-1

View file

@ -1,9 +1,9 @@
Files created:
----------------------------------------
{output_directory}
.ytdl-sub-JMC-download-archive.json
.ytdl-sub-JMC-migrated-download-archive.json
Files removed:
----------------------------------------
{output_directory}
.ytdl-sub-music_video_playlist_test-download-archive.json
.ytdl-sub-subscription_test-download-archive.json

View file

@ -0,0 +1,128 @@
Files created:
----------------------------------------
{output_directory}
.ytdl-sub-subscription_test-download-archive.json
tvshow.nfo
NFO tags:
tvshow:
genre: ytdl-sub
mpaa: TV-14
title: JMC
{output_directory}/Season 2020
s2020.e000001 - Mock Entry 20-3-thumb.jpg
s2020.e000001 - Mock Entry 20-3.info.json
s2020.e000001 - Mock Entry 20-3.mp4
Video Tags:
contentRating: TV-14
date: 2020-08-07
episode_id: 1
genre: ytdl-sub
show: JMC
synopsis:
https://20-3.com
The Description
title: 2020-08-07 - Mock Entry 20-3
year: 2020
s2020.e000001 - Mock Entry 20-3.nfo
NFO tags:
episodedetails:
aired: 2020-08-07
episode: 1
genre: ytdl-sub
mpaa: TV-14
plot:
https://20-3.com
The Description
season: 2020
title: 2020-08-07 - Mock Entry 20-3
year: 2020
s2020.e000002 - Mock Entry 20-2-thumb.jpg
s2020.e000002 - Mock Entry 20-2.info.json
s2020.e000002 - Mock Entry 20-2.mp4
Video Tags:
contentRating: TV-14
date: 2020-08-08
episode_id: 2
genre: ytdl-sub
show: JMC
synopsis:
https://20-2.com
The Description
title: 2020-08-08 - Mock Entry 20-2
year: 2020
s2020.e000002 - Mock Entry 20-2.nfo
NFO tags:
episodedetails:
aired: 2020-08-08
episode: 2
genre: ytdl-sub
mpaa: TV-14
plot:
https://20-2.com
The Description
season: 2020
title: 2020-08-08 - Mock Entry 20-2
year: 2020
s2020.e000003 - Mock Entry 20-1-thumb.jpg
s2020.e000003 - Mock Entry 20-1.info.json
s2020.e000003 - Mock Entry 20-1.mp4
Video Tags:
contentRating: TV-14
date: 2020-08-08
episode_id: 3
genre: ytdl-sub
show: JMC
synopsis:
https://20-1.com
The Description
title: 2020-08-08 - Mock Entry 20-1
year: 2020
s2020.e000003 - Mock Entry 20-1.nfo
NFO tags:
episodedetails:
aired: 2020-08-08
episode: 3
genre: ytdl-sub
mpaa: TV-14
plot:
https://20-1.com
The Description
season: 2020
title: 2020-08-08 - Mock Entry 20-1
year: 2020
{output_directory}/Season 2021
s2021.e000004 - Mock Entry 21-1-thumb.jpg
s2021.e000004 - Mock Entry 21-1.info.json
s2021.e000004 - Mock Entry 21-1.mp4
Video Tags:
contentRating: TV-14
date: 2021-08-08
episode_id: 4
genre: ytdl-sub
show: JMC
synopsis:
https://21-1.com
The Description
title: 2021-08-08 - Mock Entry 21-1
year: 2021
s2021.e000004 - Mock Entry 21-1.nfo
NFO tags:
episodedetails:
aired: 2021-08-08
episode: 4
genre: ytdl-sub
mpaa: TV-14
plot:
https://21-1.com
The Description
season: 2021
title: 2021-08-08 - Mock Entry 21-1
year: 2021

View file

@ -0,0 +1,124 @@
Files created:
----------------------------------------
{output_directory}
.ytdl-sub-subscription_test-download-archive.json
tvshow.nfo
NFO tags:
tvshow:
genre: ytdl-sub
mpaa: TV-14
title: JMC
{output_directory}/Season 2020
s2020.e000001 - Mock Entry 20-3.info.json
s2020.e000001 - Mock Entry 20-3.mp4
Video Tags:
contentRating: TV-14
date: 2020-08-07
episode_id: 1
genre: ytdl-sub
show: JMC
synopsis:
https://20-3.com
The Description
title: 2020-08-07 - Mock Entry 20-3
year: 2020
s2020.e000001 - Mock Entry 20-3.nfo
NFO tags:
episodedetails:
aired: 2020-08-07
episode: 1
genre: ytdl-sub
mpaa: TV-14
plot:
https://20-3.com
The Description
season: 2020
title: 2020-08-07 - Mock Entry 20-3
year: 2020
s2020.e000002 - Mock Entry 20-2.info.json
s2020.e000002 - Mock Entry 20-2.mp4
Video Tags:
contentRating: TV-14
date: 2020-08-08
episode_id: 2
genre: ytdl-sub
show: JMC
synopsis:
https://20-2.com
The Description
title: 2020-08-08 - Mock Entry 20-2
year: 2020
s2020.e000002 - Mock Entry 20-2.nfo
NFO tags:
episodedetails:
aired: 2020-08-08
episode: 2
genre: ytdl-sub
mpaa: TV-14
plot:
https://20-2.com
The Description
season: 2020
title: 2020-08-08 - Mock Entry 20-2
year: 2020
s2020.e000003 - Mock Entry 20-1.info.json
s2020.e000003 - Mock Entry 20-1.mp4
Video Tags:
contentRating: TV-14
date: 2020-08-08
episode_id: 3
genre: ytdl-sub
show: JMC
synopsis:
https://20-1.com
The Description
title: 2020-08-08 - Mock Entry 20-1
year: 2020
s2020.e000003 - Mock Entry 20-1.nfo
NFO tags:
episodedetails:
aired: 2020-08-08
episode: 3
genre: ytdl-sub
mpaa: TV-14
plot:
https://20-1.com
The Description
season: 2020
title: 2020-08-08 - Mock Entry 20-1
year: 2020
{output_directory}/Season 2021
s2021.e000004 - Mock Entry 21-1.info.json
s2021.e000004 - Mock Entry 21-1.mp4
Video Tags:
contentRating: TV-14
date: 2021-08-08
episode_id: 4
genre: ytdl-sub
show: JMC
synopsis:
https://21-1.com
The Description
title: 2021-08-08 - Mock Entry 21-1
year: 2021
s2021.e000004 - Mock Entry 21-1.nfo
NFO tags:
episodedetails:
aired: 2021-08-08
episode: 4
genre: ytdl-sub
mpaa: TV-14
plot:
https://21-1.com
The Description
season: 2021
title: 2021-08-08 - Mock Entry 21-1
year: 2021

View file

@ -1,22 +0,0 @@
Files created:
----------------------------------------
{output_directory}/JMC
Oblivion Mod Falcor p.1.info.json
Oblivion Mod Falcor p.1.jpg
Oblivion Mod Falcor p.1.mp4
Video Tags:
album: Music Videos
artist: JMC
genre: ytdl-sub
premiered: 2010-08-13
title: Oblivion Mod "Falcor" p.1
year: 2010
Embedded thumbnail
Oblivion Mod Falcor p.1.nfo
NFO tags:
musicvideo:
album: Music Videos
artist: JMC
genre: ytdl-sub
premiered: 2010-08-13
title: Oblivion Mod "Falcor" p.1

View file

@ -1,20 +0,0 @@
Files created:
----------------------------------------
{output_directory}/JMC
Oblivion Mod Falcor p.1.info.json
Oblivion Mod Falcor p.1.mp4
Video Tags:
album: Music Videos
artist: JMC
genre: ytdl-sub
premiered: 2010-08-13
title: Oblivion Mod "Falcor" p.1
year: 2010
Oblivion Mod Falcor p.1.nfo
NFO tags:
musicvideo:
album: Music Videos
artist: JMC
genre: ytdl-sub
premiered: 2010-08-13
title: Oblivion Mod "Falcor" p.1

View file

@ -186,6 +186,7 @@ def preset_with_subscription_overrides_map(
"elem2",
"elem3",
],
"custom_map": {"custom_map_key": ["custom_map_list_value"]},
}
},
},
@ -290,6 +291,7 @@ def test_subscription_overrides_map(
"elem2",
"elem3",
],
"custom_map": {"custom_map_key": ["custom_map_list_value"]},
}