summaryrefslogtreecommitdiff
path: root/templates/detail.html
diff options
context:
space:
mode:
authorTyler Hoang <tyler@tylerhoang.xyz>2026-05-06 17:20:35 -0700
committerTyler Hoang <tyler@tylerhoang.xyz>2026-05-06 17:20:35 -0700
commit2d298f982408f222ad344b2aa9c18bbe7dc70f12 (patch)
tree7347dff5f45789189032bee2821c3cd314b69625 /templates/detail.html
parent4bbafdd460945eb506ddb07b9068731245708812 (diff)
Add TMDB poster picker to film detail page
- New movie_images() async function in services/tmdb.py fetches poster URLs from TMDB /movie/{id}/images endpoint, filtering for English and no-text posters only - New GET /tmdb/posters endpoint returns list of available posters for a TMDB ID - New POST /films/{film_id}/poster endpoint to save selected poster (mirrors the stars endpoint pattern) - Add "Change Poster" button on detail page (only shown if film has a TMDB ID) that opens a 3-column grid of posters - Selected poster gets accent border, main image updates instantly, no page reload needed - Posters are cached per load to avoid refetching on re-open Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Diffstat (limited to 'templates/detail.html')
-rw-r--r--templates/detail.html96
1 files changed, 96 insertions, 0 deletions
diff --git a/templates/detail.html b/templates/detail.html
index 59779d8..20897b0 100644
--- a/templates/detail.html
+++ b/templates/detail.html
@@ -12,6 +12,23 @@
<span>{{ film.title[:1] }}</span>
{% endif %}
</div>
+
+ {% if film.tmdb_id %}
+ <button
+ type="button"
+ id="change-poster-btn"
+ class="secondary-button"
+ style="width: 100%; margin-top: 12px;"
+ data-tmdb-id="{{ film.tmdb_id }}"
+ data-film-id="{{ film.id }}"
+ >Change Poster</button>
+
+ <div id="poster-picker" style="display: none; margin-top: 12px;">
+ <p id="poster-picker-status" style="color: var(--muted); font-size: 0.86rem; margin: 0 0 10px;">Loading posters…</p>
+ <div id="poster-grid" style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px;"></div>
+ </div>
+ {% endif %}
+
<div class="detail-aside-meta">
<div>
<span class="summary-label">Shelf</span>
@@ -122,4 +139,83 @@
</div>
</section>
</article>
+
+{% if film.tmdb_id %}
+<script>
+(function () {
+ const btn = document.getElementById("change-poster-btn");
+ const picker = document.getElementById("poster-picker");
+ const grid = document.getElementById("poster-grid");
+ const status = document.getElementById("poster-picker-status");
+ const filmId = btn.dataset.filmId;
+ const tmdbId = btn.dataset.tmdbId;
+
+ let loaded = false;
+
+ btn.addEventListener("click", async () => {
+ if (picker.style.display === "none") {
+ picker.style.display = "block";
+ btn.textContent = "Close";
+ } else {
+ picker.style.display = "none";
+ btn.textContent = "Change Poster";
+ return;
+ }
+
+ if (loaded) return;
+ status.textContent = "Loading posters…";
+ status.style.display = "block";
+
+ try {
+ const resp = await fetch(`/tmdb/posters?tmdb_id=${tmdbId}`);
+ if (!resp.ok) throw new Error("fetch failed");
+ const data = await resp.json();
+ status.style.display = "none";
+
+ if (!data.posters.length) {
+ status.textContent = "No posters found.";
+ status.style.display = "block";
+ return;
+ }
+
+ grid.innerHTML = data.posters.map((url) => `
+ <button type="button" class="poster-option" data-url="${url}" style="padding: 0; border: 2px solid transparent; border-radius: 6px; overflow: hidden; cursor: pointer; background: none;">
+ <img src="${url}" alt="Poster option" loading="lazy" style="width: 100%; display: block; aspect-ratio: 2/3; object-fit: cover;">
+ </button>
+ `).join("");
+
+ grid.querySelectorAll(".poster-option").forEach((optBtn) => {
+ optBtn.addEventListener("click", async () => {
+ const url = optBtn.dataset.url;
+
+ grid.querySelectorAll(".poster-option").forEach((b) => b.style.borderColor = "transparent");
+ optBtn.style.borderColor = "var(--accent)";
+
+ try {
+ const saveResp = await fetch(`/films/${filmId}/poster`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify({ poster_url: url }),
+ });
+ if (!saveResp.ok) return;
+
+ const posterImg = document.querySelector(".poster-large img");
+ if (posterImg) posterImg.src = url;
+ picker.style.display = "none";
+ btn.textContent = "Change Poster";
+ } catch (err) {
+ console.error("Failed to save poster", err);
+ }
+ });
+ });
+
+ loaded = true;
+ } catch (err) {
+ status.textContent = "Failed to load posters.";
+ console.error(err);
+ }
+ });
+})();
+</script>
+{% endif %}
{% endblock %}