[object Object]

← back to Ventura Corridor

iter 148: /api/magazine/lottery?n=N&cat= — random N features for rotators/IG backup picks

a9953cdd6bdc694e81e8be2ef510c66ab52010a7 · 2026-05-06 19:14:56 -0700 · SteveStudio2

Files touched

Diff

commit a9953cdd6bdc694e81e8be2ef510c66ab52010a7
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date:   Wed May 6 19:14:56 2026 -0700

    iter 148: /api/magazine/lottery?n=N&cat= — random N features for rotators/IG backup picks
---
 src/server/index.ts | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/src/server/index.ts b/src/server/index.ts
index dcb7bf2..281bb82 100644
--- a/src/server/index.ts
+++ b/src/server/index.ts
@@ -1891,6 +1891,39 @@ app.get('/api/magazine/random', async (req, res) => {
   }
 });
 
+// Lottery — N random published features. Useful for "5 you may have missed" rails,
+// IG-autopost backup picks, and the fleet-tv rotator. Optional ?cat= filter; ?n= clamps to 1..50.
+app.get('/api/magazine/lottery', async (req, res) => {
+  try {
+    const cat = String(req.query.cat || '').trim() || null;
+    const n = Math.min(50, Math.max(1, parseInt(String(req.query.n || 5), 10) || 5));
+    const where: string[] = [`mf.status = 'published'`, `length(mf.editorial) > 200`];
+    const params: any[] = [];
+    if (cat) { params.push(cat); where.push(`mf.category_tag = $${params.length}`); }
+    params.push(n);
+    const r = await query(
+      `SELECT mf.id, mf.headline, mf.subhead, mf.pull_quote, mf.category_tag,
+              mf.published_at, COALESCE(mf.taps, 0) AS taps, COALESCE(mf.views, 0) AS views,
+              b.name AS biz_name, b.address AS biz_address, b.city
+       FROM magazine_features mf JOIN businesses b ON b.id = mf.business_id
+       WHERE ${where.join(' AND ')}
+       ORDER BY random() LIMIT $${params.length}`,
+      params
+    );
+    res.json({
+      count: r.rowCount,
+      cat,
+      features: r.rows.map((f: any) => ({
+        ...f,
+        permalink: `/magazine/${f.id}`,
+        share_card: `/share/${f.id}`,
+      })),
+    });
+  } catch (e: any) {
+    res.status(500).json({ error: e.message });
+  }
+});
+
 // Per-feature TTS audio — /api/magazine/:id/audio.aiff
 // Uses macOS `say` command. Caches by editorial-hash so we don't re-render every visit.
 import { existsSync as _fs_exists, mkdirSync as _fs_mkdir, statSync as _fs_stat, createReadStream as _fs_stream } from 'node:fs';

← af14cb7 iter 147: /api/magazine.json now accepts ?cat= and ?limit= f  ·  back to Ventura Corridor  ·  iter 149: per-feature editor margin notes — collapsible "add f050969 →