in main
This commit is contained in:
parent
189b54964b
commit
ff3707adb9
7 changed files with 107 additions and 5 deletions
|
|
@ -14,6 +14,7 @@ from ytdl_sub.cli.download_args_parser import DownloadArgsParser
|
|||
from ytdl_sub.cli.main_args_parser import parser
|
||||
from ytdl_sub.config.config_file import ConfigFile
|
||||
from ytdl_sub.subscriptions.subscription import Subscription
|
||||
from ytdl_sub.utils.exceptions import ExperimentalFeatureNotEnabled
|
||||
from ytdl_sub.utils.exceptions import ValidationException
|
||||
from ytdl_sub.utils.file_handler import FileHandler
|
||||
from ytdl_sub.utils.file_handler import FileHandlerTransactionLog
|
||||
|
|
@ -62,7 +63,7 @@ def _maybe_write_subscription_log_file(
|
|||
|
||||
|
||||
def _download_subscriptions_from_yaml_files(
|
||||
config: ConfigFile, subscription_paths: List[str], dry_run: bool
|
||||
config: ConfigFile, subscription_paths: List[str], update_with_info_json: bool, dry_run: bool
|
||||
) -> List[Tuple[Subscription, FileHandlerTransactionLog]]:
|
||||
"""
|
||||
Downloads all subscriptions from one or many subscription yaml files.
|
||||
|
|
@ -73,6 +74,8 @@ def _download_subscriptions_from_yaml_files(
|
|||
Configuration file
|
||||
subscription_paths
|
||||
Path to subscription files to download
|
||||
update_with_info_json
|
||||
Whether to actually download or update using existing info json
|
||||
dry_run
|
||||
Whether to dry run or not
|
||||
|
||||
|
|
@ -101,7 +104,10 @@ def _download_subscriptions_from_yaml_files(
|
|||
logger.debug("Subscription full yaml:\n%s", subscription.as_yaml())
|
||||
|
||||
try:
|
||||
transaction_log = subscription.download(dry_run=dry_run)
|
||||
if update_with_info_json:
|
||||
transaction_log = subscription.update_with_info_json(dry_run=dry_run)
|
||||
else:
|
||||
transaction_log = subscription.download(dry_run=dry_run)
|
||||
except Exception as exc: # pylint: disable=broad-except
|
||||
_maybe_write_subscription_log_file(
|
||||
config=config, subscription=subscription, dry_run=dry_run, exception=exc
|
||||
|
|
@ -305,9 +311,21 @@ def main() -> List[Tuple[Subscription, FileHandlerTransactionLog]]:
|
|||
|
||||
with working_directory_lock(config=config):
|
||||
if args.subparser == "sub":
|
||||
if (
|
||||
args.update_with_info_json
|
||||
and not config.config_options.experimental.enable_update_with_info_json
|
||||
):
|
||||
raise ExperimentalFeatureNotEnabled(
|
||||
"--update-with-info-json requires setting "
|
||||
"configuration.experimental.update_with_info_json to True. This feature is ",
|
||||
"still being tested and has the ability to destroy files. Ensure you have a ",
|
||||
"full backup before usage. You have been warned!",
|
||||
)
|
||||
|
||||
transaction_logs = _download_subscriptions_from_yaml_files(
|
||||
config=config,
|
||||
subscription_paths=args.subscription_paths,
|
||||
update_with_info_json=args.update_with_info_json,
|
||||
dry_run=args.dry_run,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -135,6 +135,13 @@ _add_shared_arguments(parser, suppress_defaults=False)
|
|||
subparsers = parser.add_subparsers(dest="subparser")
|
||||
###################################################################################################
|
||||
# SUBSCRIPTION PARSER
|
||||
class SubArguments:
|
||||
UPDATE_WITH_INFO_JSON = CLIArgument(
|
||||
short="-u",
|
||||
long="--update-with-info-json",
|
||||
)
|
||||
|
||||
|
||||
subscription_parser = subparsers.add_parser("sub")
|
||||
_add_shared_arguments(subscription_parser, suppress_defaults=True)
|
||||
subscription_parser.add_argument(
|
||||
|
|
@ -144,6 +151,14 @@ subscription_parser.add_argument(
|
|||
help="path to subscription files, uses subscriptions.yaml if not provided",
|
||||
default=["subscriptions.yaml"],
|
||||
)
|
||||
subscription_parser.add_argument(
|
||||
SubArguments.UPDATE_WITH_INFO_JSON.short,
|
||||
SubArguments.UPDATE_WITH_INFO_JSON.long,
|
||||
action="store_true",
|
||||
help="update all subscriptions with the current config using info.json files",
|
||||
default=False,
|
||||
)
|
||||
|
||||
###################################################################################################
|
||||
# DOWNLOAD PARSER
|
||||
download_parser = subparsers.add_parser("dl")
|
||||
|
|
|
|||
|
|
@ -24,6 +24,27 @@ else:
|
|||
_DEFAULT_FFPROBE_PATH = "/usr/bin/ffprobe"
|
||||
|
||||
|
||||
class ExperimentalValidator(StrictDictValidator):
|
||||
_optional_keys = {"enable_update_with_info_json"}
|
||||
_allow_extra_keys = True
|
||||
|
||||
def __init__(self, name: str, value: Any):
|
||||
super().__init__(name, value)
|
||||
|
||||
self._enable_update_with_info_json = self._validate_key(
|
||||
key="enable_update_with_info_json", validator=BoolValidator, default=False
|
||||
)
|
||||
|
||||
@property
|
||||
def enable_update_with_info_json(self) -> bool:
|
||||
"""
|
||||
Enables modifying subscription files using info.json files using the argument
|
||||
``--update-with-info-json``. This feature is still being tested and has the ability to
|
||||
destroy files. Ensure you have a full backup before usage. You have been warned!
|
||||
"""
|
||||
return self._enable_update_with_info_json.value
|
||||
|
||||
|
||||
class PersistLogsValidator(StrictDictValidator):
|
||||
_required_keys = {"logs_directory"}
|
||||
_optional_keys = {"keep_logs_after", "keep_successful_logs"}
|
||||
|
|
@ -79,6 +100,7 @@ class PersistLogsValidator(StrictDictValidator):
|
|||
return self._keep_successful_logs.value
|
||||
|
||||
|
||||
# pylint: disable=too-many-instance-attributes
|
||||
class ConfigOptions(StrictDictValidator):
|
||||
_required_keys = {"working_directory"}
|
||||
_optional_keys = {
|
||||
|
|
@ -88,6 +110,7 @@ class ConfigOptions(StrictDictValidator):
|
|||
"lock_directory",
|
||||
"ffmpeg_path",
|
||||
"ffprobe_path",
|
||||
"experimental",
|
||||
}
|
||||
|
||||
def __init__(self, name: str, value: Any):
|
||||
|
|
@ -114,6 +137,9 @@ class ConfigOptions(StrictDictValidator):
|
|||
self._ffprobe_path = self._validate_key(
|
||||
key="ffprobe_path", validator=FFprobeFileValidator, default=_DEFAULT_FFPROBE_PATH
|
||||
)
|
||||
self._experimental = self._validate_key(
|
||||
key="experimental", validator=ExperimentalValidator, default={}
|
||||
)
|
||||
|
||||
@property
|
||||
def working_directory(self) -> str:
|
||||
|
|
@ -167,6 +193,13 @@ class ConfigOptions(StrictDictValidator):
|
|||
"""
|
||||
return self._persist_logs
|
||||
|
||||
@property
|
||||
def experimental(self) -> ExperimentalValidator:
|
||||
"""
|
||||
Experimental validator. readthedocs in the validator itself!
|
||||
"""
|
||||
return self._experimental
|
||||
|
||||
@property
|
||||
def lock_directory(self) -> str:
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ class InfoJsonDownloader(BaseDownloader[InfoJsonDownloaderOptions]):
|
|||
file_names_mtime: Dict[str, Dict[str, float]] = defaultdict(dict)
|
||||
entries: List[Entry] = []
|
||||
|
||||
for download_mapping in self._enhanced_download_archive.mapping._entry_mappings.values():
|
||||
for download_mapping in self._enhanced_download_archive.mapping.entry_mappings.values():
|
||||
entry = self._get_entry_from_download_mapping(download_mapping)
|
||||
entries.append(entry)
|
||||
|
||||
|
|
@ -117,7 +117,7 @@ class InfoJsonDownloader(BaseDownloader[InfoJsonDownloaderOptions]):
|
|||
the working directory
|
||||
"""
|
||||
# Use original mapping since the live mapping gets wiped
|
||||
entry_file_names = self._original_mapping._entry_mappings[entry.uid].file_names
|
||||
entry_file_names = self._original_mapping.entry_mappings[entry.uid].file_names
|
||||
|
||||
for file_name in entry_file_names:
|
||||
ext = get_file_extension(file_name)
|
||||
|
|
|
|||
|
|
@ -36,3 +36,7 @@ class InvalidDlArguments(ValidationException):
|
|||
|
||||
class FileNotDownloadedException(ValueError):
|
||||
"""ytdlp failed to download something"""
|
||||
|
||||
|
||||
class ExperimentalFeatureNotEnabled(ValidationException):
|
||||
"""Feature is not enabled for usage"""
|
||||
|
|
|
|||
|
|
@ -175,6 +175,15 @@ class DownloadMappings:
|
|||
download_mappings._entry_mappings = entry_mappings_json
|
||||
return download_mappings
|
||||
|
||||
@property
|
||||
def entry_mappings(self) -> Dict[str, DownloadMapping]:
|
||||
"""
|
||||
Returns
|
||||
-------
|
||||
Mapping of entries to files
|
||||
"""
|
||||
return self._entry_mappings
|
||||
|
||||
@property
|
||||
def entry_ids(self) -> List[str]:
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ from ytdl_sub.cli.main import logger as main_logger
|
|||
from ytdl_sub.cli.main import main
|
||||
from ytdl_sub.config.config_file import ConfigFile
|
||||
from ytdl_sub.subscriptions.subscription import Subscription
|
||||
from ytdl_sub.utils.exceptions import ExperimentalFeatureNotEnabled
|
||||
from ytdl_sub.utils.file_handler import FileHandler
|
||||
from ytdl_sub.utils.file_handler import FileHandlerTransactionLog
|
||||
from ytdl_sub.utils.file_handler import FileMetadata
|
||||
|
|
@ -127,7 +128,10 @@ def test_subscription_logs_write_to_file(
|
|||
):
|
||||
try:
|
||||
_download_subscriptions_from_yaml_files(
|
||||
config=config, subscription_paths=subscription_paths, dry_run=dry_run
|
||||
config=config,
|
||||
subscription_paths=subscription_paths,
|
||||
update_with_info_json=False,
|
||||
dry_run=dry_run,
|
||||
)
|
||||
except ValueError:
|
||||
assert not mock_success_output
|
||||
|
|
@ -275,3 +279,22 @@ def test_output_summary():
|
|||
|
||||
_ = _output_summary(transaction_logs=mock_subscriptions)
|
||||
assert True # Test used for manual inspection - too hard to test ansi color codes
|
||||
|
||||
|
||||
def test_update_with_info_json_requires_experimental_flag(
|
||||
music_video_config_path: Path,
|
||||
music_video_subscription_path: Path,
|
||||
) -> None:
|
||||
with patch.object(
|
||||
sys,
|
||||
"argv",
|
||||
[
|
||||
"ytdl-sub",
|
||||
"--config",
|
||||
str(music_video_config_path),
|
||||
"sub",
|
||||
str(music_video_subscription_path),
|
||||
"--update-with-info-json",
|
||||
],
|
||||
), pytest.raises(ExperimentalFeatureNotEnabled):
|
||||
_ = main()
|
||||
|
|
|
|||
Loading…
Reference in a new issue