← back to AsSeenInMovies
asseeninmovies: GET /api/spotted/random — JSON companion to /random/movie/person. 60s cache+SWR. Returns {spotted: {...}} with movie context. 57/57.
0f3342b268be32f4a6f00f843f111640270236a8 · 2026-05-13 06:05:17 -0700 · SteveStudio2
Files touched
Diff
commit 0f3342b268be32f4a6f00f843f111640270236a8
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date: Wed May 13 06:05:17 2026 -0700
asseeninmovies: GET /api/spotted/random — JSON companion to /random/movie/person. 60s cache+SWR. Returns {spotted: {...}} with movie context. 57/57.
---
server.js | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/server.js b/server.js
index fd90254..f5cc4f7 100644
--- a/server.js
+++ b/server.js
@@ -723,6 +723,26 @@ app.get('/api/spotted', async (req, res) => {
// JSON stats — same numbers the /spotted gallery + /spotted/queue strips
// render, exposed as a single small API. Useful for the status-loop tail
// monitor and any external dashboard. No auth needed — public counts only.
+// /api/spotted/random — JSON companion to /random/movie /random/person.
+// Pulls a single verified SPOTTED row at random. Useful for widgets that
+// want to feature "a placement from the catalog" inline. 60s cache.
+app.get('/api/spotted/random', async (_req, res) => {
+ try {
+ const r = await pool.query(`
+ SELECT s.id, s.product_name, s.product_category, s.brand,
+ s.scene_description, s.scene_timecode, s.shop_url,
+ m.id AS movie_id, m.title AS movie_title, m.release_year, m.poster_url
+ FROM asim_spotted s JOIN asim_movies m ON m.id = s.movie_id
+ WHERE s.verified_at IS NOT NULL AND (s.verified_by IS NULL OR s.verified_by NOT LIKE 'rejected%')
+ ORDER BY random() LIMIT 1`);
+ if (!r.rows[0]) return res.status(404).json({ error: 'no-spotted-yet' });
+ res.setHeader('Cache-Control', 'public, max-age=60, stale-while-revalidate=120');
+ res.json({ spotted: r.rows[0] });
+ } catch (e) {
+ res.status(500).json({ error: e.message });
+ }
+});
+
app.get('/api/spotted/stats', async (_req, res) => {
// Short Cache-Control — stats don't change second-to-second. 30s lets
// crawlers/dashboards/status-loop poll without hammering pg.
← 15d32a7 asseeninmovies: smoke +gzip header check on /movies (verifie
·
back to AsSeenInMovies
·
asseeninmovies: /api discovery doc — list /api/spotted/rando 11f5c83 →