Save OMDb details and posters locally

This commit is contained in:
SirBlob committed 2026-11-01 22:58:56 -05:00
1 parent 1f7e88f117
commit 4f78883f0b
6 files changed
+239 -7

No files matched your search

+50
View File
@@ -1,13 +1,19 @@
import time
from rich.text import Text
from textual import work
from textual.app import ComposeResult
from textual.binding import Binding
from textual.widgets import DataTable
import imdb
import media
import media_cache
from tui.cache_indicator import cache_state, cache_text
from tui.content_pane import ContentPane
from tui.dialogs import ConfirmDialog, FormDialog, FormField
REQUEST_DELAY_SECONDS = 0.5
STATUS_STYLES = {"watching": "blue", "watched": "green", "planning": "magenta"}
@@ -22,6 +28,8 @@ class MediaPane(ContentPane):
Binding("s", "status", "Status"),
Binding("g", "collection", "Group"),
Binding("d", "delete", "Delete"),
Binding("u", "refresh", "Refresh"),
Binding("C", "cache_all", "Cache all"),
Binding("r", "reload", "Reload"),
]
@@ -42,20 +50,27 @@ class MediaPane(ContentPane):
table.add_column("Rating", key="rating")
table.add_column("Title", key="title")
table.add_column("Group", key="collection")
table.add_column("Year", key="year")
table.add_column("Cache", key="cache")
table.add_column("IMDb", key="imdb")
self.reload()
def reload(self, focus_key: str | None = None):
table = self.table()
table.clear()
stored = media_cache.load_details()
for item in media.list_items(self.kind):
identifier = imdb.imdb_id(item.get("url", "")) or item.get("name", "")
status = media.status_of(item)
details = stored.get(identifier)
state = cache_state(bool(details), bool(details) and media_cache.has_local_poster(identifier, details))
table.add_row(
Text(status, style=STATUS_STYLES[status]),
rating_text(item),
item.get("name", ""),
item.get("collection", ""),
(details or {}).get("year") or "-",
cache_text(state),
identifier,
key=identifier,
)
@@ -148,3 +163,38 @@ class MediaPane(ContentPane):
self.run_now(lambda: media.remove_item(self.kind, identifier), f"Removed {name}")
self.app.push_screen(ConfirmDialog(f"Remove {name}?"), confirmed)
def action_refresh(self):
item = self.selected_item()
if not item:
return
identifier = imdb.imdb_id(item["url"])
def refreshed(details: dict):
self.reload(identifier)
self.notify(f"Saved details and poster for {item['name']}")
self.run_in_background(f"Looking up {item['name']} on OMDb...", lambda: media.refresh_details(identifier), refreshed)
def action_cache_all(self):
missing = media.missing_details(self.kind)
if not missing:
self.notify(f"Every {self.label} already has saved details and a poster")
return
self.notify(f"Saving details for {len(missing)} titles...")
self.cache_missing_details(missing)
@work(thread=True, exclusive=True, group="media-cache")
def cache_missing_details(self, missing: list[str]):
saved = 0
for index, identifier in enumerate(missing):
if index:
time.sleep(REQUEST_DELAY_SECONDS)
try:
media.refresh_details(identifier)
except (OSError, ValueError) as error:
self.app.call_from_thread(self.notify, f"{identifier}: {error}", title="Skipped", severity="warning")
continue
saved += 1
self.app.call_from_thread(lambda: self.reload(self.selected_key()))
self.app.call_from_thread(self.notify, f"Saved {saved} of {len(missing)} titles")