bidaangmamamayan/scripts/cron-crawl.cjs
Ryan 6b06e08c08 BidaAngMamayan: public supporter tribute news desk for Senator BAM Aquino
Forked from Forthena (PERSONAL/forthena) and retargeted:
- NO login, NO LLM: the edition is public and the ranking is deterministic
  (stories that name Sen. BAM lead; freshest first) — Daniel: no
  like/dislike or store profile for visitors.
- Crawler scoped to BAM: Bing news keyword queries + Inquirer/Rappler
  fallback wires, with a two-tier relevance gate (named-BAM always;
  Aquino+legislative-context only from fallback) so op-eds and non-Bam
  senators are dropped.
- Desks: BAM (lead), Gaming, Education, Politics, Energy, PH, Business.
- Community board /board: 'Thank you Senator BAM' — nickname-only posts,
  HTML-stripped, URL-only rejected, IP rate-limited (3/10min, 20/day).
- Yellow-gamer theme (Orbitron/Rajdhani/JetBrains Mono, dark + gold,
  HUD corners), supporter disclaimer in header and footer.
- Tests: category/date/relevance/text suites + Mongo board suite +
  full HTTP e2e (all passing).

Infra: 66.181.46.132 (bidaangmamamayan.com), local Mongo 7.0,
nginx + certbot TLS, PM2 bama (:3000) + 15-min crawl cron.
2026-09-15 08:37:03 +00:00

37 lines
1.3 KiB
JavaScript

// Bama crawl trigger — fires the server's /api/crawl every 15 min via PM2
// cron_restart. The web app itself never crawls on page load.
const fs = require("fs");
const path = require("path");
// Load .env.production (KEY=VALUE lines) so the cron process has the real
// secret + port.
const envFile = path.join(__dirname, "..", ".env.production");
try {
for (const line of fs.readFileSync(envFile, "utf8").split("\n")) {
const m = line.match(/^([A-Z0-9_]+)=(.*)$/);
if (m && !process.env[m[1]]) process.env[m[1]] = m[2];
}
} catch (e) {}
const SECRET = process.env.CRON_SECRET || "bama-cron";
const PORT = process.env.PORT || "3000";
let run = async () => {
const res = await fetch(`http://127.0.0.1:${PORT}/api/crawl`, {
method: "POST",
headers: { "x-bama-cron": SECRET },
signal: AbortSignal.timeout(280000),
});
const j = await res.json().catch(() => ({}));
const c = (j && j.crawl) || {};
console.log(
`[bama-crawl] ${res.status} added=${c.added} named=${c.named} fallback=${c.usedFallback ? "yes" : "no"} gated=${c.gatedOut} imgs=${c.withImage} articles=${c.articles ? c.articles.ok + "/" + c.articles.fetched : "?"} ${c.errors && c.errors.length ? "errs=" + c.errors.length : ""}`
);
process.exit(res.ok ? 0 : 1);
};
run().catch((e) => {
console.error("[bama-crawl] FAILED", e && e.message);
process.exit(1);
});