one-off downloader working

This commit is contained in:
jbannon 2022-04-13 05:30:29 +00:00
parent beb48ac5aa
commit d6fe2505f6
7 changed files with 103 additions and 26 deletions

View file

@ -10,6 +10,7 @@ presets:
ytdl_options: ytdl_options:
format: 'bestaudio[ext=mp3]' format: 'bestaudio[ext=mp3]'
output_options: output_options:
output_directory: "/tmp/{sanitized_artist}"
file_name: "[{album_year}] {sanitized_album}/{track_number_padded} - {sanitized_title}.{ext}" file_name: "[{album_year}] {sanitized_album}/{track_number_padded} - {sanitized_title}.{ext}"
convert_thumbnail: "jpeg" convert_thumbnail: "jpeg"
thumbnail_name: "[{album_year}] {sanitized_album}/folder.jpeg" thumbnail_name: "[{album_year}] {sanitized_album}/folder.jpeg"

View file

@ -22,8 +22,6 @@ bl00dwave:
preset: "soundcloud_with_id3_tags" preset: "soundcloud_with_id3_tags"
soundcloud: soundcloud:
username: bl00dwave username: bl00dwave
output_options:
output_directory: "/tmp/bl00dwave"
overrides: overrides:
artist: "bl00dwave" artist: "bl00dwave"
genre: "Synthwave / Electronic" genre: "Synthwave / Electronic"

View file

@ -1,12 +1,84 @@
from argparse import ArgumentError
from typing import Dict
from typing import List from typing import List
from mergedeep import mergedeep
class SubscriptionArgsParser: class SubscriptionArgsParser:
""" """
'Unknown' 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 in a subscription yaml. This class will convert those extra args into a dict that can be
passed in to instantiate a
:class:`~ytdl_subscribe.validators.config.preset_validator.PresetValidator` :class:`~ytdl_subscribe.validators.config.preset_validator.PresetValidator`
""" """
def __init__(self, unknown_arguments: List[str]): def __init__(self, extra_arguments: List[str]):
self._unknown_arguments = unknown_arguments """
:param extra_arguments: List of extra arguments from argparse
"""
self._unknown_arguments = extra_arguments
@property
def _argument_exception(self) -> ArgumentError:
"""
:return: Exception to raise if a parsing error occurs.
"""
return ArgumentError(
argument=None,
message="dl arguments must be in the form of --subscription.option.name 'value' "
"proceeding the url",
)
@classmethod
def _is_argument_name(cls, arg: str) -> bool:
"""
:param arg: Arg value from the unknown args list
:return: True if it's an argument name, denoted by starting with '--'. False otherwise.
"""
return arg.startswith("--")
@classmethod
def _argument_name_and_value_to_dict(cls, arg_name: str, arg_value: str) -> Dict:
"""
:param arg_name: Argument name in the form of 'key1.key2.key3'
:param arg_value: Argument value
:return: dict containing {'key1':{'key2':{'key3': value}}}
"""
argument_dict = {}
# Remove the argument --'s, then split on period
arg_name_split = arg_name.replace("--", "", 1).split(".")
next_arg_name = arg_name_split[0]
next_dict = argument_dict
for next_arg_name in arg_name_split[:-1]:
next_dict[next_arg_name] = {}
next_dict = next_dict[next_arg_name]
next_dict[arg_name_split[-1]] = arg_value
return argument_dict
def to_subscription_dict(self) -> Dict:
"""
Converts the extra arguments into a dict equivalent to a subscription yaml.
:return: dict containing argument names and values
"""
subscription_dict = {}
if len(self._unknown_arguments) % 2 != 0:
raise self._argument_exception
for idx in range(0, len(self._unknown_arguments), 2):
argument_name = self._unknown_arguments[idx]
argument_value = self._unknown_arguments[idx + 1]
if not self._is_argument_name(arg=argument_name):
raise self._argument_exception
argument_dict = self._argument_name_and_value_to_dict(
arg_name=argument_name, arg_value=argument_value
)
mergedeep.merge(subscription_dict, argument_dict, strategy=mergedeep.Strategy.REPLACE)
return subscription_dict

View file

@ -1,9 +1,11 @@
import argparse import argparse
import sys import sys
from random import randint
from typing import List from typing import List
################################################################################################### ###################################################################################################
# GLOBAL PARSER # GLOBAL 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
@ -30,15 +32,11 @@ subscription_parser.add_argument(
default="config.yaml", default="config.yaml",
) )
################################################################################################### ###################################################################################################
# INTERACTIVE DOWNLOAD PARSER # DOWNLOAD PARSER
download_parser = subparsers.add_parser("dl") download_parser = subparsers.add_parser("dl")
download_parser.add_argument(
"url",
help="url to the desired content to download, will prompt for further arguments needed",
)
if __name__ == "__main__": if __name__ == "__main__":
args, unknown = 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":
@ -53,18 +51,19 @@ if __name__ == "__main__":
for subscription in subscriptions: for subscription in subscriptions:
subscription.to_subscription().download() subscription.to_subscription().download()
print("hi") print("Subscription download complete!")
# for subscription_path in subscription_paths:
#
#
# subscriptions = parse_subscriptions(
# yaml_dict, presets, subscriptions=args.subscriptions
# )
# for s in subscriptions:
# s.extract_info()
# One-off download # One-off download
if args.subparser == "dl": if args.subparser == "dl":
print("Interactive download is not supported yet. Stay tuned!") subscription_name = f"cli-dl-{randint(0, 999)}"
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!")
sys.exit(0) sys.exit(0)

View file

@ -1,4 +1,3 @@
from abc import ABC
from typing import List from typing import List
from ytdl_subscribe.downloaders.soundcloud_downloader import SoundcloudDownloader from ytdl_subscribe.downloaders.soundcloud_downloader import SoundcloudDownloader

View file

@ -1,4 +1,3 @@
from abc import ABC
from typing import List from typing import List
from ytdl_subscribe.downloaders.youtube_downloader import YoutubeDownloader from ytdl_subscribe.downloaders.youtube_downloader import YoutubeDownloader

View file

@ -1,5 +1,6 @@
import copy import copy
from typing import Any from typing import Any
from typing import Dict
from typing import List from typing import List
from typing import Optional from typing import Optional
from typing import Type from typing import Type
@ -93,6 +94,12 @@ class SubscriptionValidator(StrictDictValidator):
preset_options=self.preset, preset_options=self.preset,
) )
@classmethod
def from_dict(
cls, config: ConfigFileValidator, subscription_name, subscription_dict: Dict
) -> "SubscriptionValidator":
return SubscriptionValidator(config=config, name=subscription_name, value=subscription_dict)
@classmethod @classmethod
def from_file_path( def from_file_path(
cls, config: ConfigFileValidator, subscription_path: str cls, config: ConfigFileValidator, subscription_path: str
@ -104,8 +111,10 @@ class SubscriptionValidator(StrictDictValidator):
subscriptions: List["SubscriptionValidator"] = [] subscriptions: List["SubscriptionValidator"] = []
for subscription_key, subscription_object in subscription_dict.items(): for subscription_key, subscription_object in subscription_dict.items():
subscriptions.append( subscriptions.append(
SubscriptionValidator( SubscriptionValidator.from_dict(
config=config, name=subscription_key, value=subscription_object config=config,
subscription_name=subscription_key,
subscription_dict=subscription_object,
) )
) )