clean up main, better error handling
This commit is contained in:
parent
10d239fcaf
commit
311dbfc3d1
4 changed files with 102 additions and 53 deletions
|
|
@ -1,3 +1,4 @@
|
||||||
|
import hashlib
|
||||||
from argparse import ArgumentError
|
from argparse import ArgumentError
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
@ -5,7 +6,7 @@ from typing import List
|
||||||
from mergedeep import mergedeep
|
from mergedeep import mergedeep
|
||||||
|
|
||||||
|
|
||||||
class SubscriptionArgsParser:
|
class DownloadArgsParser:
|
||||||
"""
|
"""
|
||||||
'Extra' arguments can be given to `ytdl-sub dl` which are meant to represent fields
|
'Extra' arguments can be given to `ytdl-sub dl` which are meant to represent fields
|
||||||
in a subscription yaml. This class will convert those extra args into a dict that can be
|
in a subscription yaml. This class will convert those extra args into a dict that can be
|
||||||
|
|
@ -50,7 +51,6 @@ class SubscriptionArgsParser:
|
||||||
# Remove the argument --'s, then split on period
|
# Remove the argument --'s, then split on period
|
||||||
arg_name_split = arg_name.replace("--", "", 1).split(".")
|
arg_name_split = arg_name.replace("--", "", 1).split(".")
|
||||||
|
|
||||||
next_arg_name = arg_name_split[0]
|
|
||||||
next_dict = argument_dict
|
next_dict = argument_dict
|
||||||
for next_arg_name in arg_name_split[:-1]:
|
for next_arg_name in arg_name_split[:-1]:
|
||||||
next_dict[next_arg_name] = {}
|
next_dict[next_arg_name] = {}
|
||||||
|
|
@ -82,3 +82,10 @@ class SubscriptionArgsParser:
|
||||||
mergedeep.merge(subscription_dict, argument_dict, strategy=mergedeep.Strategy.REPLACE)
|
mergedeep.merge(subscription_dict, argument_dict, strategy=mergedeep.Strategy.REPLACE)
|
||||||
|
|
||||||
return subscription_dict
|
return subscription_dict
|
||||||
|
|
||||||
|
def get_args_hash(self) -> str:
|
||||||
|
"""
|
||||||
|
:return: Hash of the arguments provided
|
||||||
|
"""
|
||||||
|
hash_string = str(sorted(self._unknown_arguments))
|
||||||
|
return hashlib.sha256(hash_string.encode()).hexdigest()[-8:]
|
||||||
29
ytdl_subscribe/cli/main_args_parser.py
Normal file
29
ytdl_subscribe/cli/main_args_parser.py
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
###################################################################################################
|
||||||
|
# GLOBAL PARSER
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="YoutubeDL-Subscribe: Download and organize your favorite media hassle-free."
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"-c",
|
||||||
|
"--config",
|
||||||
|
metavar="CONFIGPATH",
|
||||||
|
type=str,
|
||||||
|
help="path to the config yaml, uses config.yaml if not provided",
|
||||||
|
default="config.yaml",
|
||||||
|
)
|
||||||
|
###################################################################################################
|
||||||
|
# SUBSCRIPTION PARSER
|
||||||
|
subparsers = parser.add_subparsers(dest="subparser")
|
||||||
|
subscription_parser = subparsers.add_parser("sub")
|
||||||
|
subscription_parser.add_argument(
|
||||||
|
"subscription_paths",
|
||||||
|
metavar="SUBPATH",
|
||||||
|
nargs="*",
|
||||||
|
help="path to subscription files, uses config.yaml if not provided",
|
||||||
|
default="config.yaml",
|
||||||
|
)
|
||||||
|
###################################################################################################
|
||||||
|
# DOWNLOAD PARSER
|
||||||
|
download_parser = subparsers.add_parser("dl")
|
||||||
|
|
@ -1,69 +1,82 @@
|
||||||
import argparse
|
import argparse
|
||||||
import sys
|
import sys
|
||||||
from random import randint
|
import traceback
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
###################################################################################################
|
from ytdl_subscribe.cli.download_args_parser import DownloadArgsParser
|
||||||
# GLOBAL PARSER
|
from ytdl_subscribe.cli.main_args_parser import parser
|
||||||
from ytdl_subscribe.cli.subscription_args_parser import SubscriptionArgsParser
|
|
||||||
from ytdl_subscribe.validators.config.config_file_validator import ConfigFileValidator
|
from ytdl_subscribe.validators.config.config_file_validator import ConfigFileValidator
|
||||||
from ytdl_subscribe.validators.config.subscription_validator import SubscriptionValidator
|
from ytdl_subscribe.validators.config.subscription_validator import SubscriptionValidator
|
||||||
|
from ytdl_subscribe.validators.exceptions import ValidationException
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(
|
|
||||||
description="YoutubeDL-Subscribe: Download and organize your favorite media hassle-free."
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"-c",
|
|
||||||
"--config",
|
|
||||||
metavar="CONFIGPATH",
|
|
||||||
type=str,
|
|
||||||
help="path to the config yaml, uses config.yaml if not provided",
|
|
||||||
default="config.yaml",
|
|
||||||
)
|
|
||||||
###################################################################################################
|
|
||||||
# SUBSCRIPTION PARSER
|
|
||||||
subparsers = parser.add_subparsers(dest="subparser")
|
|
||||||
subscription_parser = subparsers.add_parser("sub")
|
|
||||||
subscription_parser.add_argument(
|
|
||||||
"subscription_paths",
|
|
||||||
metavar="SUBPATH",
|
|
||||||
nargs="*",
|
|
||||||
help="path to subscription files, uses config.yaml if not provided",
|
|
||||||
default="config.yaml",
|
|
||||||
)
|
|
||||||
###################################################################################################
|
|
||||||
# DOWNLOAD PARSER
|
|
||||||
download_parser = subparsers.add_parser("dl")
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
def _download_subscriptions_from_yaml_files(
|
||||||
|
config: ConfigFileValidator, args: argparse.Namespace
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
Downloads all subscriptions from one or many subscription yaml files.
|
||||||
|
|
||||||
|
:param config: Configuration file
|
||||||
|
:param args: Arguments from argparse
|
||||||
|
"""
|
||||||
|
subscription_paths: List[str] = args.subscription_paths
|
||||||
|
subscriptions: List[SubscriptionValidator] = []
|
||||||
|
|
||||||
|
for subscription_path in subscription_paths:
|
||||||
|
subscriptions += SubscriptionValidator.from_file_path(
|
||||||
|
config=config, subscription_path=subscription_path
|
||||||
|
)
|
||||||
|
|
||||||
|
for subscription in subscriptions:
|
||||||
|
subscription.to_subscription().download()
|
||||||
|
|
||||||
|
|
||||||
|
def _download_subscription_from_cli(config: ConfigFileValidator, extra_args: List[str]) -> None:
|
||||||
|
"""
|
||||||
|
Downloads a one-off subscription using the CLI
|
||||||
|
|
||||||
|
:param config: Configuration file
|
||||||
|
:param extra_args: Extra arguments from argparse that contain dynamic subscription options
|
||||||
|
"""
|
||||||
|
dl_args_parser = DownloadArgsParser(extra_arguments=extra_args)
|
||||||
|
subscription_args_dict = dl_args_parser.to_subscription_dict()
|
||||||
|
|
||||||
|
subscription_name = f"cli-dl-{dl_args_parser.get_args_hash()}"
|
||||||
|
SubscriptionValidator.from_dict(
|
||||||
|
config=config,
|
||||||
|
subscription_name=subscription_name,
|
||||||
|
subscription_dict=subscription_args_dict,
|
||||||
|
).to_subscription().download()
|
||||||
|
|
||||||
|
|
||||||
|
def _main():
|
||||||
|
"""Entrypoint for ytdl-subscribe"""
|
||||||
args, extra_args = parser.parse_known_args()
|
args, extra_args = parser.parse_known_args()
|
||||||
|
|
||||||
config: ConfigFileValidator = ConfigFileValidator.from_file_path(args.config)
|
config: ConfigFileValidator = ConfigFileValidator.from_file_path(args.config)
|
||||||
if args.subparser == "sub":
|
if args.subparser == "sub":
|
||||||
subscription_paths: List[str] = args.subscription_paths
|
_download_subscriptions_from_yaml_files(config=config, args=args)
|
||||||
subscriptions: List[SubscriptionValidator] = []
|
|
||||||
|
|
||||||
for subscription_path in subscription_paths:
|
|
||||||
subscriptions += SubscriptionValidator.from_file_path(
|
|
||||||
config=config, subscription_path=subscription_path
|
|
||||||
)
|
|
||||||
|
|
||||||
for subscription in subscriptions:
|
|
||||||
subscription.to_subscription().download()
|
|
||||||
|
|
||||||
print("Subscription download complete!")
|
print("Subscription download complete!")
|
||||||
|
|
||||||
# One-off download
|
# One-off download
|
||||||
if args.subparser == "dl":
|
if args.subparser == "dl":
|
||||||
subscription_name = f"cli-dl-{randint(0, 999)}"
|
_download_subscription_from_cli(config=config, extra_args=extra_args)
|
||||||
subscription_args_dict = SubscriptionArgsParser(
|
|
||||||
extra_arguments=extra_args
|
|
||||||
).to_subscription_dict()
|
|
||||||
SubscriptionValidator.from_dict(
|
|
||||||
config=config,
|
|
||||||
subscription_name=subscription_name,
|
|
||||||
subscription_dict=subscription_args_dict,
|
|
||||||
).to_subscription().download()
|
|
||||||
print("Download complete!")
|
print("Download complete!")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
_main()
|
||||||
|
except ValidationException as validation_exception:
|
||||||
|
print(validation_exception)
|
||||||
|
sys.exit(1)
|
||||||
|
except Exception as exc: # pylint: disable=broad-except
|
||||||
|
print(traceback.format_exc())
|
||||||
|
print(
|
||||||
|
"A fatal error occurred. Please copy and paste the stacktrace above and make a Github "
|
||||||
|
"issue at https://github.com/jmbannon/ytdl-subscribe/issues with your config and "
|
||||||
|
"command/subscription yaml file to reproduce. Thanks for trying ytdl-subscribe!"
|
||||||
|
)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ class SubscriptionValidator(StrictDictValidator):
|
||||||
|
|
||||||
if preset_name not in self.config.presets.keys:
|
if preset_name not in self.config.presets.keys:
|
||||||
raise self._validation_exception(
|
raise self._validation_exception(
|
||||||
f"'preset '{preset_name}' does not exist in the provided config. "
|
f"preset '{preset_name}' does not exist in the provided config. "
|
||||||
f"Available presets: {', '.join(self.config.presets.keys)}"
|
f"Available presets: {', '.join(self.config.presets.keys)}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue