From ae47d476f3dde0d1e2f37ce29721cf56213754bb Mon Sep 17 00:00:00 2001 From: Maks Snegov Date: Wed, 9 Feb 2022 18:08:06 +0300 Subject: [PATCH] Add parse/rename CLI options --- renamer.py | 106 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 70 insertions(+), 36 deletions(-) diff --git a/renamer.py b/renamer.py index 7e4cf40..99693b9 100755 --- a/renamer.py +++ b/renamer.py @@ -2,9 +2,11 @@ import argparse import collections +import enum import logging import os import os.path +import pprint import re import sys @@ -42,12 +44,48 @@ PATTERNS = ( ("unknown", r".*") ) + +# noinspection PyInterpreter +class EnumAction(argparse.Action): + """ + Argparse action for handling Enums + """ + def __init__(self, **kwargs): + # Pop off the type value + enum_type = kwargs.pop("type", None) + + # Ensure an Enum subclass is provided + if enum_type is None: + raise ValueError("type must be assigned an Enum when using EnumAction") + if not issubclass(enum_type, enum.Enum): + raise TypeError("type must be an Enum when using EnumAction") + + # Generate choices from the Enum + kwargs.setdefault("choices", tuple(e.value for e in enum_type)) + + super(EnumAction, self).__init__(**kwargs) + + self._enum = enum_type + + def __call__(self, parser, namespace, values, option_string=None): + # Convert value back into an Enum + value = self._enum(values) + setattr(namespace, self.dest, value) + + +class CliAction(enum.Enum): + parse = "parse" + rename = "rename" + + _lg = logging.getLogger("spqr.movie-renamer") def main(): parser = argparse.ArgumentParser(description="Rename media files.") - parser.add_argument("target", type=str, + parser.add_argument("action", type=CliAction, action=EnumAction, metavar="ACTION", + help="what to do with media file/directory (%(choices)s)") + parser.add_argument("target", type=str, metavar="TARGET", help="path to the media file/directory") parser.add_argument("-v", "--verbose", action="store_true", default=False, help="verbose output") @@ -56,23 +94,41 @@ def main(): loglevel = logging.DEBUG if args.verbose else logging.INFO logging.basicConfig(level=loglevel) - if os.path.isdir(args.target): - process_dir(args.target) - else: - process_file(args.target) + process_path(args.action, args.target) return 0 -def process_dir(dir_path): - """ - Process dir with media files. - If this dir is season of some tv show -> process them as season. - Otherwise -> process each file individually. - """ - for fname in os.listdir(dir_path): - fpath = os.path.join(dir_path, fname) - process_file(fpath) +def process_path(action: CliAction, path): + # process only files + if os.path.isdir(path): + for child_path in sorted(os.listdir(path)): + process_path(action, os.path.join(path, child_path)) + + # split filepath to dir path, title, and extension + dir_path, fname = os.path.split(path) + title, ext = os.path.splitext(fname) + ext = ext[1:] + if ext not in PROCESSED_FILETYPES: + _lg.debug("Extension is not supported: %s", path) + return + + parsed_title = parse_title(title) + if action == CliAction.parse: + print_parsed_title(title, parsed_title) + return + + if action == CliAction.rename: + pretty_title = generate_pretty_name(parsed_title) + pretty_title += ".%s" % ext + if pretty_title != fname: + _lg.warning("%s -> %s", fname, pretty_title) + return + + +def print_parsed_title(title, parsed): + print(title) + pprint.pprint(parsed, indent=4) def generate_pretty_name(parsed_title): @@ -91,28 +147,6 @@ def generate_pretty_name(parsed_title): return result -def process_file(fpath): - # process only files - if not os.path.isfile(fpath): - _lg.debug("Not a file: %s", fpath) - return - - # split filepath to dir path, title, and extension - dir_path, fname = os.path.split(fpath) - title, ext = os.path.splitext(fname) - ext = ext[1:] - if ext not in PROCESSED_FILETYPES: - _lg.debug("Extension is not supported: %s", fpath) - return - - parsed_title = parse_title(title) - pretty_title = generate_pretty_name(parsed_title) - pretty_title += ".%s" % ext - - if pretty_title != fname: - _lg.warning("%s -> %s", fname, pretty_title) - - def _get_parsed_title_dict(chunk_list, chunk_map): """ Get {chunk_type: [chunk_value_1, ..., chunk_value_n]} dictionary. """ p_title = collections.defaultdict(list)