116 lines
4.4 KiB
Python
116 lines
4.4 KiB
Python
import imdb
|
|
import jsonfile
|
|
|
|
ABOUT_FILE = "about.json"
|
|
MEDIA_KINDS = {
|
|
"show": {"key": "shows", "label": "TV show", "omdb_type": "series"},
|
|
"movie": {"key": "movies", "label": "movie", "omdb_type": "movie"}
|
|
}
|
|
|
|
|
|
def load_items(kind: str) -> tuple[dict, list[dict]]:
|
|
data = jsonfile.load(ABOUT_FILE)
|
|
return data, data.setdefault(MEDIA_KINDS[kind]["key"], [])
|
|
|
|
|
|
def find_index(items: list[dict], text: str) -> int | None:
|
|
identifier = imdb.imdb_id(text)
|
|
for index, item in enumerate(items):
|
|
if identifier and imdb.imdb_id(item.get("url", "")) == identifier:
|
|
return index
|
|
if item.get("name", "").lower() == text.lower():
|
|
return index
|
|
return None
|
|
|
|
|
|
def valid_rating(value: str) -> int:
|
|
rating = int(value)
|
|
if not 0 <= rating <= 10:
|
|
raise ValueError("Rating must be between 0 and 10")
|
|
return rating
|
|
|
|
|
|
def list_items(arguments) -> None:
|
|
_, items = load_items(arguments.kind)
|
|
if not items:
|
|
print(f"No {MEDIA_KINDS[arguments.kind]['label']}s yet.")
|
|
return
|
|
for item in sorted(items, key=lambda entry: -entry.get("rating", 0)):
|
|
print(f"{item.get('rating', '?'):>3}/10 {item.get('name')} {item.get('url')}")
|
|
|
|
|
|
def resolve_name(arguments, identifier: str) -> str | None:
|
|
if arguments.name:
|
|
return arguments.name
|
|
details = imdb.lookup(identifier)
|
|
if not details:
|
|
print("Could not look up the title. Pass --name, or set OMDB_API_KEY in .env.")
|
|
return None
|
|
expected_type = MEDIA_KINDS[arguments.kind]["omdb_type"]
|
|
if details.get("Type") != expected_type:
|
|
print(f"Warning: OMDb lists {details.get('Title')} as a {details.get('Type')}, not a {expected_type}.")
|
|
return details.get("Title")
|
|
|
|
|
|
def add_item(arguments) -> None:
|
|
identifier = imdb.imdb_id(arguments.title)
|
|
if not identifier:
|
|
print(f"{arguments.title} is not an IMDb link or ID.")
|
|
return
|
|
data, items = load_items(arguments.kind)
|
|
if find_index(items, identifier) is not None:
|
|
print(f"{identifier} is already listed. Use rate to change its rating.")
|
|
return
|
|
name = resolve_name(arguments, identifier)
|
|
if not name:
|
|
return
|
|
items.append({"name": name, "rating": arguments.rating, "url": imdb.title_url(identifier)})
|
|
jsonfile.save(ABOUT_FILE, data)
|
|
print(f"Added {name} ({arguments.rating}/10)")
|
|
|
|
|
|
def remove_item(arguments) -> None:
|
|
data, items = load_items(arguments.kind)
|
|
index = find_index(items, arguments.title)
|
|
if index is None:
|
|
print(f"{arguments.title} is not listed.")
|
|
return
|
|
removed = items.pop(index)
|
|
jsonfile.save(ABOUT_FILE, data)
|
|
print(f"Removed {removed.get('name')}")
|
|
|
|
|
|
def rate_item(arguments) -> None:
|
|
data, items = load_items(arguments.kind)
|
|
index = find_index(items, arguments.title)
|
|
if index is None:
|
|
print(f"{arguments.title} is not listed.")
|
|
return
|
|
items[index]["rating"] = arguments.rating
|
|
jsonfile.save(ABOUT_FILE, data)
|
|
print(f"Rated {items[index].get('name')} {arguments.rating}/10")
|
|
|
|
|
|
def register(subparsers) -> None:
|
|
for kind, settings in MEDIA_KINDS.items():
|
|
parser = subparsers.add_parser(kind, help=f"Manage the {settings['label']}s on the about page")
|
|
parser.set_defaults(kind=kind)
|
|
actions = parser.add_subparsers(dest="action", required=True)
|
|
|
|
actions.add_parser("list", help=f"List {settings['label']}s").set_defaults(handler=list_items)
|
|
|
|
add_parser = actions.add_parser("add", help=f"Add a {settings['label']} by IMDb link or ID")
|
|
add_parser.add_argument("title", help="IMDb link or ID, like tt0816692")
|
|
add_parser.add_argument("--rating", type=valid_rating, required=True, help="Your rating from 0 to 10")
|
|
add_parser.add_argument("--name", help="Display name, looked up on OMDb when left out")
|
|
add_parser.set_defaults(handler=add_item)
|
|
|
|
remove_parser = actions.add_parser("remove", help=f"Remove a {settings['label']}")
|
|
remove_parser.add_argument("title", help="IMDb link, ID or name")
|
|
remove_parser.set_defaults(handler=remove_item)
|
|
|
|
rate_parser = actions.add_parser("rate", help=f"Change a {settings['label']}'s rating")
|
|
rate_parser.add_argument("title", help="IMDb link, ID or name")
|
|
rate_parser.add_argument("rating", type=valid_rating, help="New rating from 0 to 10")
|
|
rate_parser.set_defaults(handler=rate_item)
|