Files
website/tools/content/media.py
T
2026-10-31 22:53:17 -04:00

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)