diff --git a/subscriptions.yaml b/subscriptions.yaml index 5b202161..1b5c16f3 100644 --- a/subscriptions.yaml +++ b/subscriptions.yaml @@ -71,7 +71,7 @@ subscriptions: youtube: playlist_id: PLoopXDarluPBnuxs4PTC55Sc_2ShAXC0i preset: "music_videos" - output_path: "/mnt/nas/Downloads/ytdl/music_videos/Tom Petty" + output_path: "/tmp/Tom Petty" overrides: artist: "Tom Petty and the Heartbreakers" diff --git a/tmp/tom_petty/PLoopXDarluPBnuxs4PTC55Sc_2ShAXC0i.info.json b/tmp/tom_petty/PLoopXDarluPBnuxs4PTC55Sc_2ShAXC0i.info.json new file mode 100644 index 00000000..e478c589 --- /dev/null +++ b/tmp/tom_petty/PLoopXDarluPBnuxs4PTC55Sc_2ShAXC0i.info.json @@ -0,0 +1 @@ +{"uploader": "Tom Petty", "uploader_id": "UCvYomLPMwUr1FAXRMGhVfCQ", "uploader_url": "https://www.youtube.com/channel/UCvYomLPMwUr1FAXRMGhVfCQ", "thumbnails": [{"url": "https://i.ytimg.com/vi/h0JvF9vpqx8/hqdefault.jpg?sqp=-oaymwEWCKgBEF5IWvKriqkDCQgBFQAAiEIYAQ==&rs=AOn4CLC4j3LQTvtLdI600zjuPexZmwaNIQ", "width": 168, "height": 94, "id": "0", "resolution": "168x94"}, {"url": "https://i.ytimg.com/vi/h0JvF9vpqx8/hqdefault.jpg?sqp=-oaymwEWCMQBEG5IWvKriqkDCQgBFQAAiEIYAQ==&rs=AOn4CLCKP0397w_dG1v5vdRyRVACk1Ja4Q", "width": 196, "height": 110, "id": "1", "resolution": "196x110"}, {"url": "https://i.ytimg.com/vi/h0JvF9vpqx8/hqdefault.jpg?sqp=-oaymwEXCPYBEIoBSFryq4qpAwkIARUAAIhCGAE=&rs=AOn4CLCF_NTc5h0u2FnvSK4AO0xF4oF-GQ", "width": 246, "height": 138, "id": "2", "resolution": "246x138"}, {"url": "https://i.ytimg.com/vi/h0JvF9vpqx8/hqdefault.jpg?sqp=-oaymwEXCNACELwBSFryq4qpAwkIARUAAIhCGAE=&rs=AOn4CLAc79s_ev2Tmoz8MgB9rF1VZ-zKhQ", "width": 336, "height": 188, "id": "3", "resolution": "336x188"}], "channel": "Tom Petty", "channel_id": "UCvYomLPMwUr1FAXRMGhVfCQ", "channel_url": "https://www.youtube.com/channel/UCvYomLPMwUr1FAXRMGhVfCQ", "id": "PLoopXDarluPBnuxs4PTC55Sc_2ShAXC0i", "title": "Top Music Videos", "description": "Tom Petty & The Heartbreaker's Top Music Videos", "webpage_url": "https://youtube.com/playlist?list=PLoopXDarluPBnuxs4PTC55Sc_2ShAXC0i", "webpage_url_basename": "playlist", "extractor": "youtube:tab", "extractor_key": "YoutubeTab", "epoch": 1638037790} \ No newline at end of file diff --git a/tmp/tom_petty/PLoopXDarluPBnuxs4PTC55Sc_2ShAXC0i.jpg b/tmp/tom_petty/PLoopXDarluPBnuxs4PTC55Sc_2ShAXC0i.jpg new file mode 100644 index 00000000..91496804 Binary files /dev/null and b/tmp/tom_petty/PLoopXDarluPBnuxs4PTC55Sc_2ShAXC0i.jpg differ diff --git a/ytdl_subscribe/main.py b/ytdl_subscribe/main.py index a50390a2..6ac0735f 100644 --- a/ytdl_subscribe/main.py +++ b/ytdl_subscribe/main.py @@ -1,5 +1,9 @@ import argparse -from ytdl_subscribe.parse import parse_subscriptions +from ytdl_subscribe.parse import ( + parse_subscriptions, + parse_subscriptions_file, + parse_presets, +) parser = argparse.ArgumentParser( description="YoutubeDL-Subscribe: Download and organize your favorite media easily." @@ -12,29 +16,47 @@ parser.add_argument( help="path to the config yaml, uses subscriptions.yaml if not provided", default="subscriptions.yaml", ) -subparsers = parser.add_subparsers(dest='subparser') -subscription_parser = subparsers.add_parser('s') +subparsers = parser.add_subparsers(dest="subparser") +subscription_parser = subparsers.add_parser("s") subscription_parser.add_argument( "subscriptions", metavar="SUB", nargs="*", help="specific subscriptions to download, downloads all if not provided", ) -download_parser = subparsers.add_parser('dl') -download_parser.add_argument("-p", "--preset", metavar="PRESET", help="which preset to apply") -download_parser.add_argument("-o", "--output", metavar="OUT", help="output path") -download_parser.add_argument("-r", "--overrides", metavar="NAME:VALUE", nargs="+", help="variable overrides formmatted as name:value") +download_parser = subparsers.add_parser("dl") +download_parser.add_argument( + "-p", "--preset", metavar="PRESET", help="which preset to apply" +) +download_parser.add_argument("-o", "--output", metavar="OUT", help="output path") +download_parser.add_argument( + "-r", + "--overrides", + metavar="NAME:VALUE", + nargs="+", + help="variable overrides formmatted as name:value", +) if __name__ == "__main__": args = parser.parse_args() print(args) - subscriptions = parse_subscriptions(args.config) + # subscriptions = parse_subscriptions(args.config) - if args.subparser == 's': - if args.subscriptions: - subscriptions = [s for s in subscriptions if s.name in args.subscriptions] + yaml_dict = parse_subscriptions_file(args.config, set_config_variables=True) + presets = parse_presets(yaml_dict) + # Subscription download + if args.subparser == "s": + subscriptions = parse_subscriptions( + yaml_dict, presets, subscriptions=args.subscriptions + ) for s in subscriptions: s.extract_info() + + # One-off download + if args.subparser == "dl": + preset = args.preset + output_path = args.output_path + overrides = args.overrides diff --git a/ytdl_subscribe/parse.py b/ytdl_subscribe/parse.py index 147907ca..1ae98410 100644 --- a/ytdl_subscribe/parse.py +++ b/ytdl_subscribe/parse.py @@ -11,21 +11,81 @@ def _set_config_variables(config): Subscription.WORKING_DIRECTORY = config.get("working_directory", "") -def parse_subscriptions(subscription_yaml_path): +def parse_subscriptions_file(subscription_yaml_path, set_config_variables=True): + """ + Reads and parses a subscription yaml from its path. + TODO: trafaret the dict for validation + + Parameters + ---------- + subscription_yaml_path: str + File path + set_config_variables: bool + Whether to set global config variables + + Returns + ------- + dict + The subscription yaml after safe_load + """ with open(subscription_yaml_path, "r") as f: yaml_dict = yaml.safe_load(f) config = yaml_dict[YAMLSection.CONFIG_KEY] - _set_config_variables(config) + if set_config_variables: + _set_config_variables(config) + + return yaml_dict + + +def parse_presets(yaml_dict): + """ + Parses presets from a subscription yaml dict + + Parameters + ---------- + yaml_dict: dict + Subscription YAML dict + + Returns + ------- + dict + Presets + """ presets = yaml_dict[YAMLSection.PRESET_KEY] + return presets - subscriptions = [] + +def parse_subscriptions(yaml_dict, presets, subscriptions=None): + """ + Parses subscriptions from a subscription yaml dict + + Parameters + ---------- + yaml_dict: dict + presets: dict + subscriptions: list of str or None + If present, only parse these subscriptions + + Returns + ------- + list of Subscription + """ + parsed_subscriptions = [] + + # Parse all subscriptions even if all are not used for validation's sake for name, subscription in yaml_dict[YAMLSection.SUBSCRIPTIONS_KEY].items(): preset = {} if subscription.get("preset") in presets: preset = presets[subscription["preset"]] subscription = mergedeep.merge({}, preset, subscription) - subscriptions.append(Subscription.from_dict(name, subscription)) + parsed_subscriptions.append(Subscription.from_dict(name, subscription)) - return subscriptions + # Filter subscriptions if present + if subscriptions: + parsed_subscriptions = [ + sub for sub in parsed_subscriptions if sub.name in subscriptions + ] + + return parsed_subscriptions