Merge branch 'main' into Nachtzuster_improvements_to_birdnet_analysis

This commit is contained in:
Patrick McGuire
2022-05-05 16:56:48 -04:00
committed by GitHub
12 changed files with 156 additions and 91 deletions
+1
View File
@@ -37,6 +37,7 @@ Currently listening in these countries . . . that I know of . . .
- Italy - Italy
- Finland - Finland
- Australia - Australia
- Canada
## Features ## Features
* 24/7 recording and BirdNET-Lite analysis * 24/7 recording and BirdNET-Lite analysis
+7
View File
@@ -48,6 +48,13 @@ ICE_PWD=birdnetpi
BIRDNETPI_URL= BIRDNETPI_URL=
#---------------------------- RTSP Stream URL -------------------------------#
## If RTSP_STREAM is set, the system will use the RTSP stream as its audio
## source instead of recording its own audio. If this variable is kept empty,
## BirdNET-Pi will default to recording its own audio.
RTSP_STREAM=
#------------------- Mobile Notifications via Pushed.co ---------------------# #------------------- Mobile Notifications via Pushed.co ---------------------#
#____________The two variables below enable mobile notifications_______________# #____________The two variables below enable mobile notifications_______________#
+18
View File
@@ -513,3 +513,21 @@ button:hover {
padding:5px; padding:5px;
border: 2px solid black; border: 2px solid black;
} }
button.legacyview {
color:gray;
margin:5px;
float:right;
z-index:100;
position:relative;
font-size:small;
background:#dbffeb;
padding:5px;
border: 2px solid black;
}
button.loadmore {
margin-top:10px;
font-size:x-large;
background:#dbffeb;
padding:10px;
border: 2px solid black;
}
+22 -6
View File
@@ -64,6 +64,19 @@ if(isset($_GET['submit'])) {
} }
} }
if(isset($_GET["rtsp_stream"])) {
$rtsp_stream = str_replace("\r\n", ",", $_GET["rtsp_stream"]);
if(strcmp($rtsp_stream,$config['RTSP_STREAM']) !== 0) {
$contents = preg_replace("/RTSP_STREAM=.*/", "RTSP_STREAM=$rtsp_stream", $contents);
$contents2 = preg_replace("/RTSP_STREAM=.*/", "RTSP_STREAM=$rtsp_stream", $contents2);
$fh = fopen('/etc/birdnet/birdnet.conf', "w");
$fh2 = fopen("./scripts/thisrun.txt", "w");
fwrite($fh, $contents);
fwrite($fh2, $contents2);
exec('sudo systemctl restart birdnet_recording.service');
}
}
if(isset($_GET["overlap"])) { if(isset($_GET["overlap"])) {
$overlap = $_GET["overlap"]; $overlap = $_GET["overlap"];
if(strcmp($overlap,$config['OVERLAP']) !== 0) { if(strcmp($overlap,$config['OVERLAP']) !== 0) {
@@ -108,14 +121,14 @@ if(isset($_GET['submit'])) {
$contents2 = preg_replace("/PRIVACY_MODE=.*/", "PRIVACY_MODE=$privacy_mode", $contents2); $contents2 = preg_replace("/PRIVACY_MODE=.*/", "PRIVACY_MODE=$privacy_mode", $contents2);
if(strcmp($privacy_mode,"on") == 0) { if(strcmp($privacy_mode,"on") == 0) {
exec('sudo sed -i \'s/\/usr\/local\/bin\/server.py/\/usr\/local\/bin\/privacy_server.py/g\' ../../BirdNET-Pi/templates/birdnet_server.service'); exec('sudo sed -i \'s/\/usr\/local\/bin\/server.py/\/usr\/local\/bin\/privacy_server.py/g\' ../../BirdNET-Pi/templates/birdnet_server.service');
exec('sudo systemctl daemon-reload'); exec('sudo systemctl daemon-reload');
exec('restart_services.sh'); exec('restart_services.sh');
header('Location: /log'); header('Location: /log');
} elseif(strcmp($privacy_mode,"off") == 0) { } elseif(strcmp($privacy_mode,"off") == 0) {
exec('sudo sed -i \'s/\/usr\/local\/bin\/privacy_server.py/\/usr\/local\/bin\/server.py/g\' ../../BirdNET-Pi/templates/birdnet_server.service'); exec('sudo sed -i \'s/\/usr\/local\/bin\/privacy_server.py/\/usr\/local\/bin\/server.py/g\' ../../BirdNET-Pi/templates/birdnet_server.service');
exec('sudo systemctl daemon-reload'); exec('sudo systemctl daemon-reload');
exec('restart_services.sh'); exec('restart_services.sh');
header('Location: /log'); header('Location: /log');
} }
} }
} }
@@ -201,6 +214,9 @@ if (file_exists('./scripts/thisrun.txt')) {
<label for="channels">Audio Channels: </label> <label for="channels">Audio Channels: </label>
<input name="channels" type="number" min="1" max="32" step="1" value="<?php print($newconfig['CHANNELS']);?>" required/><br> <input name="channels" type="number" min="1" max="32" step="1" value="<?php print($newconfig['CHANNELS']);?>" required/><br>
<p>Set Channels to the number of channels supported by your sound card. 32 max.</p> <p>Set Channels to the number of channels supported by your sound card. 32 max.</p>
<label for="rtsp_stream">RTSP Stream: </label>
<input name="rtsp_stream" type="url" value="<?php echo $newconfig['RTSP_STREAM'];?>"</input><br>
<p>If you place an RTSP stream URL here, BirdNET-Pi will use that as its audio source.</p>
<label for="recording_length">Recording Length: </label> <label for="recording_length">Recording Length: </label>
<input name="recording_length" oninput="document.getElementsByName('extraction_length')[0].setAttribute('max', this.value);" type="number" min="3" max="60" step="1" value="<?php print($newconfig['RECORDING_LENGTH']);?>" required/><br> <input name="recording_length" oninput="document.getElementsByName('extraction_length')[0].setAttribute('max', this.value);" type="number" min="3" max="60" step="1" value="<?php print($newconfig['RECORDING_LENGTH']);?>" required/><br>
<p>Set Recording Length in seconds between 6 and 60. Multiples of 3 are recommended, as BirdNET analyzes in 3-second chunks.</p> <p>Set Recording Length in seconds between 6 and 60. Multiples of 3 are recommended, as BirdNET analyzes in 3-second chunks.</p>
+3
View File
@@ -167,13 +167,16 @@ until grep 5050 <(netstat -tulpn 2>&1) &> /dev/null 2>&1;do
done done
if [ $(find ${RECS_DIR} -maxdepth 1 -name '*wav' | wc -l) -gt 0 ];then if [ $(find ${RECS_DIR} -maxdepth 1 -name '*wav' | wc -l) -gt 0 ];then
find $RECS_DIR -maxdepth 1 -name '*wav' -type f -size 0 -delete
run_birdnet "${RECS_DIR}" run_birdnet "${RECS_DIR}"
fi fi
YESTERDAY="$RECS_DIR/$(date --date="yesterday" "+%B-%Y/%d-%A")" YESTERDAY="$RECS_DIR/$(date --date="yesterday" "+%B-%Y/%d-%A")"
TODAY="$RECS_DIR/$(date "+%B-%Y/%d-%A")" TODAY="$RECS_DIR/$(date "+%B-%Y/%d-%A")"
if [ $(find ${YESTERDAY} -name '*wav' 2>/dev/null | wc -l) -gt 0 ];then if [ $(find ${YESTERDAY} -name '*wav' 2>/dev/null | wc -l) -gt 0 ];then
find $YESTERDAY -name '*wav' -type f -size 0 -delete
run_birdnet "${YESTERDAY}" run_birdnet "${YESTERDAY}"
elif [ $(find ${TODAY} -name '*wav' | wc -l) -gt 0 ];then elif [ $(find ${TODAY} -name '*wav' | wc -l) -gt 0 ];then
find $TODAY -name '*wav' -type f -size 0 -delete
run_birdnet "${TODAY}" run_birdnet "${TODAY}"
fi fi
+20 -20
View File
@@ -2,29 +2,29 @@
set -x set -x
source /etc/birdnet/birdnet.conf source /etc/birdnet/birdnet.conf
if [ "${TIMESTAMP_FORMAT}" == "12" ];then
STAMP="%I:%M:%S%P"
else
STAMP="%H:%M:%S"
fi
[ -z $RECORDING_LENGTH ] && RECORDING_LENGTH=15 [ -z $RECORDING_LENGTH ] && RECORDING_LENGTH=15
if ! pulseaudio --check;then pulseaudio --start;fi if [ ! -z $RTSP_STREAM ];then
while true;do
if pgrep arecord &> /dev/null ;then for i in ${RTSP_STREAM//,/ };do
echo "Recording" ffmpeg -i ${i} -t ${RECORDING_LENGTH} -vn -acodec pcm_s16le -ac 2 -ar 48000 file:${RECS_DIR}/$(date "+%F")-birdnet-$(date "+%H:%M:%S").wav
else done
until grep 5050 <(netstat -tulpn 2>&1);do
sleep 1
done done
if [ -z ${REC_CARD} ];then else
if ! pulseaudio --check;then pulseaudio --start;fi
arecord -f S16_LE -c${CHANNELS} -r48000 -t wav --max-file-time ${RECORDING_LENGTH}\ if pgrep arecord &> /dev/null ;then
--use-strftime ${RECS_DIR}/%B-%Y/%d-%A/%F-birdnet-${STAMP}.wav echo "Recording"
else else
arecord -f S16_LE -c${CHANNELS} -r48000 -t wav --max-file-time ${RECORDING_LENGTH}\ until grep 5050 <(netstat -tulpn 2>&1);do
-D "${REC_CARD}" --use-strftime \ sleep 1
${RECS_DIR}/%B-%Y/%d-%A/%F-birdnet-${STAMP}.wav done
if [ -z ${REC_CARD} ];then
arecord -f S16_LE -c${CHANNELS} -r48000 -t wav --max-file-time ${RECORDING_LENGTH}\
--use-strftime ${RECS_DIR}/%B-%Y/%d-%A/%F-birdnet-%H:%M:%S.wav
else
arecord -f S16_LE -c${CHANNELS} -r48000 -t wav --max-file-time ${RECORDING_LENGTH}\
-D "${REC_CARD}" --use-strftime \
${RECS_DIR}/%B-%Y/%d-%A/%F-birdnet-%H:%M:%S.wav
fi
fi fi
fi fi
+5 -4
View File
@@ -13,9 +13,9 @@ source /etc/birdnet/birdnet.conf
# Set Variables # Set Variables
TMPFILE=$(mktemp) TMPFILE=$(mktemp)
ANALYZED=${RECS_DIR}/*/*Analyzed #ANALYZED=${RECS_DIR}/*/*Analyzed
# SCAN_DIRS are all directories marked "Analyzed" #SCAN_DIRS are all directories marked "Analyzed"
SCAN_DIRS=($(find ${ANALYZED} -type d 2>/dev/null | sort )) SCAN_DIRS=($(find $HOME -type d -name '*Analyzed' 2>/dev/null | sort ))
for h in "${SCAN_DIRS[@]}";do for h in "${SCAN_DIRS[@]}";do
# The TMPFILE is created from each .csv file BirdNET creates # The TMPFILE is created from each .csv file BirdNET creates
@@ -30,13 +30,14 @@ for h in "${SCAN_DIRS[@]}";do
for i in $(find ${h} -name '*csv' 2>/dev/null | sort );do for i in $(find ${h} -name '*csv' 2>/dev/null | sort );do
# Iterates over each '.csv' file found in each "Analyzed" directory # Iterates over each '.csv' file found in each "Analyzed" directory
# to create the TMPFILE # to create the TMPFILE
echo "${i}" | cut -d'/' -f7 >> ${TMPFILE} echo "$(basename ${i})" >> ${TMPFILE}
sort -k1n -t\; "${i}" | awk '!/Start/{print}' >> ${TMPFILE} sort -k1n -t\; "${i}" | awk '!/Start/{print}' >> ${TMPFILE}
done done
# The extraction reads each line of the TMPFILE and sets the variables ffmpeg # The extraction reads each line of the TMPFILE and sets the variables ffmpeg
# will use. # will use.
while read -r line;do while read -r line;do
echo "Line = $line"
DATE="$(echo "${line}" \ DATE="$(echo "${line}" \
| awk -F- '/birdnet/{print $1"-"$2"-"$3}')" | awk -F- '/birdnet/{print $1"-"$2"-"$3}')"
if [ ! -z ${DATE} ];then if [ ! -z ${DATE} ];then
+7
View File
@@ -61,6 +61,13 @@ ICE_PWD=birdnetpi
BIRDNETPI_URL= BIRDNETPI_URL=
#---------------------------- RTSP Stream URL -------------------------------#
## If RTSP_STREAM is set, the system will use the RTSP stream as its audio
## source instead of recording its own audio. If this variable is kept empty,
## BirdNET-Pi will default to recording its own audio.
RTSP_STREAM=
#------------------- Mobile Notifications via Pushed.co ---------------------# #------------------- Mobile Notifications via Pushed.co ---------------------#
#____________The two variables below enable mobile notifications_______________# #____________The two variables below enable mobile notifications_______________#
+7 -3
View File
@@ -4,8 +4,12 @@ source /etc/birdnet/birdnet.conf
if [ -z ${REC_CARD} ];then if [ -z ${REC_CARD} ];then
echo "Stream not supported" echo "Stream not supported"
else elif [[ ! -z ${RTSP_STREAM} ]];then
ffmpeg -loglevel 52 -ac ${CHANNELS} -f alsa -i ${REC_CARD} -acodec libmp3lame \ ffmpeg -loglevel 52 -ac ${CHANNELS} -i ${RTSP_STREAM} -acodec libmp3lame \
-b:a 320k -ac ${CHANNELS} -content_type 'audio/mpeg' \ -b:a 320k -ac ${CHANNELS} -content_type 'audio/mpeg' \
-f mp3 icecast://source:${ICE_PWD}@localhost:8000/stream -re -f mp3 icecast://source:${ICE_PWD}@localhost:8000/stream -re
fi else
ffmpeg -loglevel 52 -ac ${CHANNELS} -f alsa -i ${REC_CARD} -acodec libmp3lame \
-b:a 320k -ac ${CHANNELS} -content_type 'audio/mpeg' \
-f mp3 icecast://source:${ICE_PWD}@localhost:8000/stream -re
fi
+50 -49
View File
@@ -10,65 +10,66 @@ if($db == False) {
if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" && isset($_GET['previous_detection_identifier'])) { if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" && isset($_GET['previous_detection_identifier'])) {
$statement4 = $db->prepare('SELECT Com_Name, Sci_Name, Date, Time, Confidence, File_Name FROM detections ORDER BY Date DESC, Time DESC LIMIT 1'); $statement4 = $db->prepare('SELECT Com_Name, Sci_Name, Date, Time, Confidence, File_Name FROM detections ORDER BY Date DESC, Time DESC LIMIT 5');
if($statement4 == False) { if($statement4 == False) {
echo "Database is busy"; echo "Database is busy";
header("refresh: 0;"); header("refresh: 0;");
} }
$result4 = $statement4->execute(); $result4 = $statement4->execute();
$mostrecent = $result4->fetchArray(SQLITE3_ASSOC); // hopefully one of the 5 most recent detections has an image that is valid, we'll use that one as the most recent detection until the newer ones get their images created
$comname = preg_replace('/ /', '_', $mostrecent['Com_Name']); while($mostrecent = $result4->fetchArray(SQLITE3_ASSOC)) {
$sciname = preg_replace('/ /', '_', $mostrecent['Sci_Name']); $comname = preg_replace('/ /', '_', $mostrecent['Com_Name']);
$comname = preg_replace('/\'/', '', $comname); $sciname = preg_replace('/ /', '_', $mostrecent['Sci_Name']);
$filename = "/By_Date/".$mostrecent['Date']."/".$comname."/".$mostrecent['File_Name']; $comname = preg_replace('/\'/', '', $comname);
$filename = "/By_Date/".$mostrecent['Date']."/".$comname."/".$mostrecent['File_Name'];
// check to make sure the image actually exists, sometimes it takes a minute to be created
if($_GET['previous_detection_identifier'] != $filename || $_GET['previous_detection_identifier'] == "undefined") { if (isset($_SERVER['HTTPS']) &&
// check to make sure the image actually exists, sometimes it takes a minute to be created ($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1) ||
if (isset($_SERVER['HTTPS']) && isset($_SERVER['HTTP_X_FORWARDED_PROTO']) &&
($_SERVER['HTTPS'] == 'on' || $_SERVER['HTTPS'] == 1) || $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $protocol = 'https://';
$_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') {
$protocol = 'https://';
}
else {
$protocol = 'http://';
}
$headers = @get_headers($protocol.$_SERVER['HTTP_HOST'].$filename.".png");
if(strpos($headers[0],'200')) {
?>
<style>
.fade-in {
opacity: 1;
animation-name: fadeInOpacity;
animation-iteration-count: 1;
animation-timing-function: ease-in;
animation-duration: 1s;
} }
else {
@keyframes fadeInOpacity { $protocol = 'http://';
0% { }
opacity: 0; $headers = @get_headers($protocol.$_SERVER['HTTP_HOST'].$filename.".png");
} // we've found our valid detection! ignore everything else from the database loop
100% { if(strpos($headers[0],'200')) {
if($_GET['previous_detection_identifier'] == $filename) { die(); }
?>
<style>
.fade-in {
opacity: 1; opacity: 1;
animation-name: fadeInOpacity;
animation-iteration-count: 1;
animation-timing-function: ease-in;
animation-duration: 1s;
} }
@keyframes fadeInOpacity {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
</style>
<table class="<?php echo ($_GET['previous_detection_identifier'] == 'undefined') ? '' : 'fade-in'; ?>">
<h3>Most Recent Detection: <span style="font-weight: normal;"><?php echo $mostrecent['Date']." ".$mostrecent['Time'];?></span></h3>
<tr>
<td class="relative"><a target="_blank" href="index.php?filename=<?php echo $mostrecent['File_Name']; ?>"><img class="copyimage" width="25" height="25" src="images/copy.png"></a>
<form action="" method="GET">
<input type="hidden" name="view" value="Species Stats">
<button type="submit" name="species" value="<?php echo $mostrecent['Com_Name'];?>"><?php echo $mostrecent['Com_Name'];?></button></br>
<a href="https://wikipedia.org/wiki/<?php echo $sciname;?>" target="_blank"/><i><?php echo $mostrecent['Sci_Name'];?></i></a>
<br>Confidence: <?php echo $mostrecent['Confidence'];?><br>
<video style="margin-top:10px" onplay='setLiveStreamVolume(0)' onended='setLiveStreamVolume(1)' onpause='setLiveStreamVolume(1)' controls poster="<?php echo $filename.".png";?>" preload="none" title="<?php echo $filename;?>"><source src="<?php echo $filename;?>"></video></td>
</form>
</tr>
</table> <?php break;
} }
</style>
<table class="<?php echo ($_GET['previous_detection_identifier'] == 'undefined') ? '' : 'fade-in'; ?>">
<h3>Most Recent Detection: <span style="font-weight: normal;"><?php echo $mostrecent['Date']." ".$mostrecent['Time'];?></span></h3>
<tr>
<td class="relative"><a target="_blank" href="index.php?filename=<?php echo $mostrecent['File_Name']; ?>"><img class="copyimage" width="25" height="25" src="images/copy.png"></a>
<form action="" method="GET">
<input type="hidden" name="view" value="Species Stats">
<button type="submit" name="species" value="<?php echo $mostrecent['Com_Name'];?>"><?php echo $mostrecent['Com_Name'];?></button></br>
<a href="https://wikipedia.org/wiki/<?php echo $sciname;?>" target="_blank"/><i><?php echo $mostrecent['Sci_Name'];?></i></a>
<br>Confidence: <?php echo $mostrecent['Confidence'];?><br>
<video style="margin-top:10px" onplay='setLiveStreamVolume(0)' onended='setLiveStreamVolume(1)' onpause='setLiveStreamVolume(1)' controls poster="<?php echo $filename.".png";?>" preload="none" title="<?php echo $filename;?>"><source src="<?php echo $filename;?>"></video></td>
</form>
</tr>
</table> <?php
}
} }
die(); die();
} }
+11 -7
View File
@@ -89,7 +89,7 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) {
?> ?>
<?php if(isset($_GET['display_limit']) && is_numeric($_GET['display_limit'])){ ?> <?php if(isset($_GET['display_limit']) && is_numeric($_GET['display_limit'])){ ?>
<tr class="relative" id="<?php echo $iterations; ?>"> <tr class="relative" id="<?php echo $iterations; ?>">
<td><a target="_blank" href="index.php?filename=<?php echo $todaytable['File_Name']; ?>"><img class="copyimage" width=25 src="images/copy.png"></a><?php echo $todaytable['Time'];?><br> <td class="relative"><a target="_blank" href="index.php?filename=<?php echo $todaytable['File_Name']; ?>"><img class="copyimage" width=25 src="images/copy.png"></a><?php echo $todaytable['Time'];?><br>
<b><a class="a2" href="https://allaboutbirds.org/guide/<?php echo $comname;?>" target="top"><?php echo $todaytable['Com_Name'];?></a></b><br> <b><a class="a2" href="https://allaboutbirds.org/guide/<?php echo $comname;?>" target="top"><?php echo $todaytable['Com_Name'];?></a></b><br>
<a class="a2" href="https://wikipedia.org/wiki/<?php echo $sciname;?>" target="top"><i><?php echo $todaytable['Sci_Name'];?></i></a><br> <a class="a2" href="https://wikipedia.org/wiki/<?php echo $sciname;?>" target="top"><i><?php echo $todaytable['Sci_Name'];?></i></a><br>
<b>Confidence:</b> <?php echo $todaytable['Confidence'];?><br> <b>Confidence:</b> <?php echo $todaytable['Confidence'];?><br>
@@ -112,7 +112,7 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) {
// don't show the button if there's no more detections to be displayed, we're at the end of the list // don't show the button if there's no more detections to be displayed, we're at the end of the list
if($iterations >= 40 && isset($_GET['display_limit']) && is_numeric($_GET['display_limit'])) { ?> if($iterations >= 40 && isset($_GET['display_limit']) && is_numeric($_GET['display_limit'])) { ?>
<center> <center>
<button style="margin-top:10px;font-size:x-large;background:#dbffeb;padding:10px;border: 2px solid black;" onclick="loadDetections(<?php echo $_GET['display_limit'] + 40; ?>, this);" value="Today's Detections">Load 40 More...</button> <button class="loadmore" onclick="loadDetections(<?php echo $_GET['display_limit'] + 40; ?>, this);" value="Today's Detections">Load 40 More...</button>
</center> </center>
<?php } <?php }
@@ -156,11 +156,11 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) {
</tr> </tr>
</table> </table>
<h3>Today's Detections — <input size="11" type="text" placeholder="Search..." id="searchterm" name="searchterm"></h3> <h3>Today's Detections — <input autocomplete="off" size="11" type="text" placeholder="Search..." id="searchterm" name="searchterm"></h3>
<div style="padding-bottom:10px" id="detections_table"></div> <div style="padding-bottom:10px" id="detections_table"></div>
<button onclick="switchViews(this);" style="color:gray;margin:5px;float:right;z-index:100;position:relative;font-size:small;background:#dbffeb;padding:5px;border: 2px solid black;">Legacy view</button> <button onclick="switchViews(this);" class="legacyview">Legacy view</button>
</div> </div>
@@ -169,7 +169,7 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) {
var timer = ''; var timer = '';
searchterm = ""; searchterm = "";
document.getElementById("searchterm").oninput = (function(e) { document.getElementById("searchterm").onkeydown = (function(e) {
if (e.key === "Enter") { if (e.key === "Enter") {
clearTimeout(timer); clearTimeout(timer);
searchDetections(document.getElementById("searchterm").value); searchDetections(document.getElementById("searchterm").value);
@@ -178,7 +178,11 @@ document.getElementById("searchterm").oninput = (function(e) {
clearTimeout(timer); clearTimeout(timer);
timer = setTimeout(function() { timer = setTimeout(function() {
searchDetections(document.getElementById("searchterm").value); searchDetections(document.getElementById("searchterm").value);
document.getElementById("searchterm").blur();
setTimeout(function() {
// search auto submitted and now the user is probably scrolling, get the keyboard out of the way & prevent browser from jumping to the top when a video is played
document.getElementById("searchterm").blur();
}, 2000);
}, 1000); }, 1000);
} }
}); });
@@ -194,7 +198,7 @@ function switchViews(element) {
} }
} }
function searchDetections(searchvalue) { function searchDetections(searchvalue) {
document.getElementById("detections_table").innerHTML = ""; document.getElementById("detections_table").innerHTML = "<h3>Loading...</h3>";
searchterm = searchvalue; searchterm = searchvalue;
loadDetections(40,undefined); loadDetections(40,undefined);
} }
+5 -2
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Update BirdNET-Pi # Update BirdNET-Pi's Git Repo
source /etc/birdnet/birdnet.conf source /etc/birdnet/birdnet.conf
trap 'exit 1' SIGINT SIGHUP trap 'exit 1' SIGINT SIGHUP
USER=$(awk -F: '/1000/ {print $1}' /etc/passwd) USER=$(awk -F: '/1000/ {print $1}' /etc/passwd)
@@ -11,4 +11,7 @@ sudo -u${USER} git -C $my_dir pull -f
sudo systemctl daemon-reload sudo systemctl daemon-reload
sudo -u${USER} git -C $my_dir stash pop sudo -u${USER} git -C $my_dir stash pop
sudo ln -sf $my_dir/* /usr/local/bin/ sudo ln -sf $my_dir/* /usr/local/bin/
sudo $my_dir/update_birdnet_snippets.sh
# The script below handles changes to the host system
# Any additions to the updater should be placed in that file.
sudo $my_dir/update_birdnet_snippets.sh