#!/usr/bin/env python3 # File: library_info_cli.py # Author: bgstack15 # Startdate: 2024-07-06-7 15:19 # Title: CLI for library_info # Project: library_info # Purpose: cli client for library_info_lib # History: # Usage: --help # Reference: # Improve: # Dependencies: # dep-almalinux8: python3-requests, python3-dateutil import argparse, sys, json, datetime import library_info_lib parser = argparse.ArgumentParser(description="Shows currently checked out items from the configured libraries.") parser.add_argument("-d","--debug", nargs='?', default=0, type=int, choices=range(0,11), help="Set debug level. >=5 adds verbose=True to get_checkouts().") # add output option: html, raw, json # add mutual: all or single. group1 = parser.add_mutually_exclusive_group() group1.add_argument("-s","--single", help="Show this single account.") group1.add_argument("-a","--all", action='store_true', default=True, help="Check all accounts") parser.add_argument("-o","--output", choices=["html","json","raw"], default="raw", help="Output format.") try: # This was only added in python 3.9 parser.add_argument("-f","--full", action=argparse.BooleanOptionalAction, default=True, help="Use full image objects or not. They are huge and during debugging it is useful to turn off.") except AttributeError: group2 = parser.add_mutually_exclusive_group() group2.add_argument("-f","--full", action="store_true", default=True, help="Use full image objects or not. They are huge and during debugging it is useful to turn off.") group2.add_argument("--no-f","--no-full", action="store_true", default=False) args = parser.parse_args() debuglevel = 0 if args.debug is None: # -d was used but no value provided debuglevel = 10 elif args.debug: debuglevel = args.debug full_images = args.full single = args.single output = args.output def prn(*args,**kwargs): kwargs["end"] = "" print(*args,**kwargs) def eprint(*args,**kwargs): kwargs["file"] = sys.stderr print(*args,**kwargs) def serialize(item): eprint(f"DEBUG: trying to serialize {item}, type {type(item)}") if type(item) == datetime.datetime: # We know library due dates are just a day, and not a time. return item.strftime("%F") else: eprint(f"WARNING: unknown type {type(item)} for json-serializing object {item}") return item def html(checkouts): # Uses https://datatables.net/download/builder?dt/jq-3.7.0/dt-2.0.8/cr-2.0.3/fh-4.0.1 # with css corrected by having the utf-8 line at the top of the .min.css file. """ Make an html of the items """ prn("\n") prn("\n") prn('\n') prn('\n') prn('\n') prn('') # inline css, if any prn('\n') prn("Library checkouts\n") prn("\n") prn("\n") seen_accounts = [] for i in checkouts: if i["patron"] not in seen_accounts: seen_accounts.append(i["patron"]) if seen_accounts: prn("

Accounts: ") prn(", ".join(seen_accounts)) prn("

\n") try: # fails on python36 on almalinux8 now = datetime.datetime.now(datetime.UTC) except AttributeError: now = datetime.datetime.utcnow() prn("Last modified: " + now.strftime("%FT%TZ") + "\n") prn("

Checkouts

\n") if len(checkouts): prn("\n") prn(f"\n") prn("\n") for i in checkouts: prn(f"") prn(f"") prn(f"") due = i["due"].strftime("%F") prn(f"") if "img" in i: img_src = i["img"] else: img_src = "" #prn(f"") prn(f"") prn(f"") prn(f"") prn(f"\n") prn(f"\n") prn(f"
PatronbarcodedueformatcoverTitle
{i['patron']}{i['barcode']}{due}{i['format']} {i['format']}{i['title']}
\n") else: prn(f"No checkouts.\n") prn(f"\n") prn(f"\n") prn('') # disable paging, because I dislike it. # Use column 2 (due date) ascending as initial sort. prn(""" """) prn(f"") if "__main__" == __name__: if debuglevel >= 1: eprint(args) if single: checkouts = library_info_lib.get_single_checkouts(alias = single, full_images = full_images, verbose = debuglevel >= 5) else: checkouts = library_info_lib.get_all_checkouts(full_images = full_images, verbose = debuglevel >= 5) if "raw" == output: print(checkouts) elif "json" == output: print(json.dumps(checkouts,default=serialize)) elif "html" == output: html(checkouts) else: print(f"Error! Invalid choice for output format {output}.")