diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..3221104
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,13 @@
+# Changelog
+
+## v0.0.1-rc
+
+- Integrate BirdNET-Analyzer as submodule
+- Add birdnet_recording service
+- Add birdnet_analyzis service
+- Create symfony webapp
+- Extracts BirdNET bird contacts into SQL database
+- Add birdnet_stream icecast audio streaming and live spectrogram service https://birdnet/spectro
+- Add /today/species and /today/{date}/species/{id} endpoints
+- Add records deletion button
+- Add systemd status page /status
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..1c16cfc
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,28 @@
+# Contributing
+
+This project welcomes contributions and suggestions.
+
+You can contribute to this project by contributing to:
+
+* [Issues](https://github.com/UncleSamulus/BirdNET-stream/issues)
+* [Discussions](https://github.com/UncleSamulus/BirdNET-stream/discussions)
+* [Localization](#Localization)
+
+If you intend to contribute code changes, learn how to [set up your development environment](#Set-up-your-development-environment).
+
+
+## Set up your development environment
+
+You should follow [./INSTALL.md](./INSTALL.md) to install a working BirdNET-stream system on your system.
+
+## Localization
+
+BirdNET-stream webapp is written in PHP Symfony. The i18n files are stored in the `[./www/translations](./www/translations)` directory.
+
+Any help is welcome to translate the webapp into your language.
+
+
+## Filing a pull request
+
+All contributions are expected to be reviewed and merged via pull requests into the main branch.
\ No newline at end of file
diff --git a/INSTALL.md b/INSTALL.md
index ef44c87..fa5cda5 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -65,7 +65,7 @@ sudo systemctl enable --now birdnet_recording.service birdnet_analyzis.service b
```
#### Check if services are working
-
+
```bash
# Sercices status
sudo systemctl status birdnet_recording.service birdnet_analyzis.service
@@ -140,11 +140,71 @@ sudo npm install -g yarn
yarn build
```
+## Setup audio streaming with icecast and ffmpeg for live spectrogram
+
+Install icecast:
+
+```bash
+sudo apt-get install icecast2
+```
+
+Modify icecast password:
+
+```xml
+[...]
+
+
+ secret
+
+ secret
+
+ birdnet
+ secret
+
+[...]
+```
+
+Launch and enable icecast:
+
+```bash
+sudo systemctl enable --now icecast2
+```
+
+Adapt `config/analyzer.conf` to this configuration:
+
+```conf
+ICECAST_USER=source
+ICECAST_PASSWORD=secret # change this to the password you set above
+ICECAST_PORT=8000
+ICECAST_HOST=localhost
+ICECAST_MOUNT=stream
+```
+
+Launch and enable audio streamer daemon:
+
+```bash
+sudo systemctl enable --now birdnet_streaming.service
+```
+
+Add a reverse proxy to nginx to allow https
+
+```nginx
+server {
+ [...]
+
+ location /stream {
+ proxy_pass http://localhost:8000/birdnet;
+ }
+
+ [...]
+}
+```
+
## Setup https certificates with dehydrated (only for public instances)
```bash
sudo apt-get install dehydrated
-```
+````
Edit `/etc/dehydrated/domains.txt` and add your domain name.
@@ -166,9 +226,11 @@ server {
```
Create acme-challenge directory:
+
```bash
sudo mkdir -p /var/www/html/.well-known/acme-challenge
```
+
Adapt `/etc/dehydrated/config`, by adding this folder to the `WELLKNOWN` path:
```bash
@@ -182,11 +244,13 @@ dehydrated --register --accept-terms
```
Generate certificates:
+
```bash
dehydrated -c
```
Add dehydrated cron
+
```bash
sudo crontab -e
```
diff --git a/TODO b/TODO
index 1a1361a..82ededb 100644
--- a/TODO
+++ b/TODO
@@ -1,4 +1,2 @@
-- Fix install of venv
- Fix clean script
-- Change install script for php 8.1
- Fix service manager
diff --git a/daemon/birdnet_analyzis.sh b/daemon/birdnet_analyzis.sh
index a59cb80..a2626ad 100755
--- a/daemon/birdnet_analyzis.sh
+++ b/daemon/birdnet_analyzis.sh
@@ -1,6 +1,13 @@
#! /usr/bin/env bash
set -e
+DEBUG=${DEBUG:-1}
+debug() {
+ if [ $DEBUG -eq 1 ]; then
+ echo "$1"
+ fi
+}
+
config_filepath="./config/analyzer.conf"
if [ -f "$config_filepath" ]; then
@@ -69,6 +76,7 @@ analyze_chunk() {
date=$(echo $chunk_name | cut -d'_' -f2)
week=$(./daemon/weekof.sh $date)
$PYTHON_EXECUTABLE ./analyzer/analyze.py --i $chunk_path --o "$output_dir/model.out.csv" --lat $LATITUDE --lon $LONGITUDE --week $week --min_conf $CONFIDENCE --threads 4 --rtype csv
+ debug "Model output written to $output_dir/model.out.csv"
}
# Perform audio chunk analysis on all recorded chunks
diff --git a/daemon/birdnet_streaming.sh b/daemon/birdnet_streaming.sh
new file mode 100755
index 0000000..1b7a3b6
--- /dev/null
+++ b/daemon/birdnet_streaming.sh
@@ -0,0 +1,51 @@
+#! /usr/bin/env bash
+
+DEBUG=${DEBUG:-1}
+
+export PULSE_RUNTIME_PATH="/run/user/$(id -u)/pulse/"
+
+debug() {
+ if [ $DEBUG -eq 1 ]; then
+ echo "$1"
+ fi
+}
+
+stream() {
+ DEVICE=$1
+ debug "Launching audio stream from $DEVICE at icecast://source:secret@$ICECAST_HOST:$ICECAST_PORT/$ICECAST_MOUNT"
+ ffmpeg -nostdin -hide_banner -loglevel error -nostats \
+ -f pulse -i $DEVICE -vn -acodec libmp3lame -ac 1 -ar 48000 -content_type 'audio/mpeg' \
+ -f mp3 "icecast://source:${ICECAST_PASSWORD}@${ICECAST_HOST}:${ICECAST_PORT}/${ICECAST_MOUNT}" -listen 1
+}
+
+config_filepath="./config/analyzer.conf"
+
+if [ -f "$config_filepath" ]; then
+ source "$config_filepath"
+else
+ echo "Config file not found: $config_filepath"
+ exit 1
+fi
+
+if [[ -z $AUDIO_DEVICE ]]; then
+ echo "AUDIO_DEVICE is not set"
+ exit 1
+fi
+
+if [[ -z $ICECAST_HOST ]]; then
+ echo "ICECAST_HOST is not set"
+ exit 1
+fi
+if [[ -z $ICECAST_PORT ]]; then
+ echo "ICECAST_PORT is not set"
+ exit 1
+fi
+if [[ -z $ICECAST_MOUNT ]]; then
+ echo "ICECAST_MOUNT is not set"
+ exit 1
+fi
+if [[ -z $ICECAST_PASSWORD ]]; then
+ echo "ICECAST_PASSWORD is not set"
+ exit 1
+fi
+stream $AUDIO_DEVICE
diff --git a/daemon/systemd/templates/birdnet_streaming.service b/daemon/systemd/templates/birdnet_streaming.service
new file mode 100644
index 0000000..5ef6424
--- /dev/null
+++ b/daemon/systemd/templates/birdnet_streaming.service
@@ -0,0 +1,12 @@
+[Unit]
+Description=BirdNET-stream audio streaming service
+
+[Service]
+Type=simple
+User=
+Group=
+WorkingDirectory=
+ExecStart=bash ./daemon/birdnet_streaming.sh
+
+[Install]
+WantedBy=multi-user.target
\ No newline at end of file