diff --git a/wavinfo/__main__.py b/wavinfo/__main__.py index a7a4de9..d144d68 100644 --- a/wavinfo/__main__.py +++ b/wavinfo/__main__.py @@ -7,6 +7,9 @@ import sys import json from enum import Enum from base64 import b64encode +from cmd import Cmd +from shlex import split +from typing import List, Dict class MyJSONEncoder(json.JSONEncoder): @@ -23,6 +26,85 @@ class MissingDataError(RuntimeError): pass +class MetaBrowser(Cmd): + prompt = "(wavinfo) " + + metadata: List | Dict + path: List[str] = [] + + @property + def cwd(self): + root: List | Dict = self.metadata + for key in self.path: + if isinstance(root, list): + root = root[int(key)] + else: + root = root[key] + + return root + + @staticmethod + def print_value(collection, key): + val = collection[key] + if isinstance(val, int): + print(f" - {key}: {val}") + elif isinstance(val, str): + print(f" - {key}: \"{val}\"") + elif isinstance(val, dict): + print(f" - {key}: Dict ({len(val)} keys)") + elif isinstance(val, list): + print(f" - {key}: List ({len(val)} keys)") + elif isinstance(val, bytes): + print(f" - {key}: ({len(val)} bytes)") + elif val == None: + print(f" - {key}: (NO VALUE)") + else: + print(f" - {key}: Unknown") + + def do_ls(self, _): + 'List items at the current node: LS' + root = self.cwd + + if isinstance(root, list): + print(f"List:") + for i in range(len(root)): + self.print_value(root, i) + + elif isinstance(root, dict): + print(f"Dictionary:") + for key in root: + self.print_value(root, key) + + else: + print(f"Cannot print node, is not a list or dictionary.") + + def do_cd(self, args): + 'Switch to a different node: CD node-name | ".."' + argv = split(args) + if argv[0] == "..": + self.path = self.path[0:-1] + else: + if isinstance(self.cwd, list): + if int(argv[0]) < len(self.cwd): + self.path = self.path + [argv[0]] + else: + print(f"Index {argv[0]} does not exist") + elif isinstance(self.cwd, dict): + if argv[0] in self.cwd.keys(): + self.path = self.path + [argv[0]] + else: + print(f"Key \"{argv[0]}\" does not exist") + + if len(self.path) > 0: + self.prompt = "(" + "/".join(self.path) + ") " + else: + self.prompt = "(wavinfo) " + + def do_bye(self, _): + 'Exit the interactive browser: BYE' + return True + + def main(): parser = OptionParser() @@ -38,7 +120,15 @@ def main(): default=False, action='store_true') + parser.add_option('-i', + help='Read metadata with an interactive prompt', + default=False, + action='store_true') + (options, args) = parser.parse_args(sys.argv) + + interactive_dict = [] + for arg in args[1:]: try: this_file = WavInfoReader(path=arg) @@ -65,7 +155,12 @@ def main(): ret_dict['scopes'][scope][name] = value - json.dump(ret_dict, cls=MyJSONEncoder, fp=sys.stdout, indent=2) + if options.i: + interactive_dict.append(ret_dict) + else: + json.dump(ret_dict, cls=MyJSONEncoder, fp=sys.stdout, + indent=2) + except MissingDataError as e: print("MissingDataError: Missing metadata (%s) in file %s" % (e, arg), file=sys.stderr) @@ -73,6 +168,12 @@ def main(): except Exception as e: raise e + if len(interactive_dict) > 0: + cli = MetaBrowser() + cli.metadata = interactive_dict + cli.cmdloop() + + if __name__ == "__main__": main()