From 3b28310412b7d8e38a91c81351e6b2ee61065fda Mon Sep 17 00:00:00 2001 From: Dennis Fink Date: Wed, 5 Mar 2025 08:13:23 +0100 Subject: Add pmediainfo --- patternutils/commands/pmediainfo.py | 98 +++++++++++++++++++++++++++++++++++++ pyproject.toml | 4 ++ 2 files changed, 102 insertions(+) create mode 100644 patternutils/commands/pmediainfo.py diff --git a/patternutils/commands/pmediainfo.py b/patternutils/commands/pmediainfo.py new file mode 100644 index 0000000..0fa7b18 --- /dev/null +++ b/patternutils/commands/pmediainfo.py @@ -0,0 +1,98 @@ +import functools +import itertools +import os.path +from typing import Any, Generator, Iterator, Optional + +import click +from pymediainfo import MediaInfo + +from .. import config +from .. import match as mat +from .. import utils + + +def apply_mediainfo( + walk_function: Iterator[os.DirEntry[str]], +) -> Generator[Optional[dict[str, Any]], None, None]: + for f in walk_function: + media_info_raw = MediaInfo.parse(os.path.abspath(f)) + if len(media_info_raw.tracks) <= 1: + click.secho(f"{f.name} cannot be parsed by mediainfo", fg="red", err=True) + yield None + else: + media_info = media_info_raw.to_data() + media_info["_path"] = f.path + media_info["_name"] = f.name + media_info["_abspath"] = os.path.abspath(f.path) + media_info["_realpath"] = os.path.realpath(f.path) + media_info["_relpath"] = os.path.relpath(f.path) + yield media_info + + +@click.command(context_settings={"help_option_names": ("-h", "--help", "-?")}) +@click.option("-d", "--directory", multiple=True, default=["./"]) +@click.option( + "-r", + "--recursive", + is_flag=True, + default=False, + help="search directories recursively", +) +@click.option( + "--abort-on-unparseable", + is_flag=True, + default=False, + help="exit if a file cannot be parsed by mediainfo", +) +@click.option( + "--stream", + is_flag=True, + default=False, + help="Output a stream of objects instead a list of objects", +) +@click.option( + "--human-readable", + is_flag=True, + default=False, + help="output the JSON in a human readable format", +) +@click.option( + "-v", "--verbose", is_flag=True, default=False, help="explain what is being done" +) +@click.version_option() +def pmediainfo( + directory: list[str], + recursive: bool, + abort_on_unparseable: bool, + stream: bool, + human_readable: bool, + verbose: bool, +) -> None: + # Monkey patch walk function to include commandline options + walk_function = functools.partial( + utils.walk, recursive=recursive, match_directories=False + ) + new_walk = itertools.chain.from_iterable(map(walk_function, directory)) + + has_unparseable_files = False + parsed_data = [] + + for media_info in apply_mediainfo(new_walk): + if media_info is None: + has_unparseable_files = True + if stream and abort_on_unparseable: + raise SystemExit + else: + if stream: + click.echo(utils.json_dumps(media_info, human_readable)) + else: + parsed_data.append(media_info) + + if not stream: + if has_unparseable_files and abort_on_unparseable: + raise SystemExit + click.echo(utils.json_dumps(parsed_data, human_readable)) + + +if __name__ == "__main__": + pmediainfo() diff --git a/pyproject.toml b/pyproject.toml index 265aa8c..f6942c2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,9 @@ pygments = [ prss = [ "feedparser >=6.0.8, <7.0.0", ] +pmediainfo = [ + "pymediainfo >=6.1.0, <7.0.0", +] [project.scripts] pmatch = "patternutils.commands.pmatch:pmatch" @@ -33,6 +36,7 @@ tln = "patternutils.commands.tln:tln" patterncfg = "patternutils.commands.patterncfg:patterncfg" prss = "patternutils.commands.prss:prss" pjson = "patternutils.commands.pjson:pjson" +pmediainfo = "patternutils.commands.pmediainfo:pmediainfo" [dependency-groups] dev = [ -- cgit v1.3.1