Add base daemon scripts
This commit is contained in:
parent
43e4ebeef3
commit
17b2d3d2b1
|
@ -1,3 +1,7 @@
|
||||||
var/
|
var/
|
||||||
/.venv/
|
/.venv/
|
||||||
/analyzer/
|
/analyzer/
|
||||||
|
|
||||||
|
.env
|
||||||
|
|
||||||
|
species_list.txt
|
11
INSTALL.md
11
INSTALL.md
|
@ -1,5 +1,13 @@
|
||||||
# Installation Guide for BirdNET-stream
|
# Installation Guide for BirdNET-stream
|
||||||
|
|
||||||
|
This guide allow you to install BirdNET-stream step by step on your debian based system.
|
||||||
|
|
||||||
|
For a one-liner installation, you can use the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -sL https://raw.githubusercontent.com/birdnet-stream/birdnet-stream/master/install.sh | bash
|
||||||
|
```
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
- git
|
- git
|
||||||
|
@ -25,7 +33,8 @@ sudo apt-get install ffmpeg
|
||||||
### Clone BirdNET-stream repository
|
### Clone BirdNET-stream repository
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://forge.chapril.org/UncleSamulus/BirdNET-stream.git
|
git clone --recurse-submodules https://forge.chapril.org/UncleSamulus/BirdNET-stream.git
|
||||||
|
```
|
||||||
|
|
||||||
### Setup python virtualenv and packages
|
### Setup python virtualenv and packages
|
||||||
|
|
||||||
|
|
16
README.md
16
README.md
|
@ -6,6 +6,22 @@
|
||||||
<img src="./media/logo.svg" alt="BirdNET-stream logo image IA generated" style="width: 500px">
|
<img src="./media/logo.svg" alt="BirdNET-stream logo image IA generated" style="width: 500px">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
## Introduction
|
||||||
|
|
||||||
|
BirdNET-stream record sound on Linux computer and analyze it with the help of the BirdNET algorithm. It extracts most interesting bird songs and calls accessible in a webapp.
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
On debian based system, you can install BirdNET-stream with the following command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -sL https://raw.githubusercontent.com/birdnet-stream/birdnet-stream/master/install.sh | bash
|
||||||
|
```
|
||||||
|
|
||||||
|
For finer control, or to adapt to your system, you can follow the instructions in the [INSTALL.md](./INSTALL.md) file.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
## Acknoledgements
|
## Acknoledgements
|
||||||
|
|
||||||
- [BirdNET](https://birdnet.cornell.edu) on which this project relies
|
- [BirdNET](https://birdnet.cornell.edu) on which this project relies
|
||||||
|
|
|
@ -41,33 +41,30 @@ check_prerequisites() {
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
if [[ -z ${SPECIES_LIST} ]]; then
|
||||||
if [[ -z ${SPECIES_LIST} ]];
|
|
||||||
then
|
|
||||||
echo "SPECIES_LIST is not set"
|
echo "SPECIES_LIST is not set"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
if [[ -f $PYTHON_EXECUTABLE ]];
|
if [[ -f ${PYTHON_EXECUTABLE} ]]; then
|
||||||
then
|
|
||||||
if $verbose; then
|
if $verbose; then
|
||||||
echo "Python executable found: $PYTHON_EXECUTABLE"
|
echo "Python executable found: ${PYTHON_EXECUTABLE}"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
echo "Python executable not found: $PYTHON_EXECUTABLE"
|
echo "Python executable not found: ${PYTHON_EXECUTABLE}"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
# Get array of audio chunks to be processed
|
# Get array of audio chunks to be processed
|
||||||
get_chunk_list() {
|
get_chunk_list() {
|
||||||
find "$CHUNK_FOLDER/in" -type f -name '*.wav' -exec basename {} \; ! -size 0 | sort
|
find "${CHUNK_FOLDER}/in" -type f -name '*.wav' -exec basename {} \; ! -size 0 | sort
|
||||||
}
|
}
|
||||||
|
|
||||||
# Perform audio chunk analysis on one chunk
|
# Perform audio chunk analysis on one chunk
|
||||||
analyze_chunk() {
|
analyze_chunk() {
|
||||||
chunk_name=$1
|
chunk_name=$1
|
||||||
chunk_path="$CHUNK_FOLDER/in/$chunk_name"
|
chunk_path="${CHUNK_FOLDER}/in/$chunk_name"
|
||||||
output_dir="$CHUNK_FOLDER/out/$chunk_name.d"
|
output_dir="${CHUNK_FOLDER}/out/$chunk_name.d"
|
||||||
mkdir -p "$output_dir"
|
mkdir -p "$output_dir"
|
||||||
date=$(echo $chunk_name | cut -d'_' -f2)
|
date=$(echo $chunk_name | cut -d'_' -f2)
|
||||||
week=$(./daemon/weekof.sh $date)
|
week=$(./daemon/weekof.sh $date)
|
||||||
|
@ -78,8 +75,8 @@ analyze_chunk() {
|
||||||
analyze_chunks() {
|
analyze_chunks() {
|
||||||
for chunk_name in $(get_chunk_list); do
|
for chunk_name in $(get_chunk_list); do
|
||||||
analyze_chunk $chunk_name
|
analyze_chunk $chunk_name
|
||||||
chunk_path="$CHUNK_FOLDER/in/$chunk_name"
|
chunk_path="${CHUNK_FOLDER}/in/$chunk_name"
|
||||||
mv $chunk_path "$CHUNK_FOLDER/out/$chunk_name"
|
mv $chunk_path "${CHUNK_FOLDER}/out/$chunk_name"
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
#! /usr/bin/env bash
|
||||||
|
##
|
||||||
|
## Clean up var folder from useless files
|
||||||
|
##
|
||||||
|
|
||||||
|
config_filepath="./config/analyzer.conf"
|
||||||
|
|
||||||
|
if [ -f "$config_filepath" ]; then
|
||||||
|
source "$config_filepath"
|
||||||
|
else
|
||||||
|
echo "Config file not found: $config_filepath"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
wav2dir_name() {
|
||||||
|
wav_path=$1
|
||||||
|
dir_name=$(basename "$wav_path" .wav)
|
||||||
|
echo "$dir_name"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Clean out folder from empty audio
|
||||||
|
clean() {
|
||||||
|
rm -rf $(junk)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if string contains string
|
||||||
|
mem() {
|
||||||
|
string=$2
|
||||||
|
substring=$1
|
||||||
|
if [[ "$string" == *"$substring"* ]]; then
|
||||||
|
echo "true"
|
||||||
|
else
|
||||||
|
echo "false"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get list of junk files
|
||||||
|
junk() {
|
||||||
|
# Get all empty files from treatement folder
|
||||||
|
find "${CHUNK_FOLDER}/out" -type f -name '*.wav' -size 0
|
||||||
|
for file in $junk; do
|
||||||
|
folder=$(wav2dir_name "$file")
|
||||||
|
if [[ -d $folder ]]; then
|
||||||
|
junk="$junk $folder"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
# Get all empty files from record folder
|
||||||
|
junk=$(find "${CHUNK_FOLDER}/in" -type f -name '*.wav' -exec basename {} \; ! -size 0)
|
||||||
|
# Get all empty treatment directories
|
||||||
|
junk="$junk $(find ${CHUNK_FOLDER}/out -type d -empty)"
|
||||||
|
# Get all empty record directories
|
||||||
|
treatement_folder=$(find "${CHUNK_FOLDER}/out" -type d ! -empty)
|
||||||
|
for folder in $treatement_folder; do
|
||||||
|
if ! $(mem $folder $junk) && $(no_bird_in_model_output $folder); then
|
||||||
|
junk="$junk $folder"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo "$junk"
|
||||||
|
}
|
||||||
|
|
||||||
|
no_bird_in_model_output() {
|
||||||
|
folder=$1
|
||||||
|
output="${folder}/model.out.csv"
|
||||||
|
lines=$(wc -l < "$output")
|
||||||
|
if [[ $lines -eq 1 ]]; then
|
||||||
|
echo "true"
|
||||||
|
else
|
||||||
|
echo "false"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
clean
|
||||||
|
}
|
||||||
|
|
||||||
|
main
|
|
@ -1,7 +1,6 @@
|
||||||
#! /usr/bin/env bash
|
#! /usr/bin/env bash
|
||||||
|
|
||||||
record_chunk()
|
record_chunk() {
|
||||||
{
|
|
||||||
DEVICE=$1
|
DEVICE=$1
|
||||||
DURATION=$2
|
DURATION=$2
|
||||||
ffmpeg -f pulse -i ${DEVICE} -t ${DURATION} -vn -acodec pcm_s16le -ac 1 -ar 48000 file:${CHUNK_FOLDER}/in/birdnet_$(date "+%Y%m%d_%H%M%S").wav
|
ffmpeg -f pulse -i ${DEVICE} -t ${DURATION} -vn -acodec pcm_s16le -ac 1 -ar 48000 file:${CHUNK_FOLDER}/in/birdnet_$(date "+%Y%m%d_%H%M%S").wav
|
||||||
|
@ -23,6 +22,16 @@ if [[ -z $AUDIO_DEVICE ]]; then
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
check_folder() {
|
||||||
|
if [[ ! -d "${CHUNK_FOLDER}" ]]; then
|
||||||
|
echo "CHUNK_FOLDER does not exist: ${CHUNK_FOLDER}"
|
||||||
|
echo "Creating recording dir"
|
||||||
|
mkdir -p "${CHUNK_FOLDER}/in"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_folder
|
||||||
|
|
||||||
while true; do
|
while true; do
|
||||||
record_chunk $AUDIO_DEVICE $RECORDING_DURATION
|
record_chunk $AUDIO_DEVICE $RECORDING_DURATION
|
||||||
done
|
done
|
|
@ -0,0 +1,15 @@
|
||||||
|
# Launch BirdNET-Analyzer on the previously recorded audio chunks
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Description=BirdNET-stream Analyzis
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=$USER
|
||||||
|
Group=$USER
|
||||||
|
ExecStart=/home/$USER/BirdNET-Analyzer/deamon/birdnet_analysis.sh
|
||||||
|
Restart=always
|
||||||
|
RestartSec=3
|
||||||
|
Type=simple
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
|
@ -0,0 +1,15 @@
|
||||||
|
# BirdNET recording script launcher service
|
||||||
|
|
||||||
|
[Unit]
|
||||||
|
Description=BirdNET-stream recording
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
User=1000
|
||||||
|
Group=1000
|
||||||
|
ExecStart="bash /home/$USER/BirdNET-stream/daemon/birdnet_recording.sh"
|
||||||
|
Restart=always
|
||||||
|
RestartSec=3
|
||||||
|
Type=simple
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
|
@ -1,5 +1,6 @@
|
||||||
#! /usr/bin/env bash
|
#! /usr/bin/env bash
|
||||||
|
|
||||||
|
# Take a week with format "YYYY-MM-DD" and return the week number.
|
||||||
function weekof()
|
function weekof()
|
||||||
{
|
{
|
||||||
local date=$1
|
local date=$1
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
#! /usr/bin/env bash
|
||||||
|
set -X
|
||||||
|
set -e
|
||||||
|
|
||||||
|
DEBUG=${DEBUG:-0}
|
||||||
|
|
||||||
|
# Standard Installation Script for BirdNET-stream for Debian Based Linux distros
|
||||||
|
|
||||||
|
REQUIREMENTS="git ffmpeg python3-pip python3-dev"
|
||||||
|
REPOSITORY="https://github.com/UncleSamulus/BirdNET-stream.git"
|
||||||
|
PYTHON_VENV=".venv/birdnet-stream"
|
||||||
|
|
||||||
|
# Update system
|
||||||
|
update() {
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get upgrade
|
||||||
|
}
|
||||||
|
|
||||||
|
debug() {
|
||||||
|
if [ $DEBUG -eq 1 ]; then
|
||||||
|
echo "$1"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
install_requirements() {
|
||||||
|
if
|
||||||
|
requirements=$1
|
||||||
|
# Install requirements
|
||||||
|
missing_requirements=""
|
||||||
|
for requirement in $requirements; do
|
||||||
|
if ! dpkg -s $requirement >/dev/null 2>&1; then
|
||||||
|
missing_requirements="$missing_requirements $requirement"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
if [ -n "$missing_requirements" ]; then
|
||||||
|
debug "Installing missing requirements: $missing_requirements"
|
||||||
|
sudo apt-get install $missing_requirements
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install BirdNET-stream
|
||||||
|
install_birdnetstream() {
|
||||||
|
# Clone BirdNET-stream
|
||||||
|
debug "Cloning BirdNET-stream from $REPOSITORY"
|
||||||
|
git clone --recurse-submodules $REPOSITORY
|
||||||
|
# Install BirdNET-stream
|
||||||
|
cd BirdNET-stream
|
||||||
|
debug "Creating python3 virtual environment '$PYTHON_VENV'"
|
||||||
|
python3 -m venv $PYTHON_VENV
|
||||||
|
debug "Activating $PYTHON_VENV"
|
||||||
|
source .venv/birdnet-stream/bin/activate
|
||||||
|
debug "Installing python packages"
|
||||||
|
pip install -U pip
|
||||||
|
pip install -r requirements.txt
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install systemd services
|
||||||
|
install_birdnetstream_services() {
|
||||||
|
debug "Setting up BirdNET stream systemd services"
|
||||||
|
sudo ln -s $PWD/BirdNET-stream/daemon/systemd/birdnet_recording.service /etc/systemd/system/birdnet_recording.service
|
||||||
|
sudo ln -s $PWD/BirdNET-stream/daemon/systemd/birdnet_analyzis.service /etc/systemd/system/birdnet_analyzis.service
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl enable --now birdnet_recording.service birdnet_analyzis.service
|
||||||
|
}
|
||||||
|
|
||||||
|
main() {
|
||||||
|
install_requirements $REQUIREMENTS
|
||||||
|
install_birdnetstream
|
||||||
|
install_birdnetstream_services
|
||||||
|
}
|
||||||
|
|
||||||
|
main
|
|
@ -1,24 +0,0 @@
|
||||||
#! /usr/bin/env bash
|
|
||||||
|
|
||||||
# Load config file
|
|
||||||
config_filepath="./config/analyzer.conf"
|
|
||||||
|
|
||||||
if [ -f "$config_filepath" ]; then
|
|
||||||
source "$config_filepath"
|
|
||||||
else
|
|
||||||
echo "Config file not found: $config_filepath"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Remove all files from the temporary record directory
|
|
||||||
function clean_record_dir()
|
|
||||||
{
|
|
||||||
rm -rf "$CHUNK_FOLDER/in/*.wav"
|
|
||||||
}
|
|
||||||
|
|
||||||
function remove_empty_records()
|
|
||||||
{
|
|
||||||
find $CHUNK_FOLDER/in -maxdepth 1 -name '*wav' -type f -size 0 -delete
|
|
||||||
}
|
|
||||||
|
|
||||||
remove_empty_records
|
|
Loading…
Reference in New Issue