2ec45b9138
Restructures the install so users run ONE command. The fork's newinstaller.sh clones this repo (instead of upstream Nachtzuster) and runs BirdNET-Pi's installer. install_services.sh symlinks the avian/ overlay into the Caddy site root, so http://birdnet.local/avian/ comes up after reboot with no Caddy config needed. Reviewer-flagged fixes: Frontend (avian/frontend/apt.js) - Switch all API paths from /api/*.json (which didn't route) to relative action-based URLs (./api/birdnet-api.php?action=recent etc.). - Fetch ./masks.json + ./dims.json relatively (were /avian/*.json). - Replace every innerHTML user-content sink with createElement + textContent + setAttribute — species labels are user-editable in BirdNET-Pi, so untrusted. - Add esc() helper for the few remaining innerHTML attribute contexts. - fetchJson throws on non-200 (was silently parsing 404 HTML as JSON). - Defensive null-check in loadMask if MASKS hasn't loaded. Backend (avian/api/*.php) - birdnet-api.php now derives DB_PATH from dirname(__DIR__, 3) so any BirdNET-Pi install user works (no hardcoded /home/birdnet). - recording/spectrogram/cutout use getenv('HOME') for the same reason. - cutout.php reworked as the canonical image resolver: bundled illustration → bundled cutout → cached rembg → fresh Wikipedia+rembg, with the binomial regex guard and atomic rename on cache write. Wikipedia URL host pinned to wikimedia.org / wikipedia.org to block SSRF. - Stale 'X-BirdNET-Proxy-Token' auth claims removed everywhere. Pregen (avian/scripts/pregen.py) - Gemini key moved from URL query to x-goog-api-key header. - Model bumped to gemini-2.5-flash-image-preview. - Bounded retry on 429 + 5xx with Retry-After honoured. - Default --sleep raised from 1s to 4s (under free-tier RPM). - Unified parser handles |/_/comma in all three input modes. - responseModalities now [TEXT, IMAGE] (was IMAGE-only). - --poses validated against POSES keys. - ASCII [ok]/[fail] markers (was ✓/✗ — Windows console crash). - Surfaces finishReason + blockReason on safety blocks. Prompt template - 'Two placeholders' typo → three. - 'warm paper' / 'transparent background' contradiction resolved. Forwarding - mqtt-bridge.py: paho-mqtt 2.x CallbackAPIVersion compat shim. - avian-mqtt.service: dropped broken %i, set User=birdnet + %h path. - forwarding/README.md uses the actual action-based URLs. README - One-line install via curl … newinstaller.sh. - No more 'install BirdNET-Pi separately' step (our fork does it). - License section uses absolute github.com links. - bird.onethreenine.net replaces the not-yet-existent project writeup. - docs/thumb.png replaced with the 24-bird Twitter capture. Removed - avian/caddy/ and avian/scripts/install.sh — no longer needed; the overlay symlink in install_services.sh handles everything.
68 lines
2.8 KiB
HTML
68 lines
2.8 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">
|
||
<title>apartment birds</title>
|
||
<meta name="description" content="A live bird collage from your apartment window.">
|
||
<link rel="stylesheet" href="./styles.css">
|
||
</head>
|
||
<body>
|
||
|
||
<main class="stage">
|
||
<header class="static-head">
|
||
<button type="button" class="pre" id="aboutLink">apartment birds</button>
|
||
<h1 id="staticTitle">Heard Recently</h1>
|
||
</header>
|
||
|
||
<div class="views" id="views">
|
||
<section class="view view-collage" data-view="0">
|
||
<div id="collage" class="collage"></div>
|
||
</section>
|
||
<section class="view view-stats" data-view="1" hidden>
|
||
<div id="statsTimeline" class="stats-tl"></div>
|
||
</section>
|
||
<section class="view view-atlas" data-view="2" hidden>
|
||
<div class="atlas-sort" id="atlasSort">
|
||
<i class="seg-pill" aria-hidden="true"></i>
|
||
<button type="button" data-sort="count" aria-current="true">most heard</button>
|
||
<button type="button" data-sort="recent">most recent</button>
|
||
<button type="button" data-sort="first">first seen</button>
|
||
</div>
|
||
<div id="atlasList" class="atlas-list"></div>
|
||
</section>
|
||
</div>
|
||
</main>
|
||
|
||
<div class="window-pick" id="winPick" role="tablist">
|
||
<i class="seg-pill" aria-hidden="true"></i>
|
||
<button data-h="1" type="button">1H</button>
|
||
<button data-h="12" type="button">12H</button>
|
||
<button data-h="24" type="button" aria-current="true">24H</button>
|
||
<button data-h="168" type="button">7D</button>
|
||
<button data-h="9999999" type="button">ALL</button>
|
||
</div>
|
||
|
||
<nav class="slider" id="slider" aria-label="View">
|
||
<i class="seg-pill" aria-hidden="true"></i>
|
||
<button type="button" data-i="0" aria-current="true">collage</button>
|
||
<button type="button" data-i="1">stats</button>
|
||
<button type="button" data-i="2">atlas</button>
|
||
</nav>
|
||
|
||
<div id="about-modal" aria-hidden="true" role="dialog" aria-labelledby="aboutTitle">
|
||
<div class="modal-backdrop" data-close="1"></div>
|
||
<div class="about-card" role="document">
|
||
<button type="button" class="modal-close" data-close="1" aria-label="close">×</button>
|
||
<p class="about-eyebrow">apartment birds</p>
|
||
<h2 id="aboutTitle">The birds outside my window</h2>
|
||
<p class="about-body">A tiny microphone listens for birds passing the window and identifies them with Cornell's <a href="https://birdnet.cornell.edu/" target="_blank" rel="noopener">BirdNET</a>. Each species shows up as an illustration in the collage — sized by how much it's been heard.</p>
|
||
<button type="button" class="about-explore" data-close="1">explore the birds →</button>
|
||
<p class="built-by">built with <a href="https://github.com/Twarner491/AvianVisitors" target="_blank" rel="noopener">AvianVisitors</a></p>
|
||
</div>
|
||
</div>
|
||
|
||
<script src="./apt.js"></script>
|
||
</body>
|
||
</html>
|