Vogelalbum 1.0.0

Eine Kamera am Vogelhaus, ein Rechner der erkennt wer da war — und eine
Sammlung, die sich von allein fuellt.

Zwei neuronale Netze: eines findet den Vogel im Bild, eines bestimmt die
Art. 148 heimische Arten, auf Deutschland eingeschraenkt und neu normiert —
ohne diese Einschraenkung wird aus einer Kohlmeise eine nordamerikanische
Schwesterart. Daraus entsteht ein Sammelalbum: nummerierte Seiten,
gefundene Arten in Farbe, fehlende als Schatten, dazu Erstfang, Punkte,
Stufen und 15 Abzeichen.

Laeuft vollstaendig auf eigener Hardware. Kein Cloud-Dienst, kein Konto,
keine Telemetrie; die Bilder verlassen das eigene Netz nicht.

Zwei getrennt deploybare Teile: die Sammlung als Django-Anwendung, die
Erkennung als eigener Dienst. Der Erkennungs-Dienst fragt selbst an und
braucht deshalb weder eine erreichbare Adresse noch einen offenen Port —
er laeuft hinter einem gewoehnlichen Router.

Dabei: Firmware fuer Raspberry Pi und ESP32-S3, Anbindung an Home
Assistant ueber MQTT, Oberflaeche auf Deutsch und Englisch, Einstellungen
je Kamera aus dem Browser, und ein Weg fuer Fotos von unterwegs.

AGPL-3.0.
This commit is contained in:
christian committed 2026-10-15 14:30:02 +00:00
commit c11fe9ab04
189 files changed
+29806

No files matched your search

