diff options
author | Wolfgang Müller | 2024-10-26 20:59:35 +0200 |
---|---|---|
committer | Wolfgang Müller | 2024-11-06 21:29:59 +0100 |
commit | ec4750b5e2f801fec7e1100299114483d4a04f4e (patch) | |
tree | 6f4f36d43f25ae69c022aa1bf1ac08cf3a2fae48 | |
parent | 9e7ede5afcbc99a3670ee8232ecfbce79da0dde8 (diff) | |
download | later-ec4750b5e2f801fec7e1100299114483d4a04f4e.tar.gz |
Use getopt-based parser for command-line arguments
Upcoming commits will want to make use of bespoke argument handling
alongside subcommands and using Python's argparse proved unable to
easily handle that kind of complexity. Therefore switch to the more
basic getopt-based parser with which we can implement our own logic.
Without argparse we're no longer bound to having an autogenerated help
listing, so stop mentioning that in the manual. Instead have later(1)
output a concise usage listing when given an unknown argument.
Since we'll be adding more commands to later(1) in the future, also
specify an explicit "list" command.
-rwxr-xr-x | later | 89 | ||||
-rw-r--r-- | later.1 | 20 |
2 files changed, 87 insertions, 22 deletions
@@ -1,13 +1,14 @@ #!/usr/bin/env python3 -import argparse import datetime +import getopt import json import os import re import sys -from dataclasses import dataclass +from dataclasses import dataclass, field from datetime import datetime as dt +from typing import Protocol class YTDLPLogger: @@ -25,6 +26,18 @@ def exit(message=""): sys.exit(f"later: {message}" if message else 0) +def usage(message=""): + lines = [] + if message: + lines.append(f"later: {message}") + lines.append("") + + lines.append("usage: later [options] [list]") + lines.append("options: [-u | --update-titles]") + + sys.exit("\n".join(lines)) + + def get_xdg(directory, fallback): env = f"XDG_{directory.upper()}_HOME" if env in os.environ: @@ -138,6 +151,54 @@ class TitleMap: exit(f"cannot write title cache: {err}") +class CommandFunction(Protocol): + def __call__(self, args: "Arguments", title_map: TitleMap) -> None: + pass + + +@dataclass +class Command: + name: str + fun: CommandFunction + implies_list: bool = True + args: bool = True + + +@dataclass +class Arguments: + command: Command + update_titles: bool = False + rest: list[str] = field(default_factory=list) + + +def parse_args(argv, commands, default): + try: + options, args = getopt.gnu_getopt(argv, "u", "update-titles") + except getopt.GetoptError as e: + usage(e) + + parsed_args = Arguments(command=commands[default]) + + for option in options: + match option: + case ("-u", _) | ("--update-titles", _): + parsed_args.update_titles = True + + if args: + if args[0] in commands: + parsed_args.command = commands[args.pop(0)] + + parsed_args.rest = args + + if parsed_args.rest and not parsed_args.command.args: + usage(f'unexpected argument for "{parsed_args.command.name}"') + + if not parsed_args.rest and parsed_args.command.args: + usage(f'"{parsed_args.command.name}" requires an argument') + + return parsed_args + + def entries(title_map): def get_mtime(entry): return entry.stat().st_mtime @@ -163,20 +224,20 @@ def entries(title_map): yield WatchLaterEntry(name=name, path=entry.path, mtime=mtime) -parser = argparse.ArgumentParser( - prog="later", description="List mpv's watch_later entries" -) -parser.add_argument( - "-u", - "--update-titles", - action="store_true", - help="update titles of videos using yt-dlp", -) -args = parser.parse_args() +def list_entries(args, title_map): + for entry in entries(title_map): + print(entry.format(title_map)) + + +commands = {"list": Command("list", list_entries, implies_list=False, args=False)} + +args = parse_args(sys.argv[1:], commands, "list") title_map = TitleMap(title_map_file, update=args.update_titles) -for entry in entries(title_map): - print(entry.format(title_map)) +args.command.fun(args=args, title_map=title_map) + +if args.command.implies_list: + list_entries(args, title_map) title_map.maybe_commit() @@ -1,4 +1,4 @@ -.Dd September 20, 2024 +.Dd October 26, 2024 .Dt LATER 1 .Os .Sh NAME @@ -6,12 +6,11 @@ .Nd list mpv's watch_later entries .Sh SYNOPSIS .Nm -.Op Fl u | \-update-titles -.Nm -.Fl h | \-help +.Op options +.Op Ic list .Sh DESCRIPTION .Nm -lists all watch_later entries as saved by +is a program to manage watch_later entries as created by .Xr mpv 1 . .Pp In order to display file names and URLs for an entry, the @@ -19,12 +18,17 @@ In order to display file names and URLs for an entry, the option must be set in .Xr mpv 1 . .Pp -The options are as follows: +The following options can be given for any command: .Bl -tag -width "-h, --update-titles" .It Fl u , Fl \-update-titles update titles of videos using yt-dlp -.It Fl h , Fl \-help -show a concise help message +.El +.Pp +The commands are as follows: +.Bl -tag -width Ds +.It Sy list +Lists all watch_later entries. +This command is implied if there are no remaining arguments. .El .Sh FILES .Bl -tag -width "1" |