← back to AsSeenInMovies
api/spotted/featured: N (default 6, max 24) verified spotted placements with movie context
e3ecee03e5cea69d567075664ae17df455fe307c · 2026-05-13 10:10:54 -0700 · SteveStudio2
Files touched
M server.jsM test/smoke.js
Diff
commit e3ecee03e5cea69d567075664ae17df455fe307c
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date: Wed May 13 10:10:54 2026 -0700
api/spotted/featured: N (default 6, max 24) verified spotted placements with movie context
---
server.js | 19 +++++++++++++++++++
test/smoke.js | 5 +++++
2 files changed, 24 insertions(+)
diff --git a/server.js b/server.js
index 0b6cbd4..158bd5d 100644
--- a/server.js
+++ b/server.js
@@ -109,6 +109,7 @@ app.get('/api', (_req, res) => {
'GET /api/spotted': 'Verified SPOTTED placements (limit ≤ 200, optional category=…)',
'GET /api/spotted/stats': 'Aggregate counts (pending/live/rejected/submitted_7d/films/brands/categories)',
'GET /api/spotted/random': 'A single random verified SPOTTED placement (with movie context)',
+ 'GET /api/spotted/featured':'N random verified SPOTTED placements (?n=6, max 24) — multi-row companion',
'GET /api/movies/random': 'A single random poster-having movie',
'GET /api/people/random': 'A single random headshot-having person',
'GET /api/credits/stats': 'Aggregate counts on asim_credits (total, acting, directing, writing, distinct_people, distinct_movies)',
@@ -823,6 +824,24 @@ app.get('/api/spotted/random', async (_req, res) => {
}
});
+// /api/spotted/featured — N (default 6, max 24) verified spotted rows with
+// movie context, randomly sampled. Multi-row companion to /api/spotted/random.
+// Used by widgets that want a small grid inline. 60s cache + 120s SWR.
+app.get('/api/spotted/featured', async (req, res) => {
+ try {
+ const n = Math.min(Math.max(parseInt(req.query.n, 10) || 6, 1), 24);
+ 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`, [n]);
+ res.setHeader('Cache-Control', 'public, max-age=60, stale-while-revalidate=120');
+ res.json({ spotted: r.rows });
+ } catch (e) { res.status(500).json({ error: e.message }); }
+});
+
// /api/credits/stats — aggregate counts on asim_credits. Departments, actors
// vs crew, top contributors. Cached 5 min (363k rows is heavy to recount).
//
diff --git a/test/smoke.js b/test/smoke.js
index 3e1408c..0be75c3 100644
--- a/test/smoke.js
+++ b/test/smoke.js
@@ -134,6 +134,11 @@ function check(name, cond, hint = '') {
check('api/spotted/random: 200', r.status === 200);
check('api/spotted/random: spotted field', /"spotted":\{/.test(r.body));
+ // 11b2. /api/spotted/featured?n=3
+ r = await fetch('/api/spotted/featured?n=3');
+ check('api/spotted/featured: 200', r.status === 200);
+ check('api/spotted/featured: array', /"spotted":\[/.test(r.body));
+
// 11c. /api/credits/stats
r = await fetch('/api/credits/stats');
check('api/credits/stats: 200', r.status === 200);
← d1d1f7a smoke: 4 assertions for /api/version (200, name, git sha, no
·
back to AsSeenInMovies
·
smoke: assert /api/version Cache-Control no-store db4fdf7 →