From 476a780834e61fa7442d9461b46b42b528ff4155 Mon Sep 17 00:00:00 2001 From: Jesse Bannon Date: Tue, 7 Mar 2023 15:02:12 -0800 Subject: [PATCH] wip --- src/ytdl_sub/cli/main.py | 20 ++++++++++ src/ytdl_sub/config/config_validator.py | 49 ++++++++++++++++++++++++- 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/src/ytdl_sub/cli/main.py b/src/ytdl_sub/cli/main.py index bb40c7b1..fbcfc172 100644 --- a/src/ytdl_sub/cli/main.py +++ b/src/ytdl_sub/cli/main.py @@ -1,9 +1,13 @@ import argparse +from datetime import datetime import gc import sys +from pathlib import Path from typing import List from typing import Tuple +from yt_dlp.utils import sanitize_filename + 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 @@ -18,6 +22,18 @@ logger = Logger.get() # Use ytdl-sub dl arguments to use the preset _VIEW_EXTRA_ARGS_FORMATTER = "--preset _view --overrides.url {}" +def _get_subscription_log_file_path(config: ConfigFile, subscription_name: str, success: bool) -> Path: + assert config.config_options.persist_logs, "persist_logs should not be None" + + log_time = datetime.now().strftime("%Y-%m-%d-%H%M%S") + log_subscription_name = sanitize_filename(subscription_name).lower().replace(" ", "_") + log_success = "success" if success else "error" + + log_filename = f"{log_time}.{log_subscription_name}.{log_success}.log" + persist_log_path = Path(config.config_options.persist_logs.logs_directory) / log_filename + + return persist_log_path + def _download_subscriptions_from_yaml_files( config: ConfigFile, args: argparse.Namespace @@ -59,6 +75,10 @@ def _download_subscriptions_from_yaml_files( output.append((subscription, transaction_log)) gc.collect() # Garbage collect after each subscription download + + if config.config_options.persist_logs: + FileHandler.copy(Logger.debug_log_filename(), ) + Logger.cleanup() # Cleanup logger after each successful subscription download return output diff --git a/src/ytdl_sub/config/config_validator.py b/src/ytdl_sub/config/config_validator.py index 255000e2..b35c8b84 100644 --- a/src/ytdl_sub/config/config_validator.py +++ b/src/ytdl_sub/config/config_validator.py @@ -3,13 +3,14 @@ from typing import Dict from typing import Optional from mergedeep import mergedeep +from yt_dlp.utils import datetime_from_str from ytdl_sub.prebuilt_presets import PREBUILT_PRESETS from ytdl_sub.utils.system import IS_WINDOWS from ytdl_sub.validators.file_path_validators import FFmpegFileValidator from ytdl_sub.validators.file_path_validators import FFprobeFileValidator from ytdl_sub.validators.strict_dict_validator import StrictDictValidator -from ytdl_sub.validators.validators import LiteralDictValidator +from ytdl_sub.validators.validators import LiteralDictValidator, BoolValidator from ytdl_sub.validators.validators import StringValidator if IS_WINDOWS: @@ -21,10 +22,46 @@ else: _DEFAULT_FFMPEG_PATH = "/usr/bin/ffmpeg" _DEFAULT_FFPROBE_PATH = "/usr/bin/ffprobe" +class PersistLogsValidator(StrictDictValidator): + _required_keys = {"logs_directory"} + _optional_keys = {"keep_logs_after", "keep_successful_logs"} + + def __init__(self, name: str, value: Any): + super().__init__(name, value) + + self._logs_directory = self._validate_key( + key="logs_directory", validator=StringValidator + ) + + self._keep_logs_after: Optional[str] = None + if keep_logs_validator := self._validate_key_if_present( + key="keep_logs_after", validator=StringValidator + ): + try: + self._keep_logs_after = datetime_from_str(keep_logs_validator.value) + except Exception as exc: + raise self._validation_exception(f"Invalid datetime string: {str(exc)}") + + self._keep_successful_logs = self._validate_key( + key="keep_successful_logs", validator=BoolValidator, default=True + ) + + @property + def logs_directory(self) -> str: + return self._logs_directory.value + + @property + def keep_logs_after(self) -> Optional[str]: + return self._keep_logs_after + + @property + def keep_successful_logs(self) -> bool: + return self._keep_successful_logs.value + class ConfigOptions(StrictDictValidator): _required_keys = {"working_directory"} - _optional_keys = {"umask", "dl_aliases", "lock_directory", "ffmpeg_path", "ffprobe_path"} + _optional_keys = {"umask", "dl_aliases", "persist_logs", "lock_directory", "ffmpeg_path", "ffprobe_path"} def __init__(self, name: str, value: Any): super().__init__(name, value) @@ -38,6 +75,9 @@ class ConfigOptions(StrictDictValidator): self._dl_aliases = self._validate_key_if_present( key="dl_aliases", validator=LiteralDictValidator ) + self._persist_logs = self._validate_key_if_present( + key="persist_logs", validator=PersistLogsValidator + ) self._lock_directory = self._validate_key( key="lock_directory", validator=StringValidator, default=_DEFAULT_LOCK_DIRECTORY ) @@ -93,6 +133,11 @@ class ConfigOptions(StrictDictValidator): return self._dl_aliases.dict return {} + @property + def persist_logs(self) -> Optional[PersistLogsValidator]: + # TODO: nested docstring??? + return self._persist_logs + @property def lock_directory(self) -> str: """