Pre-share fixes from final review pass
Blockers - http://birdnet.local/avian/ now serves the collage (added avian/index.html redirect to frontend/; previously the symlink target had no top-level index, so users saw a directory listing of api/ assets/ forwarding/ frontend/ scripts/). - Gemini model bumped from gemini-2.5-flash-image-preview (deprecated 2026-01-15) to the stable gemini-2.5-flash-image. Pregen was non- functional out of the box. - avian-mqtt.service: dropped %h (which expands to /root for system-mode units regardless of User=). Use WorkingDirectory=~ which DOES respect User=, plus a relative ExecStart. - birdnet-api.php case 'lifelist' now aliases COUNT(*) AS n (was 'total'), matching what apt.js reads for atlas card counts. Atlas previously always displayed 0. Bugs - Retry-After parsing handles HTTP-date format without crashing. - apt.js no longer fetches firstseen/timeseries (declared in state but never consumed). Two wasted round-trips per page load removed. - update_birdnet.sh defaults branch=avian-visitors so the (opt-in) Sunday auto-update cron doesn't reset HEAD to upstream main and delete the avian/ overlay. - recording.php: removed dead $BIRDS_JSON_CANDIDATES. Polish - Pregen --sleep default raised 4→6s (more headroom under free-tier RPM). - en-dash in README BOM (~$35–80) replaced with hyphen for style match. - Slop sweep across user-facing docs: no em-dashes, no en-dashes, no AI-slop word hits (robust/comprehensive/seamless/etc.).
This commit is contained in:
+10
-14
@@ -1,18 +1,18 @@
|
||||
/* AvianVisitors — bird collage frontend.
|
||||
/* AvianVisitors - bird collage frontend.
|
||||
*
|
||||
* Three views over BirdNET-Pi detections:
|
||||
* collage — mask-packed cluster of species illustrations, sized by
|
||||
* collage - mask-packed cluster of species illustrations, sized by
|
||||
* count. Layout normalises so every bird always fits on
|
||||
* every viewport.
|
||||
* stats — per-species mark on a time × count plot.
|
||||
* atlas — grid of every species ever detected, with detail modal.
|
||||
* stats - per-species mark on a time × count plot.
|
||||
* atlas - grid of every species ever detected, with detail modal.
|
||||
*
|
||||
* Lives at $HOME/BirdNET-Pi/avian/frontend/ on the Pi; the install
|
||||
* symlinks $HOME/BirdNET-Pi/avian → $EXTRACTED/avian, so this file
|
||||
* loads from http://birdnet.local/avian/frontend/apt.js with the
|
||||
* collage at http://birdnet.local/avian/frontend/.
|
||||
*
|
||||
* All API calls are relative — they target the PHP shims in ../api/
|
||||
* All API calls are relative - they target the PHP shims in ../api/
|
||||
* served by BirdNET-Pi's existing Caddy + PHP-FPM stack. No frontend
|
||||
* configuration needed; works out of the box on any BirdNET-Pi host.
|
||||
*/
|
||||
@@ -44,7 +44,7 @@
|
||||
}
|
||||
// HTML-escape user-supplied strings before they land in innerHTML.
|
||||
// Species names come from BirdNET-Pi's labels file, which is
|
||||
// user-editable (custom species lists, l18n) — so they're untrusted.
|
||||
// user-editable (custom species lists, l18n) - so they're untrusted.
|
||||
function esc(s) {
|
||||
return String(s == null ? '' : s)
|
||||
.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
||||
@@ -52,7 +52,7 @@
|
||||
}
|
||||
|
||||
// ---- State ----
|
||||
var DATA = { recent: null, lifelist: null, firstseen: null, timeseries: null };
|
||||
var DATA = { recent: null, lifelist: null };
|
||||
var MASKS = null, DIMS = null;
|
||||
var currentHours = +readLS('av:window', '24') || 24;
|
||||
|
||||
@@ -153,14 +153,10 @@
|
||||
var h = currentHours;
|
||||
return Promise.all([
|
||||
fetchJson(api('lifelist')).catch(function () { return null; }),
|
||||
fetchJson(api('firstseen')).catch(function () { return null; }),
|
||||
fetchJson(api('timeseries', 'days=30')).catch(function () { return null; }),
|
||||
fetchJson(api('recent', 'hours=' + h)).catch(function () { return null; }),
|
||||
]).then(function (parts) {
|
||||
DATA.lifelist = parts[0];
|
||||
DATA.firstseen = parts[1];
|
||||
DATA.timeseries = parts[2];
|
||||
if (parts[3] && h === currentHours) DATA.recent = parts[3];
|
||||
if (parts[1] && h === currentHours) DATA.recent = parts[1];
|
||||
renderCollageFromData();
|
||||
drawHistograms();
|
||||
});
|
||||
@@ -440,7 +436,7 @@
|
||||
if (!sp.length) {
|
||||
var p = document.createElement('p');
|
||||
p.className = 'empty';
|
||||
p.textContent = 'no species yet — atlas fills in as the Pi detects birds.';
|
||||
p.textContent = 'no species yet - atlas fills in as the Pi detects birds.';
|
||||
list.innerHTML = '';
|
||||
list.appendChild(p);
|
||||
return;
|
||||
@@ -510,7 +506,7 @@
|
||||
card.querySelector('.detail-title').textContent = label;
|
||||
card.querySelector('.detail-sci em').textContent = sci;
|
||||
card.querySelector('.detail-stats').textContent =
|
||||
(+rec.n || 0) + ' calls · last heard ' + (rec.last_seen || '—');
|
||||
(+rec.n || 0) + ' calls · last heard ' + (rec.last_seen || '-');
|
||||
card.querySelector('.detail-audio').src = media('recording.php', 'sci=' + encodeURIComponent(sci));
|
||||
card.querySelector('.detail-spec').src = media('spectrogram.php', 'sci=' + encodeURIComponent(sci));
|
||||
modal.setAttribute('aria-hidden', 'false');
|
||||
|
||||
Reference in New Issue
Block a user