diff options
-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" |