+689
View File
@@ -0,0 +1,689 @@
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: Vogelalbum\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-10-10 12:07+0200\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: en\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: dex/admin.py:28
msgid ""
"Der Detector holt sich diese Werte selbst — er fragt <code>/api/config/</"
"code> mit seinem Token und übernimmt Änderungen im laufenden Betrieb, ohne "
"Neustart. Eine Stream-Adresse, die auf seiner Kommandozeile steht, behält "
"aber Vorrang."
msgstr "The detector fetches these values itself — it asks <code>/api/config/</code> with its token and applies changes while running, without a restart. A stream address given on its command line still takes precedence."
#: dex/admin.py:38
msgid ""
"Das Livebild kommt vom Live-Verteiler des Detectors, nicht von der Kamera "
"selbst — die liefert nur einen Stream, und den braucht die Erkennung. "
"Starten mit <code>python -m detector watch … --live-port 8131</code>."
msgstr "The live image comes from the detector's relay, not from the camera itself — the camera serves only one stream, and the recognition needs it. Start it with <code>python -m detector watch … --live-port 8131</code>."
#: dex/admin.py:61
msgid "gesperrt (VOGELALBUM_LIVE_ERLAUBT=0)"
msgstr "locked (VOGELALBUM_LIVE_ERLAUBT=0)"
#: dex/admin.py:63
msgid "aus"
msgstr "off"
#: dex/admin.py:65
msgid "an, aber keine Adresse"
msgstr "on, but no address"
#: dex/admin.py:67
msgid "an, aber Kamera stillgelegt"
msgstr "on, but camera disabled"
#: dex/admin.py:68
msgid "an"
msgstr "on"
#: dex/models.py:551
msgid "Gewicht"
msgstr "Weight"
#: dex/models.py:552
msgid "Spannweite"
msgstr "Wingspan"
#: dex/models.py:557
msgid "Größe"
msgstr "Length"
#: dex/models.py:558
msgid "Seltenheit"
msgstr "Rarity"
#: dex/scoring.py:25
msgid "Nestling"
msgstr "Nestling"
#: dex/scoring.py:26
msgid "Ästling"
msgstr "Fledgling"
#: dex/scoring.py:27
msgid "Spatzenkenner"
msgstr "Sparrow Spotter"
#: dex/scoring.py:28
msgid "Meisenmeister"
msgstr "Tit Master"
#: dex/scoring.py:29
msgid "Federfuchser"
msgstr "Feather Nerd"
#: dex/scoring.py:30
msgid "Amselflüsterer"
msgstr "Blackbird Whisperer"
#: dex/scoring.py:31
msgid "Spechtspäher"
msgstr "Woodpecker Watcher"
#: dex/scoring.py:32
msgid "Falkenauge"
msgstr "Falcon Eye"
#: dex/scoring.py:33
msgid "Vogelmeister"
msgstr "Bird Master"
#: dex/scoring.py:34
msgid "Legende des Vogelhauses"
msgstr "Legend of the Feeder"
#: dex/scoring.py:112
msgid "Erster Gast"
msgstr "First Guest"
#: dex/scoring.py:113
msgid "Die allererste Sichtung im Vogelhaus."
msgstr "The very first sighting at the feeder."
#: dex/scoring.py:114
msgid "Fünf Freunde"
msgstr "High Five"
#: dex/scoring.py:115
msgid "5 verschiedene Arten gesammelt."
msgstr "5 different species collected."
#: dex/scoring.py:116
msgid "Zweistellig"
msgstr "Double Digits"
#: dex/scoring.py:117
msgid "10 verschiedene Arten gesammelt."
msgstr "10 different species collected."
#: dex/scoring.py:118
msgid "Sammler"
msgstr "Collector"
#: dex/scoring.py:119
msgid "25 verschiedene Arten gesammelt."
msgstr "25 different species collected."
#: dex/scoring.py:120
msgid "Vogelalbum-Meister"
msgstr "Vogelalbum Master"
#: dex/scoring.py:121
msgid "40 verschiedene Arten gesammelt."
msgstr "40 different species collected."
#: dex/scoring.py:122
msgid "Frühaufsteher"
msgstr "Early Bird"
#: dex/scoring.py:123
msgid "Eine Sichtung vor 6 Uhr morgens."
msgstr "A sighting before 6 in the morning."
#: dex/scoring.py:124
msgid "Nachtschicht"
msgstr "Night Shift"
#: dex/scoring.py:125
msgid "Eine Sichtung nach 21 Uhr."
msgstr "A sighting after 9 in the evening."
#: dex/scoring.py:126
msgid "Volles Haus"
msgstr "Full House"
#: dex/scoring.py:127
msgid "5 verschiedene Arten an einem Tag."
msgstr "5 different species in one day."
#: dex/scoring.py:128
msgid "Stammgast"
msgstr "Regular"
#: dex/scoring.py:129
msgid "7 Tage in Folge mindestens eine Sichtung."
msgstr "At least one sighting on 7 consecutive days."
#: dex/scoring.py:130
msgid "Dauergast"
msgstr "Long Stay"
#: dex/scoring.py:131
msgid "Ein Besuch, der länger als eine Minute dauerte."
msgstr "A visit lasting longer than a minute."
#: dex/scoring.py:132
msgid "Hundert Besuche"
msgstr "One Hundred Visits"
#: dex/scoring.py:133
msgid "100 Sichtungen aufgezeichnet."
msgstr "100 sightings recorded."
#: dex/scoring.py:134
msgid "Tausend Besuche"
msgstr "One Thousand Visits"
#: dex/scoring.py:135
msgid "1000 Sichtungen aufgezeichnet."
msgstr "1000 sightings recorded."
#: dex/scoring.py:136
msgid "Klopfgeist"
msgstr "The Knocker"
#: dex/scoring.py:137
msgid "Ein Specht war da."
msgstr "A woodpecker came by."
#: dex/scoring.py:138
msgid "Greifvogel-Alarm"
msgstr "Raptor Alert"
#: dex/scoring.py:139
msgid "Ein Greifvogel oder eine Eule vor der Linse."
msgstr "A bird of prey or an owl in front of the lens."
#: dex/scoring.py:140
msgid "Seltener Gast"
msgstr "Rare Guest"
#: dex/scoring.py:141
msgid "Eine Art der Stufe 'Selten' oder höher."
msgstr "A species rated 'Rare' or above."
#: dex/templatetags/dex_extras.py:76
#, python-format
msgid "heute, %(uhrzeit)s"
msgstr "today, %(uhrzeit)s"
#: dex/templatetags/dex_extras.py:78
#, python-format
msgid "gestern, %(uhrzeit)s"
msgstr "yesterday, %(uhrzeit)s"
#: dex/templatetags/dex_extras.py:80
#, python-format
msgid "%(wochentag)s, %(uhrzeit)s"
msgstr "%(wochentag)s, %(uhrzeit)s"
#: dex/templatetags/dex_extras.py:84
#, python-format
msgid "%(datum)s, %(uhrzeit)s"
msgstr "%(datum)s, %(uhrzeit)s"
#: dex/views.py:47
msgid "Noch wartet die Kamera"
msgstr "The camera is still waiting"
#: dex/views.py:52
msgid "Wer war heute zu Gast?"
msgstr "Who stopped by today?"
#: dex/views.py:54
msgid "Zuletzt gestern zu Gast"
msgstr "Last visitor: yesterday"
#: dex/views.py:56
#, python-format
msgid "Zuletzt am %(wochentag)s zu Gast"
msgstr "Last visitor: %(wochentag)s"
#: dex/views.py:59
#, python-format
msgid "Zuletzt am %(datum)s zu Gast"
msgstr "Last visitor: %(datum)s"
#: dex/views.py:400
msgid "Bitte mindestens ein Bild auswählen."
msgstr "Please select at least one image."
#: templates/dex/badges.html:4 templates/dex/badges.html:39
#: templates/dex/base.html:81
msgid "Abzeichen"
msgstr "Badges"
#: templates/dex/badges.html:39
#, python-format
msgid "%(n)s verdient"
msgstr "%(n)s earned"
#: templates/dex/base.html:7
msgid ""
"Vögel erkennen, sammeln und katalogisieren — auf dem eigenen Server, ohne "
"Cloud."
msgstr "Identify, collect and catalogue birds — on your own server, without a cloud."
#: templates/dex/base.html:74 templates/dex/live.html:4
#: templates/dex/live.html:8
msgid "Live"
msgstr "Live"
#: templates/dex/base.html:78
msgid "Übersicht"
msgstr "Overview"
#: templates/dex/base.html:79 templates/dex/dex.html:4
msgid "Sammlung"
msgstr "Collection"
#: templates/dex/base.html:80 templates/dex/sightings.html:4
#: templates/dex/sightings.html:28
msgid "Sichtungen"
msgstr "Sightings"
#: templates/dex/base.html:97
msgid "Zwischen hellem und dunklem Modus wechseln"
msgstr "Switch between light and dark mode"
#: templates/dex/base.html:122 templates/dex/base.html:123
msgid "Einstellungen"
msgstr "Settings"
#: templates/dex/base.html:139 templates/dex/home.html:42
#, python-format
msgid "%(xp)s XP · noch %(rest)s XP bis Level %(lvl)s"
msgstr "%(xp)s XP · %(rest)s XP to level %(lvl)s"
#: templates/dex/base.html:143
msgid "Arten gesammelt"
msgstr "species collected"
#: templates/dex/base.html:168
msgid "Dieses Vogelalbum füllt sich von allein."
msgstr "This bird album fills itself."
#: templates/dex/base.html:169
msgid ""
"Eine Kamera am Futterhaus, der Rest passiert auf deinem eigenen Server — "
"ohne Cloud, ohne Konto, ohne Abo. Freie Software zum Nachbauen."
msgstr "A camera at the feeder, everything else happens on your own server — no cloud, no account, no subscription. Free software, built to be rebuilt."
#: templates/dex/base.html:172
msgid "Projekt ansehen"
msgstr "View the project"
#: templates/dex/dex.html:8
msgid "Die Sammlung"
msgstr "The Collection"
#: templates/dex/dex.html:10
#, python-format
msgid "%(a)s von %(b)s Arten"
msgstr "%(a)s of %(b)s species"
#: templates/dex/dex.html:22 templates/dex/species.html:80
msgid "Lebensraum"
msgstr "Habitat"
#: templates/dex/dex.html:27
msgid "Alle"
msgstr "All"
#: templates/dex/dex.html:36
msgid "Stufe"
msgstr "Tier"
#: templates/dex/dex.html:38
msgid "Alle Stufen"
msgstr "All tiers"
#: templates/dex/dex.html:46
msgid "Gruppe"
msgstr "Group"
#: templates/dex/dex.html:48
msgid "Alle Gruppen"
msgstr "All groups"
#: templates/dex/dex.html:55
msgid "Anwenden"
msgstr "Apply"
#: templates/dex/dex.html:58
msgid "Zurücksetzen"
msgstr "Reset"
#: templates/dex/dex.html:70
msgid "Noch nicht gesichtet"
msgstr "Not yet sighted"
#: templates/dex/dex.html:95
msgid "Keine Art passt zu dieser Auswahl."
msgstr "No species matches this selection."
#: templates/dex/hochladen.html:4 templates/dex/hochladen.html:76
msgid "Fotos hochladen"
msgstr "Upload photos"
#: templates/dex/hochladen.html:85
msgid ""
"Ein Vogel unterwegs? Foto hier einliefern — der Detector bestimmt es beim "
"nächsten Durchgang und trägt es in die Sammlung ein."
msgstr "Spotted a bird? Hand in a photo here — the detector identifies it on its next pass and adds it to the collection."
#: templates/dex/hochladen.html:90
#, python-format
msgid "%(n)s Foto angenommen. Es wartet auf den Detector."
msgid_plural "%(n)s Fotos angenommen. Sie warten auf den Detector."
msgstr[0] "%(n)s photo accepted. It is waiting for the detector."
msgstr[1] "%(n)s photos accepted. They are waiting for the detector."
#: templates/dex/hochladen.html:101
msgid "Bilder"
msgstr "Images"
#: templates/dex/hochladen.html:109
msgid "Mehrere Bilder auf einmal sind möglich. Jedes wird einzeln bestimmt."
msgstr "You can pick several images at once. Each one is identified separately."
#: templates/dex/hochladen.html:114
msgid "Gerät"
msgstr "Device"
#: templates/dex/hochladen.html:116
msgid "— ohne Zuordnung —"
msgstr "— unassigned —"
#: templates/dex/hochladen.html:125
msgid "Ort (freiwillig)"
msgstr "Location (optional)"
#: templates/dex/hochladen.html:127
msgid "Breite, z. B. 49.49"
msgstr "Latitude, e.g. 49.49"
#: templates/dex/hochladen.html:128
msgid "Länge, z. B. 8.47"
msgstr "Longitude, e.g. 8.47"
#: templates/dex/hochladen.html:131
msgid ""
"Wird auf etwa einen Kilometer gerundet gespeichert — die Gegend, nicht die "
"Adresse."
msgstr "Stored rounded to about a kilometre — the area, not the address."
#: templates/dex/hochladen.html:136
msgid "Hochladen"
msgstr "Upload"
#: templates/dex/hochladen.html:142
msgid "Warten auf Bestimmung"
msgstr "Awaiting identification"
#: templates/dex/hochladen.html:154
msgid "Noch nicht bestimmt"
msgstr "Not identified yet"
#: templates/dex/hochladen.html:160
msgid "Bleiben die Bilder länger stehen, läuft der Detector nicht."
msgstr "If images sit here for a while, the detector is not running."
#: templates/dex/home.html:4
msgid "Vogelalbum — Übersicht"
msgstr "Vogelalbum — Overview"
#: templates/dex/home.html:33
msgid ""
"Jeder Vogel wird bestimmt, gezählt und gesammelt — aus dem Kamerabild oder "
"vom Handyfoto. Alles auf dem eigenen Server."
msgstr "Every bird is identified, counted and collected — from a camera frame or a photo off your phone. All on your own server."
#: templates/dex/home.html:46 templates/dex/widget.html:37
msgid "Arten"
msgstr "species"
#: templates/dex/home.html:59
msgid "ZULETZT"
msgstr "LATEST"
#: templates/dex/home.html:67
msgid "Noch kein Gast aufgezeichnet."
msgstr "No visitor recorded yet."
#: templates/dex/home.html:68
msgid "Der erste bestimmte Vogel steht hier."
msgstr "The first identified bird shows up here."
#: templates/dex/home.html:75
msgid "Neu in der Sammlung"
msgstr "New in the collection"
#: templates/dex/home.html:75
msgid "letzte 7 Tage"
msgstr "last 7 days"
#: templates/dex/home.html:92
msgid "Neu"
msgstr "New"
#: templates/dex/home.html:100
msgid "Zuletzt zu Besuch"
msgstr "Latest visitors"
#: templates/dex/home.html:101
#, python-format
msgid "%(n)s Besuche insgesamt"
msgstr "%(n)s visits in total"
#: templates/dex/home.html:120 templates/dex/sightings.html:75
#: templates/dex/species.html:127
msgid "Erstfang"
msgstr "First catch"
#: templates/dex/home.html:129
msgid "Noch keine Sichtung aufgezeichnet."
msgstr "No sightings recorded yet."
#: templates/dex/home.html:130
msgid ""
"Sobald der Detector einen Vogel erkennt oder das erste Foto eingeliefert "
"ist, erscheint hier der erste Gast."
msgstr "As soon as the detector spots a bird or the first photo is handed in, the first visitor appears here."
#: templates/dex/home.html:135
msgid "Stammgäste"
msgstr "Regulars"
#: templates/dex/live.html:10
#, python-format
msgid "%(n)s Kamera"
msgid_plural "%(n)s Kameras"
msgstr[0] "%(n)s camera"
msgstr[1] "%(n)s cameras"
#: templates/dex/live.html:51
msgid ""
"Bleibt das Bild schwarz, läuft der Detector nicht — die Erkennung verteilt "
"das Livebild aus ihrem eigenen Bildstrom."
msgstr "If the image stays black the detector is not running — the live view is relayed from the recognition's own frame stream."
#: templates/dex/sightings.html:28 templates/dex/species.html:114
#, python-format
msgid "%(n)s insgesamt"
msgstr "%(n)s in total"
#: templates/dex/sightings.html:35
msgid "Foto hochladen"
msgstr "Upload photo"
#: templates/dex/sightings.html:40 templates/dex/species.html:114
msgid "Alle Besuche"
msgstr "All visits"
#: templates/dex/sightings.html:41
msgid "Nur bestimmte Arten"
msgstr "Identified only"
#: templates/dex/sightings.html:46
msgid "Alle Kameras"
msgstr "All cameras"
#: templates/dex/sightings.html:71
msgid "von Hand"
msgstr "by hand"
#: templates/dex/sightings.html:73
msgid "Unbestimmt"
msgstr "Unidentified"
#: templates/dex/sightings.html:84
msgid "Alternativen"
msgstr "Alternatives"
#: templates/dex/sightings.html:99
msgid "Neuer"
msgstr "Newer"
#: templates/dex/sightings.html:100
msgid "Älter"
msgstr "Older"
#: templates/dex/sightings.html:103
msgid "Noch nichts aufgezeichnet."
msgstr "Nothing recorded yet."
#: templates/dex/species.html:28
msgid "Bestes eigenes Foto"
msgstr "Best own photo"
#: templates/dex/species.html:30
msgid "Referenzfoto — diese Art war noch nicht vor unserer Kamera."
msgstr "Reference photo — this species has not been in front of our camera yet."
#: templates/dex/species.html:32
msgid "Foto"
msgstr "Photo"
#: templates/dex/species.html:50
#, python-format
msgid "%(n)s× seen"
msgid_plural "%(n)s× seen"
msgstr[0] "%(n)s× seen"
msgstr[1] "%(n)s× seen"
#: templates/dex/species.html:69 templates/dex/species.html:74
msgid "Steckbrief"
msgstr "Profile"
#: templates/dex/species.html:83
msgid "Nahrung"
msgstr "Diet"
#: templates/dex/species.html:86
msgid "Stimme"
msgstr "Voice"
#: templates/dex/species.html:89
msgid "Zugverhalten"
msgstr "Migration"
#: templates/dex/species.html:94
msgid "Verwechslungsgefahr"
msgstr "Easily confused with"
#: templates/dex/species.html:94
msgid "Arten, die man nicht auf Anhieb unterscheidet"
msgstr "species you will not tell apart at a glance"
#: templates/dex/species.html:106
#, python-format
msgid "Wann ist %(n)s da?"
msgstr "When does the %(n)s show up?"
#: templates/dex/species.html:106
msgid "Besuche über den Tag"
msgstr "visits across the day"
#: templates/dex/species.html:110
msgid "0 Uhr"
msgstr "midnight"
#: templates/dex/species.html:130
#, python-format
msgid "%(a)s von %(b)s Bildern mit Vogel"
msgstr "%(a)s of %(b)s frames with a bird"
#: templates/dex/species.html:143
msgid "Noch nicht gesammelt."
msgstr "Not collected yet."
#: templates/dex/species.html:144
#, python-format
msgid ""
"Sobald %(n)s vor der Kamera landet, wird dieser Eintrag freigeschaltet — mit "
"eurem eigenen Foto."
msgstr "Once a %(n)s lands in front of the camera this entry unlocks — with your own photo."
#: templates/dex/widget.html:25
msgid "Zuletzt gesehen"
msgstr "Last seen"
#: templates/dex/widget.html:27
msgid "sicher"
msgstr "confident"
#: templates/dex/widget.html:32
msgid "Noch kein Gast"
msgstr "No visitor yet"
#~ msgid ""
#~ "Vogelalbum · Arterkennung auf dem eigenen Server. Keine Cloud, keine "
#~ "fremden Dienste."
#~ msgstr ""
#~ "Vogelalbum · Species recognition on your own server. No cloud, no third-"
#~ "party services."
#~ msgid ""
#~ "Eine Kamera am Vogelhaus, die Erkennung auf dem eigenen Server. Jeder "
#~ "Gast wird bestimmt, gezählt und gesammelt."
#~ msgstr ""
#~ "A camera at the bird house, recognition on your own server. Every visitor "
#~ "is identified, counted and collected."
#~ msgid "Sobald sich etwas im Vogelhaus rührt, steht er hier."
#~ msgstr "As soon as something stirs at the bird house, it will show up here."
#~ msgid "Zuletzt im Vogelhaus"
#~ msgstr "Latest at the feeder"
#~ msgid "Besuche heute"
#~ msgstr "Visits today"
#~ msgid "Arten heute"
#~ msgstr "Species today"