Merge branch 'main' into remove-python-shebangs
This commit is contained in:
@@ -12,7 +12,7 @@ Icon made by <a href="https://www.freepik.com" title="Freepik">Freepik</a> from
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
## Introduction
|
## Introduction
|
||||||
BirdNET-Pi is built on the [TFLite version of BirdNET](https://github.com/kahst/BirdNET-Lite) by [**@kahst**](https://github.com/kahst) <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/"><img src="https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-lightgrey.svg"></a> using [pre-built TFLite binaries](https://github.com/PINTO0309/TensorflowLite-bin) by [**@PINTO0309**](https://github.com/PINTO0309) . It is able to recognize bird sounds from a USB sound card in realtime and share its data with the rest of the world.
|
BirdNET-Pi is built on the [TFLite version of BirdNET](https://github.com/kahst/BirdNET-Lite) by [**@kahst**](https://github.com/kahst) <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/"><img src="https://img.shields.io/badge/License-CC%20BY--NC--SA%204.0-lightgrey.svg"></a> using [pre-built TFLite binaries](https://github.com/PINTO0309/TensorflowLite-bin) by [**@PINTO0309**](https://github.com/PINTO0309) . It is able to recognize bird sounds from a USB microphone or sound card in realtime and share its data with the rest of the world.
|
||||||
|
|
||||||
Check out birds from around the world
|
Check out birds from around the world
|
||||||
- [BirdWeather](https://app.birdweather.com)<br>
|
- [BirdWeather](https://app.birdweather.com)<br>
|
||||||
|
|||||||
@@ -60,7 +60,8 @@ RTSP_STREAM=
|
|||||||
|
|
||||||
APPRISE_NOTIFICATION_TITLE="New BirdNET-Pi Detection"
|
APPRISE_NOTIFICATION_TITLE="New BirdNET-Pi Detection"
|
||||||
APPRISE_NOTIFICATION_BODY="A \$sciname \$comname was just detected with a confidence of \$confidence"
|
APPRISE_NOTIFICATION_BODY="A \$sciname \$comname was just detected with a confidence of \$confidence"
|
||||||
APPRISE_NOTIFY_EACH_DETECTION=false
|
APPRISE_NOTIFY_EACH_DETECTION=0
|
||||||
|
APPRISE_NOTIFY_NEW_SPECIES=0
|
||||||
|
|
||||||
#---------------------- Flickr Images API Configuration -----------------------#
|
#---------------------- Flickr Images API Configuration -----------------------#
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
+3
-3
@@ -5,7 +5,7 @@ body::-webkit-scrollbar {
|
|||||||
display:none
|
display:none
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css?v=14">
|
||||||
<body>
|
<body>
|
||||||
<div class="banner">
|
<div class="banner">
|
||||||
<div class="logo">
|
<div class="logo">
|
||||||
@@ -36,7 +36,7 @@ if(isset($_GET['stream'])){
|
|||||||
echo "
|
echo "
|
||||||
<audio controls autoplay><source src=\"/stream\"></audio>
|
<audio controls autoplay><source src=\"/stream\"></audio>
|
||||||
</div>
|
</div>
|
||||||
<h1><a href=\"/\">BirdNET-Pi</a></h1>
|
<h1><a href=\"/\"><img class=\"topimage\" src=\"images/bnp.png\"></a></h1>
|
||||||
</div>";
|
</div>";
|
||||||
} else {
|
} else {
|
||||||
header('WWW-Authenticate: Basic realm="My Realm"');
|
header('WWW-Authenticate: Basic realm="My Realm"');
|
||||||
@@ -51,7 +51,7 @@ if(isset($_GET['stream'])){
|
|||||||
<button type=\"submit\" name=\"stream\" value=\"play\">Live Audio</button>
|
<button type=\"submit\" name=\"stream\" value=\"play\">Live Audio</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
<h1><a href=\"/\">BirdNET-Pi</a></h1>
|
<h1><a href=\"/\"><img class=\"topimage\" src=\"images/bnp.png\"></a></h1>
|
||||||
</div>";
|
</div>";
|
||||||
}
|
}
|
||||||
if(isset($_GET['filename'])) {
|
if(isset($_GET['filename'])) {
|
||||||
|
|||||||
+50
-4
@@ -70,11 +70,16 @@ label {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
border-color:black;
|
||||||
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
background-color: transparent;
|
background-color: transparent;
|
||||||
border: none;
|
border: none;
|
||||||
color: black;
|
color: black;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
transition:background-color 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
button:hover {
|
button:hover {
|
||||||
@@ -138,10 +143,15 @@ button:hover {
|
|||||||
margin-left: auto;
|
margin-left: auto;
|
||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
margin-bottom: 15px;
|
margin-bottom: 15px;
|
||||||
box-shadow: 0px 0px 17px 1px rgba(0, 0, 0, 0.10); !important;
|
box-shadow: 0px 0px 28px 1px rgba(0, 0, 0, 0.10); !important;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.topimage {
|
||||||
|
width:175px;
|
||||||
|
display:initial !important;
|
||||||
|
}
|
||||||
|
|
||||||
.topnav form {
|
.topnav form {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -181,7 +191,7 @@ button:hover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.stats table {
|
.stats table {
|
||||||
width: 75%;
|
width: 60%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.overview th {
|
.overview th {
|
||||||
@@ -247,11 +257,14 @@ button:hover {
|
|||||||
.views .centered button {
|
.views .centered button {
|
||||||
background-color: rgb(219, 255, 235);
|
background-color: rgb(219, 255, 235);
|
||||||
padding: 12px;
|
padding: 12px;
|
||||||
|
transition:box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
box-shadow:0px 3px 1px -2px rgb(0 0 0 / 20%), 0px 2px 2px 0px rgb(0 0 0 / 14%), 0px 1px 5px 0px rgb(0 0 0 / 12%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.views .centered button:hover {
|
.views .centered button:hover {
|
||||||
background-color: rgb(159, 226, 155);
|
background-color: rgb(159, 226, 155);
|
||||||
color: black;
|
color: black;
|
||||||
|
box-shadow:0px 2px 4px -1px rgb(0 0 0 / 20%), 0px 4px 5px 0px rgb(0 0 0 / 14%), 0px 1px 10px 0px rgb(0 0 0 / 12%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings {
|
.settings {
|
||||||
@@ -546,7 +559,7 @@ button:hover {
|
|||||||
font-size:x-large;
|
font-size:x-large;
|
||||||
background:#dbffeb;
|
background:#dbffeb;
|
||||||
padding:5px;
|
padding:5px;
|
||||||
|
box-shadow: 0px 0px 5px 2px rgba(0, 0, 0, 0.10);
|
||||||
}
|
}
|
||||||
button.legacyview {
|
button.legacyview {
|
||||||
color:gray;
|
color:gray;
|
||||||
@@ -557,15 +570,31 @@ button.legacyview {
|
|||||||
font-size:small;
|
font-size:small;
|
||||||
background:#dbffeb;
|
background:#dbffeb;
|
||||||
padding:5px;
|
padding:5px;
|
||||||
|
transition:box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
box-shadow:0px 3px 1px -2px rgb(0 0 0 / 20%), 0px 2px 2px 0px rgb(0 0 0 / 14%), 0px 1px 5px 0px rgb(0 0 0 / 12%);
|
||||||
}
|
}
|
||||||
|
button.legacyview:hover {
|
||||||
|
box-shadow:0px 2px 4px -1px rgb(0 0 0 / 20%), 0px 4px 5px 0px rgb(0 0 0 / 14%), 0px 1px 10px 0px rgb(0 0 0 / 12%);
|
||||||
|
}
|
||||||
|
|
||||||
button.loadmore {
|
button.loadmore {
|
||||||
margin-top:10px;
|
margin-top:10px;
|
||||||
font-size:x-large;
|
font-size:x-large;
|
||||||
background:#dbffeb;
|
background:#dbffeb;
|
||||||
padding:10px;
|
padding:10px;
|
||||||
|
transition:box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
box-shadow:0px 3px 1px -2px rgb(0 0 0 / 20%), 0px 2px 2px 0px rgb(0 0 0 / 14%), 0px 1px 5px 0px rgb(0 0 0 / 12%);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
button.loadmore:hover {
|
||||||
|
box-shadow:0px 2px 4px -1px rgb(0 0 0 / 20%), 0px 4px 5px 0px rgb(0 0 0 / 14%), 0px 1px 10px 0px rgb(0 0 0 / 12%);
|
||||||
|
}
|
||||||
|
#searchterm {
|
||||||
|
transition:box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
}
|
||||||
|
#searchterm:hover {
|
||||||
|
box-shadow:0px 2px 4px -1px rgb(0 0 0 / 20%), 0px 4px 5px 0px rgb(0 0 0 / 14%), 0px 1px 10px 0px rgb(0 0 0 / 12%);
|
||||||
|
}
|
||||||
|
|
||||||
tr {
|
tr {
|
||||||
background-color:#9fe29b;
|
background-color:#9fe29b;
|
||||||
@@ -581,6 +610,11 @@ tr {
|
|||||||
.centered form#views button {
|
.centered form#views button {
|
||||||
box-shadow: 0px 0px 5px 2px rgba(0, 0, 0, 0.10);
|
box-shadow: 0px 0px 5px 2px rgba(0, 0, 0, 0.10);
|
||||||
margin:2px;
|
margin:2px;
|
||||||
|
transition:box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
box-shadow:0px 3px 1px -2px rgb(0 0 0 / 20%), 0px 2px 2px 0px rgb(0 0 0 / 14%), 0px 1px 5px 0px rgb(0 0 0 / 12%);
|
||||||
|
}
|
||||||
|
.centered form#views button:hover {
|
||||||
|
box-shadow:0px 2px 4px -1px rgb(0 0 0 / 20%), 0px 4px 5px 0px rgb(0 0 0 / 14%), 0px 1px 10px 0px rgb(0 0 0 / 12%);
|
||||||
}
|
}
|
||||||
input {
|
input {
|
||||||
box-shadow: 0px 0px 17px 1px rgba(0, 0, 0, 0.10);
|
box-shadow: 0px 0px 17px 1px rgba(0, 0, 0, 0.10);
|
||||||
@@ -605,6 +639,8 @@ dialog::backdrop {
|
|||||||
margin-bottom:3px;
|
margin-bottom:3px;
|
||||||
}
|
}
|
||||||
.centered_image_container img.img1 {
|
.centered_image_container img.img1 {
|
||||||
|
transition:box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
|
box-shadow:0px 3px 1px -2px rgb(0 0 0 / 20%), 0px 2px 2px 0px rgb(0 0 0 / 14%), 0px 1px 5px 0px rgb(0 0 0 / 12%);
|
||||||
cursor:pointer;
|
cursor:pointer;
|
||||||
height:95%;
|
height:95%;
|
||||||
position:absolute;
|
position:absolute;
|
||||||
@@ -613,9 +649,19 @@ dialog::backdrop {
|
|||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
width:unset;
|
width:unset;
|
||||||
}
|
}
|
||||||
|
.centered_image_container img.img1:hover{
|
||||||
|
opacity:0.8;
|
||||||
|
box-shadow:0px 2px 4px -1px rgb(0 0 0 / 20%), 0px 4px 5px 0px rgb(0 0 0 / 14%), 0px 1px 10px 0px rgb(0 0 0 / 12%);
|
||||||
|
}
|
||||||
.centered_image_container * {
|
.centered_image_container * {
|
||||||
font-size:19px !important;
|
font-size:19px !important;
|
||||||
}
|
}
|
||||||
.centered_image_container form {
|
.centered_image_container form {
|
||||||
margin-bottom:0px;
|
margin-bottom:0px;
|
||||||
}
|
}
|
||||||
|
.brbanner {
|
||||||
|
padding:15px;
|
||||||
|
background-color:rgb(159, 226, 155);
|
||||||
|
text-align:center;
|
||||||
|
font-size:large;
|
||||||
|
}
|
||||||
+55
-9
@@ -37,17 +37,17 @@ body::-webkit-scrollbar {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
var topbuttons = document.querySelectorAll("button[form='views']");
|
var topbuttons = document.querySelectorAll("button[form='views']");
|
||||||
if(window.location.search.substr(1) != '') {
|
if(window.location.search.substr(1) != '') {
|
||||||
for (var i = 0; i < topbuttons.length; i++) {
|
for (var i = 0; i < topbuttons.length; i++) {
|
||||||
if(topbuttons[i].value == decodeURIComponent(window.location.search.substr(1)).replace(/\+/g,' ').split('=').pop()) {
|
if(topbuttons[i].value == decodeURIComponent(window.location.search.substr(1)).replace(/\+/g,' ').split('=').pop()) {
|
||||||
topbuttons[i].classList.add("button-hover");
|
topbuttons[i].classList.add("button-hover");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
topbuttons[0].classList.add("button-hover");
|
topbuttons[0].classList.add("button-hover");
|
||||||
}
|
}
|
||||||
function copyOutput(elem) {
|
function copyOutput(elem) {
|
||||||
elem.innerHTML = 'Copied!';
|
elem.innerHTML = 'Copied!';
|
||||||
const copyText = document.getElementsByTagName("pre")[0].textContent;
|
const copyText = document.getElementsByTagName("pre")[0].textContent;
|
||||||
const textArea = document.createElement('textarea');
|
const textArea = document.createElement('textarea');
|
||||||
@@ -57,7 +57,7 @@ body::-webkit-scrollbar {
|
|||||||
document.body.append(textArea);
|
document.body.append(textArea);
|
||||||
textArea.select();
|
textArea.select();
|
||||||
document.execCommand("copy");
|
document.execCommand("copy");
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="views">
|
<div class="views">
|
||||||
@@ -70,7 +70,7 @@ if(isset($_GET['view'])){
|
|||||||
if($_GET['view'] == "View Log"){echo "<body style=\"scroll:no;overflow-x:hidden;\"><iframe style=\"width:calc( 100% + 1em);\" src=\"/log\"></iframe></body>";}
|
if($_GET['view'] == "View Log"){echo "<body style=\"scroll:no;overflow-x:hidden;\"><iframe style=\"width:calc( 100% + 1em);\" src=\"/log\"></iframe></body>";}
|
||||||
if($_GET['view'] == "Overview"){include('overview.php');}
|
if($_GET['view'] == "Overview"){include('overview.php');}
|
||||||
if($_GET['view'] == "Today's Detections"){include('todays_detections.php');}
|
if($_GET['view'] == "Today's Detections"){include('todays_detections.php');}
|
||||||
if($_GET['view'] == "Species Stats"){echo "<br><br>";include('stats.php');}
|
if($_GET['view'] == "Species Stats"){include('stats.php');}
|
||||||
if($_GET['view'] == "Streamlit"){echo "<iframe src=\"/stats\"></iframe>";}
|
if($_GET['view'] == "Streamlit"){echo "<iframe src=\"/stats\"></iframe>";}
|
||||||
if($_GET['view'] == "Daily Charts"){include('history.php');}
|
if($_GET['view'] == "Daily Charts"){include('history.php');}
|
||||||
if($_GET['view'] == "Tools"){
|
if($_GET['view'] == "Tools"){
|
||||||
@@ -97,7 +97,7 @@ if(isset($_GET['view'])){
|
|||||||
<button type=\"submit\" name=\"view\" value=\"System Controls\" form=\"views\">System Controls</button>
|
<button type=\"submit\" name=\"view\" value=\"System Controls\" form=\"views\">System Controls</button>
|
||||||
<button type=\"submit\" name=\"view\" value=\"Services\" form=\"views\">Services</button>
|
<button type=\"submit\" name=\"view\" value=\"Services\" form=\"views\">Services</button>
|
||||||
<button type=\"submit\" name=\"view\" value=\"File\" form=\"views\">File Manager</button>
|
<button type=\"submit\" name=\"view\" value=\"File\" form=\"views\">File Manager</button>
|
||||||
<a href=\"scripts/adminer.php\" target=\"_top\"><button type=\"submit\" form=\"\">Database Maintenanace</button></a>
|
<a href=\"scripts/adminer.php\" target=\"_top\"><button type=\"submit\" form=\"\">Database Maintenance</button></a>
|
||||||
<button type=\"submit\" name=\"view\" value=\"Webterm\" form=\"views\">Web Terminal</button>
|
<button type=\"submit\" name=\"view\" value=\"Webterm\" form=\"views\">Web Terminal</button>
|
||||||
<button type=\"submit\" name=\"view\" value=\"Included\" form=\"views\">Custom Species List</button>
|
<button type=\"submit\" name=\"view\" value=\"Included\" form=\"views\">Custom Species List</button>
|
||||||
<button type=\"submit\" name=\"view\" value=\"Excluded\" form=\"views\">Excluded Species List</button>
|
<button type=\"submit\" name=\"view\" value=\"Excluded\" form=\"views\">Excluded Species List</button>
|
||||||
@@ -210,8 +210,54 @@ if(isset($_GET['view'])){
|
|||||||
} else {
|
} else {
|
||||||
$submittedpwd = $_SERVER['PHP_AUTH_PW'];
|
$submittedpwd = $_SERVER['PHP_AUTH_PW'];
|
||||||
$submitteduser = $_SERVER['PHP_AUTH_USER'];
|
$submitteduser = $_SERVER['PHP_AUTH_USER'];
|
||||||
if($submittedpwd == $caddypwd && $submitteduser == 'birdnet'){
|
$allowedCommands = array('sudo systemctl stop livestream.service && sudo /etc/init.d/icecast2 stop',
|
||||||
|
'sudo systemctl restart livestream.service && sudo /etc/init.d/icecast2 restart',
|
||||||
|
'sudo systemctl disable --now livestream.service && sudo systemctl disable icecast2 && sudo /etc/init.d/icecast2 stop',
|
||||||
|
'sudo systemctl enable icecast2 && sudo /etc/init.d/icecast2 start && sudo systemctl enable --now livestream.service',
|
||||||
|
'sudo systemctl stop web_terminal.service',
|
||||||
|
'sudo systemctl restart web_terminal.service',
|
||||||
|
'sudo systemctl disable --now web_terminal.service',
|
||||||
|
'sudo systemctl enable --now web_terminal.service',
|
||||||
|
'sudo systemctl stop birdnet_log.service',
|
||||||
|
'sudo systemctl restart birdnet_log.service',
|
||||||
|
'sudo systemctl disable --now birdnet_log.service',
|
||||||
|
'sudo systemctl enable --now birdnet_log.service',
|
||||||
|
'sudo systemctl stop extraction.service',
|
||||||
|
'sudo systemctl restart extraction.service',
|
||||||
|
'sudo systemctl disable --now extraction.service',
|
||||||
|
'sudo systemctl enable --now extraction.service',
|
||||||
|
'sudo systemctl stop birdnet_server.service',
|
||||||
|
'sudo systemctl restart birdnet_server.service',
|
||||||
|
'sudo systemctl disable --now birdnet_server.service',
|
||||||
|
'sudo systemctl enable --now birdnet_server.service',
|
||||||
|
'sudo systemctl stop birdnet_analysis.service',
|
||||||
|
'sudo systemctl restart birdnet_analysis.service',
|
||||||
|
'sudo systemctl disable --now birdnet_analysis.service',
|
||||||
|
'sudo systemctl enable --now birdnet_analysis.service',
|
||||||
|
'sudo systemctl stop birdnet_stats.service',
|
||||||
|
'sudo systemctl restart birdnet_stats.service',
|
||||||
|
'sudo systemctl disable --now birdnet_stats.service',
|
||||||
|
'sudo systemctl enable --now birdnet_stats.service',
|
||||||
|
'sudo systemctl stop birdnet_recording.service',
|
||||||
|
'sudo systemctl restart birdnet_recording.service',
|
||||||
|
'sudo systemctl disable --now birdnet_recording.service',
|
||||||
|
'sudo systemctl enable --now birdnet_recording.service',
|
||||||
|
'sudo systemctl stop chart_viewer.service',
|
||||||
|
'sudo systemctl restart chart_viewer.service',
|
||||||
|
'sudo systemctl disable --now chart_viewer.service',
|
||||||
|
'sudo systemctl enable --now chart_viewer.service',
|
||||||
|
'sudo systemctl stop spectrogram_viewer.service',
|
||||||
|
'sudo systemctl restart spectrogram_viewer.service',
|
||||||
|
'sudo systemctl disable --now spectrogram_viewer.service',
|
||||||
|
'sudo systemctl enable --now spectrogram_viewer.service',
|
||||||
|
'stop_core_services.sh',
|
||||||
|
'restart_services.sh',
|
||||||
|
'sudo reboot',
|
||||||
|
'update_birdnet.sh',
|
||||||
|
'sudo shutdown now',
|
||||||
|
'sudo clear_all_data.sh');
|
||||||
$command = $_GET['submit'];
|
$command = $_GET['submit'];
|
||||||
|
if($submittedpwd == $caddypwd && $submitteduser == 'birdnet' && in_array($command,$allowedCommands)){
|
||||||
if(isset($command)){
|
if(isset($command)){
|
||||||
$initcommand = $command;
|
$initcommand = $command;
|
||||||
if (strpos($command, "systemctl") !== false) {
|
if (strpos($command, "systemctl") !== false) {
|
||||||
|
|||||||
@@ -20,11 +20,13 @@ make_thisrun() {
|
|||||||
make_thisrun &> /dev/null
|
make_thisrun &> /dev/null
|
||||||
if ! diff ${LAST_RUN} ${THIS_RUN};then
|
if ! diff ${LAST_RUN} ${THIS_RUN};then
|
||||||
echo "The birdnet.conf file has changed"
|
echo "The birdnet.conf file has changed"
|
||||||
echo "Reloading services"
|
if grep REC <(diff $LAST_RUN $THIS_RUN);then
|
||||||
cat ${THIS_RUN} > ${LAST_RUN}
|
echo "Recording element changed -- restarting 'birdnet_recording.service'"
|
||||||
sudo systemctl stop birdnet_recording.service
|
sudo systemctl stop birdnet_recording.service
|
||||||
sudo rm -rf ${RECS_DIR}/$(date +%B-%Y/%d-%A)/*
|
sudo rm -rf ${RECS_DIR}/$(date +%B-%Y/%d-%A)/*
|
||||||
sudo systemctl start birdnet_recording.service
|
sudo systemctl start birdnet_recording.service
|
||||||
|
fi
|
||||||
|
cat ${THIS_RUN} > ${LAST_RUN}
|
||||||
fi
|
fi
|
||||||
|
|
||||||
INCLUDE_LIST="$HOME/BirdNET-Pi/include_species_list.txt"
|
INCLUDE_LIST="$HOME/BirdNET-Pi/include_species_list.txt"
|
||||||
|
|||||||
+8
-6
@@ -16,10 +16,10 @@ if(isset($_GET['apprise_notify_each_detection'])) {
|
|||||||
} else {
|
} else {
|
||||||
$apprise_notify_each_detection = 0;
|
$apprise_notify_each_detection = 0;
|
||||||
}
|
}
|
||||||
if(isset($_GET['apprise_notify_each_species'])) {
|
if(isset($_GET['apprise_notify_new_species'])) {
|
||||||
exec('sudo systemctl start pushed_notifications.service');
|
$apprise_notify_new_species = 1;
|
||||||
} else {
|
} else {
|
||||||
exec('sudo systemctl stop pushed_notifications.service');
|
$apprise_notify_new_species = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// logic for setting the date and time based on user inputs from the form below
|
// logic for setting the date and time based on user inputs from the form below
|
||||||
@@ -46,6 +46,7 @@ $contents = preg_replace("/BIRDWEATHER_ID=.*/", "BIRDWEATHER_ID=$birdweather_id"
|
|||||||
$contents = preg_replace("/APPRISE_NOTIFICATION_TITLE=.*/", "APPRISE_NOTIFICATION_TITLE=\"$apprise_notification_title\"", $contents);
|
$contents = preg_replace("/APPRISE_NOTIFICATION_TITLE=.*/", "APPRISE_NOTIFICATION_TITLE=\"$apprise_notification_title\"", $contents);
|
||||||
$contents = preg_replace("/APPRISE_NOTIFICATION_BODY=.*/", "APPRISE_NOTIFICATION_BODY=\"$apprise_notification_body\"", $contents);
|
$contents = preg_replace("/APPRISE_NOTIFICATION_BODY=.*/", "APPRISE_NOTIFICATION_BODY=\"$apprise_notification_body\"", $contents);
|
||||||
$contents = preg_replace("/APPRISE_NOTIFY_EACH_DETECTION=.*/", "APPRISE_NOTIFY_EACH_DETECTION=$apprise_notify_each_detection", $contents);
|
$contents = preg_replace("/APPRISE_NOTIFY_EACH_DETECTION=.*/", "APPRISE_NOTIFY_EACH_DETECTION=$apprise_notify_each_detection", $contents);
|
||||||
|
$contents = preg_replace("/APPRISE_NOTIFY_NEW_SPECIES=.*/", "APPRISE_NOTIFY_NEW_SPECIES=$apprise_notify_new_species", $contents);
|
||||||
$contents = preg_replace("/FLICKR_API_KEY=.*/", "FLICKR_API_KEY=$flickr_api_key", $contents);
|
$contents = preg_replace("/FLICKR_API_KEY=.*/", "FLICKR_API_KEY=$flickr_api_key", $contents);
|
||||||
|
|
||||||
|
|
||||||
@@ -56,6 +57,7 @@ $contents2 = preg_replace("/BIRDWEATHER_ID=.*/", "BIRDWEATHER_ID=$birdweather_id
|
|||||||
$contents2 = preg_replace("/APPRISE_NOTIFICATION_TITLE=.*/", "APPRISE_NOTIFICATION_TITLE=\"$apprise_notification_title\"", $contents2);
|
$contents2 = preg_replace("/APPRISE_NOTIFICATION_TITLE=.*/", "APPRISE_NOTIFICATION_TITLE=\"$apprise_notification_title\"", $contents2);
|
||||||
$contents2 = preg_replace("/APPRISE_NOTIFICATION_BODY=.*/", "APPRISE_NOTIFICATION_BODY=\"$apprise_notification_body\"", $contents2);
|
$contents2 = preg_replace("/APPRISE_NOTIFICATION_BODY=.*/", "APPRISE_NOTIFICATION_BODY=\"$apprise_notification_body\"", $contents2);
|
||||||
$contents2 = preg_replace("/APPRISE_NOTIFY_EACH_DETECTION=.*/", "APPRISE_NOTIFY_EACH_DETECTION=$apprise_notify_each_detection", $contents2);
|
$contents2 = preg_replace("/APPRISE_NOTIFY_EACH_DETECTION=.*/", "APPRISE_NOTIFY_EACH_DETECTION=$apprise_notify_each_detection", $contents2);
|
||||||
|
$contents2 = preg_replace("/APPRISE_NOTIFY_NEW_SPECIES=.*/", "APPRISE_NOTIFY_NEW_SPECIES=$apprise_notify_new_species", $contents2);
|
||||||
$contents2 = preg_replace("/FLICKR_API_KEY=.*/", "FLICKR_API_KEY=$flickr_api_key", $contents2);
|
$contents2 = preg_replace("/FLICKR_API_KEY=.*/", "FLICKR_API_KEY=$flickr_api_key", $contents2);
|
||||||
|
|
||||||
|
|
||||||
@@ -80,7 +82,7 @@ if ($language != "none"){
|
|||||||
$home = shell_exec("awk -F: '/1000/{print $6}' /etc/passwd");
|
$home = shell_exec("awk -F: '/1000/{print $6}' /etc/passwd");
|
||||||
$home = trim($home);
|
$home = trim($home);
|
||||||
$command = "sudo -u".$user." mv ".$home."/BirdNET-Pi/model/labels.txt ".$home."/BirdNET-Pi/model/labels.txt.old && sudo -u".$user." unzip ".$home."/BirdNET-Pi/model/labels_l18n.zip ".$language." -d ".$home."/BirdNET-Pi/model && sudo -u".$user." mv ".$home."/BirdNET-Pi/model/".$language." ".$home."/BirdNET-Pi/model/labels.txt";
|
$command = "sudo -u".$user." mv ".$home."/BirdNET-Pi/model/labels.txt ".$home."/BirdNET-Pi/model/labels.txt.old && sudo -u".$user." unzip ".$home."/BirdNET-Pi/model/labels_l18n.zip ".$language." -d ".$home."/BirdNET-Pi/model && sudo -u".$user." mv ".$home."/BirdNET-Pi/model/".$language." ".$home."/BirdNET-Pi/model/labels.txt";
|
||||||
$command_output = `sudo $command`;
|
$command_output = `$command`;
|
||||||
`sudo restart_services.sh`;
|
`sudo restart_services.sh`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -144,8 +146,8 @@ https://discordapp.com/api/webhooks/{WebhookID}/{WebhookToken}
|
|||||||
<input name="apprise_notification_title" type="text" value="<?php print($config['APPRISE_NOTIFICATION_TITLE']);?>" /><br>
|
<input name="apprise_notification_title" type="text" value="<?php print($config['APPRISE_NOTIFICATION_TITLE']);?>" /><br>
|
||||||
<label for="apprise_notification_body">Notification Body (use variables $sciname, $comname, or $confidence): </label>
|
<label for="apprise_notification_body">Notification Body (use variables $sciname, $comname, or $confidence): </label>
|
||||||
<input name="apprise_notification_body" type="text" value="<?php print($config['APPRISE_NOTIFICATION_BODY']);?>" /><br>
|
<input name="apprise_notification_body" type="text" value="<?php print($config['APPRISE_NOTIFICATION_BODY']);?>" /><br>
|
||||||
<input type="checkbox" name="apprise_notify_each_species" <?php $output = shell_exec("service pushed_notifications status"); if (!strpos($output, 'dead') !== false && filesize($home."/BirdNET-Pi/apprise.txt") != 0) { echo "checked"; } ?>>
|
<input type="checkbox" name="apprise_notify_new_species" <?php if($config['APPRISE_NOTIFY_NEW_SPECIES'] == 1 && filesize($home."/BirdNET-Pi/apprise.txt") != 0) { echo "checked"; };?> >
|
||||||
<label for="apprise_notify_each_species">Notify each new species</label><br>
|
<label for="apprise_notify_new_species">Notify each new species</label><br>
|
||||||
<input type="checkbox" name="apprise_notify_each_detection" <?php if($config['APPRISE_NOTIFY_EACH_DETECTION'] == 1 && filesize($home."/BirdNET-Pi/apprise.txt") != 0) { echo "checked"; };?> >
|
<input type="checkbox" name="apprise_notify_each_detection" <?php if($config['APPRISE_NOTIFY_EACH_DETECTION'] == 1 && filesize($home."/BirdNET-Pi/apprise.txt") != 0) { echo "checked"; };?> >
|
||||||
<label for="apprise_notify_each_detection">Notify each new detection</label><br><br>
|
<label for="apprise_notify_each_detection">Notify each new detection</label><br><br>
|
||||||
<h3>Bird Photos from Flickr</h3>
|
<h3>Bird Photos from Flickr</h3>
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ df['Hour of Day'] = [r.hour for r in df.Time]
|
|||||||
df_plt=df #Default to use the whole Dbase
|
df_plt=df #Default to use the whole Dbase
|
||||||
|
|
||||||
# Add every font at the specified location
|
# Add every font at the specified location
|
||||||
font_dir = ['$HOME/BirdNET-Pi/homepage/static']
|
font_dir = [userDir+'/BirdNET-Pi/homepage/static']
|
||||||
for font in font_manager.findSystemFonts(font_dir):
|
for font in font_manager.findSystemFonts(font_dir):
|
||||||
font_manager.fontManager.addfont(font)
|
font_manager.fontManager.addfont(font)
|
||||||
|
|
||||||
|
|||||||
@@ -73,7 +73,8 @@ RTSP_STREAM=
|
|||||||
|
|
||||||
APPRISE_NOTIFICATION_TITLE="New BirdNET-Pi Detection"
|
APPRISE_NOTIFICATION_TITLE="New BirdNET-Pi Detection"
|
||||||
APPRISE_NOTIFICATION_BODY="A \$sciname \$comname was just detected with a confidence of \$confidence"
|
APPRISE_NOTIFICATION_BODY="A \$sciname \$comname was just detected with a confidence of \$confidence"
|
||||||
APPRISE_NOTIFY_EACH_DETECTION=false
|
APPRISE_NOTIFY_EACH_DETECTION=0
|
||||||
|
APPRISE_NOTIFY_NEW_SPECIES=0
|
||||||
|
|
||||||
#---------------------- Flickr Images API Configuration -----------------------#
|
#---------------------- Flickr Images API Configuration -----------------------#
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export PYTHON_VIRTUAL_ENV="$HOME/BirdNET-Pi/birdnet/bin/python3"
|
|||||||
|
|
||||||
install_depends() {
|
install_depends() {
|
||||||
apt install -y debian-keyring debian-archive-keyring apt-transport-https
|
apt install -y debian-keyring debian-archive-keyring apt-transport-https
|
||||||
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo tee /etc/apt/trusted.gpg.d/caddy-stable.asc
|
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
|
||||||
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
|
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
|
||||||
apt -qqq update && apt -qqy upgrade
|
apt -qqq update && apt -qqy upgrade
|
||||||
echo "icecast2 icecast2/icecast-setup boolean false" | debconf-set-selections
|
echo "icecast2 icecast2/icecast-setup boolean false" | debconf-set-selections
|
||||||
@@ -93,22 +93,6 @@ EOF
|
|||||||
systemctl enable extraction.service
|
systemctl enable extraction.service
|
||||||
}
|
}
|
||||||
|
|
||||||
install_pushed_notifications() {
|
|
||||||
cat << EOF > $HOME/BirdNET-Pi/templates/pushed_notifications.service
|
|
||||||
[Unit]
|
|
||||||
Description=BirdNET-Pi Pushed.co Notifications
|
|
||||||
[Service]
|
|
||||||
Restart=on-success
|
|
||||||
RestartSec=3
|
|
||||||
Type=simple
|
|
||||||
User=$USER
|
|
||||||
ExecStart=/usr/local/bin/species_notifier.sh
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
EOF
|
|
||||||
ln -sf $HOME/BirdNET-Pi/templates/pushed_notifications.service /usr/lib/systemd/system
|
|
||||||
}
|
|
||||||
|
|
||||||
create_necessary_dirs() {
|
create_necessary_dirs() {
|
||||||
echo "Creating necessary directories"
|
echo "Creating necessary directories"
|
||||||
[ -d ${EXTRACTED} ] || sudo -u ${USER} mkdir -p ${EXTRACTED}
|
[ -d ${EXTRACTED} ] || sudo -u ${USER} mkdir -p ${EXTRACTED}
|
||||||
@@ -438,7 +422,6 @@ install_services() {
|
|||||||
install_recording_service
|
install_recording_service
|
||||||
install_custom_recording_service # But does not enable
|
install_custom_recording_service # But does not enable
|
||||||
install_extraction_service
|
install_extraction_service
|
||||||
install_pushed_notifications
|
|
||||||
install_spectrogram_service
|
install_spectrogram_service
|
||||||
install_chart_viewer_service
|
install_chart_viewer_service
|
||||||
install_gotty_logs
|
install_gotty_logs
|
||||||
|
|||||||
+13
-7
@@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
ini_set('session.gc_maxlifetime', 7200);
|
||||||
|
session_set_cookie_params(7200);
|
||||||
|
session_start();
|
||||||
$myDate = date('Y-m-d');
|
$myDate = date('Y-m-d');
|
||||||
$chart = "Combo-$myDate.png";
|
$chart = "Combo-$myDate.png";
|
||||||
|
|
||||||
@@ -22,7 +25,9 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" && isse
|
|||||||
header("refresh: 0;");
|
header("refresh: 0;");
|
||||||
}
|
}
|
||||||
$result4 = $statement4->execute();
|
$result4 = $statement4->execute();
|
||||||
$images = [];
|
if(!isset($_SESSION['images'])) {
|
||||||
|
$_SESSION['images'] = [];
|
||||||
|
}
|
||||||
$iterations = 0;
|
$iterations = 0;
|
||||||
// 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
|
// 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
|
||||||
while($mostrecent = $result4->fetchArray(SQLITE3_ASSOC)) {
|
while($mostrecent = $result4->fetchArray(SQLITE3_ASSOC)) {
|
||||||
@@ -45,19 +50,20 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" && isse
|
|||||||
// we've found our valid detection! ignore everything else from the database loop
|
// we've found our valid detection! ignore everything else from the database loop
|
||||||
if(strpos($headers[0],'200')) {
|
if(strpos($headers[0],'200')) {
|
||||||
if($_GET['previous_detection_identifier'] == $filename) { die(); }
|
if($_GET['previous_detection_identifier'] == $filename) { die(); }
|
||||||
|
if($_GET['only_name'] == "true") { echo $comname.",".$filename;die(); }
|
||||||
|
|
||||||
if (!empty($config["FLICKR_API_KEY"])) {
|
if (!empty($config["FLICKR_API_KEY"])) {
|
||||||
// if we already searched flickr for this species before, use the previous image rather than doing an unneccesary api call
|
// if we already searched flickr for this species before, use the previous image rather than doing an unneccesary api call
|
||||||
$key = array_search($comname, array_column($images, 0));
|
$key = array_search($comname, array_column($_SESSION['images'], 0));
|
||||||
if($key !== false) {
|
if($key !== false) {
|
||||||
$image = $images[$key];
|
$image = $_SESSION['images'][$key];
|
||||||
} else {
|
} else {
|
||||||
$flickrjson = json_decode(file_get_contents("https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key=".$config["FLICKR_API_KEY"]."&text=".str_replace("_", "%20", $comname)."&license=2%2C3%2C4%2C5%2C6%2C9&sort=relevance&per_page=5&orientation=square,portrait&format=json&media=photos&nojsoncallback=1"), true)["photos"]["photo"][0];
|
$flickrjson = json_decode(file_get_contents("https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key=".$config["FLICKR_API_KEY"]."&text=".str_replace("_", "%20", $comname)."&license=2%2C3%2C4%2C5%2C6%2C9&sort=relevance&per_page=5&orientation=square,portrait&format=json&media=photos&nojsoncallback=1"), true)["photos"]["photo"][0];
|
||||||
$modaltext = "https://flickr.com/photos/".$flickrjson["owner"]."/".$flickrjson["id"];
|
$modaltext = "https://flickr.com/photos/".$flickrjson["owner"]."/".$flickrjson["id"];
|
||||||
$authorlink = "https://flickr.com/people/".$flickrjson["owner"];
|
$authorlink = "https://flickr.com/people/".$flickrjson["owner"];
|
||||||
$imageurl = 'http://farm' .$flickrjson["farm"]. '.static.flickr.com/' .$flickrjson["server"]. '/' .$flickrjson["id"]. '_' .$flickrjson["secret"]. '.jpg';
|
$imageurl = 'https://farm' .$flickrjson["farm"]. '.static.flickr.com/' .$flickrjson["server"]. '/' .$flickrjson["id"]. '_' .$flickrjson["secret"]. '.jpg';
|
||||||
array_push($images, array($comname,$imageurl,$flickrjson["title"], $modaltext, $authorlink));
|
array_push($_SESSION['images'], array($comname,$imageurl,$flickrjson["title"], $modaltext, $authorlink));
|
||||||
$image = $images[count($images)-1];
|
$image = $_SESSION['images'][count($_SESSION['images'])-1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,7 +244,7 @@ function loadDetectionIfNewExists(previous_detection_identifier=undefined) {
|
|||||||
const xhttp = new XMLHttpRequest();
|
const xhttp = new XMLHttpRequest();
|
||||||
xhttp.onload = function() {
|
xhttp.onload = function() {
|
||||||
// if there's a new detection that needs to be updated to the page
|
// if there's a new detection that needs to be updated to the page
|
||||||
if(this.responseText.length > 0 && !this.responseText.includes("Database is busy.")) {
|
if(this.responseText.length > 0 && !this.responseText.includes("Database is busy")) {
|
||||||
document.getElementById("most_recent_detection").innerHTML = this.responseText;
|
document.getElementById("most_recent_detection").innerHTML = this.responseText;
|
||||||
|
|
||||||
// only going to load left chart if there's a new detection
|
// only going to load left chart if there's a new detection
|
||||||
|
|||||||
+5
-7
@@ -1,7 +1,5 @@
|
|||||||
<?php
|
<?php
|
||||||
ini_set('display_errors', 1);
|
error_reporting(E_ERROR);
|
||||||
ini_set('display_startup_errors', 1);
|
|
||||||
error_reporting(E_ALL);
|
|
||||||
|
|
||||||
$db = new SQLite3('./scripts/birds.db', SQLITE3_OPEN_CREATE | SQLITE3_OPEN_READWRITE);
|
$db = new SQLite3('./scripts/birds.db', SQLITE3_OPEN_CREATE | SQLITE3_OPEN_READWRITE);
|
||||||
if($db == False){
|
if($db == False){
|
||||||
@@ -170,10 +168,10 @@ if(!isset($_GET['species']) && !isset($_GET['filename'])){
|
|||||||
<input type="hidden" name="view" value="Recordings">
|
<input type="hidden" name="view" value="Recordings">
|
||||||
<input type="hidden" name="<?php echo $view; ?>" value="<?php echo $_GET['date']; ?>">
|
<input type="hidden" name="<?php echo $view; ?>" value="<?php echo $_GET['date']; ?>">
|
||||||
<button <?php if(!isset($_GET['sort']) || $_GET['sort'] == "alphabetical"){ echo "style='background:#9fe29b !important;'"; }?> class="sortbutton" type="submit" name="sort" value="alphabetical">
|
<button <?php if(!isset($_GET['sort']) || $_GET['sort'] == "alphabetical"){ echo "style='background:#9fe29b !important;'"; }?> class="sortbutton" type="submit" name="sort" value="alphabetical">
|
||||||
<img src="images/sort_abc.svg" alt="Sort by alphabetical">
|
<img src="images/sort_abc.svg" title="Sort by alphabetical" alt="Sort by alphabetical">
|
||||||
</button>
|
</button>
|
||||||
<button <?php if(isset($_GET['sort']) && $_GET['sort'] == "occurrences"){ echo "style='background:#9fe29b !important;'"; }?> class="sortbutton" type="submit" name="sort" value="occurrences">
|
<button <?php if(isset($_GET['sort']) && $_GET['sort'] == "occurrences"){ echo "style='background:#9fe29b !important;'"; }?> class="sortbutton" type="submit" name="sort" value="occurrences">
|
||||||
<img src="images/sort_occ.svg" alt="Sort by occurrences">
|
<img src="images/sort_occ.svg" title="Sort by occurrences" alt="Sort by occurrences">
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -230,10 +228,10 @@ if(isset($_GET['species'])){ ?>
|
|||||||
<input type="hidden" name="view" value="Recordings">
|
<input type="hidden" name="view" value="Recordings">
|
||||||
<input type="hidden" name="species" value="<?php echo $_GET['species']; ?>">
|
<input type="hidden" name="species" value="<?php echo $_GET['species']; ?>">
|
||||||
<button <?php if(!isset($_GET['sort']) || $_GET['sort'] == "date"){ echo "style='background:#9fe29b !important;'"; }?> class="sortbutton" type="submit" name="sort" value="date">
|
<button <?php if(!isset($_GET['sort']) || $_GET['sort'] == "date"){ echo "style='background:#9fe29b !important;'"; }?> class="sortbutton" type="submit" name="sort" value="date">
|
||||||
<img width=35px src="images/sort_date.svg" alt="Sort by date">
|
<img width=35px src="images/sort_date.svg" title="Sort by date" alt="Sort by date">
|
||||||
</button>
|
</button>
|
||||||
<button <?php if(isset($_GET['sort']) && $_GET['sort'] == "confidence"){ echo "style='background:#9fe29b !important;'"; }?> class="sortbutton" type="submit" name="sort" value="confidence">
|
<button <?php if(isset($_GET['sort']) && $_GET['sort'] == "confidence"){ echo "style='background:#9fe29b !important;'"; }?> class="sortbutton" type="submit" name="sort" value="confidence">
|
||||||
<img src="images/sort_occ.svg" alt="Sort by confidence">
|
<img src="images/sort_occ.svg" title="Sort by confidence" alt="Sort by confidence">
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+30
-23
@@ -8,6 +8,7 @@ from datetime import timedelta, datetime
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import sqlite3
|
import sqlite3
|
||||||
from sqlite3 import Connection
|
from sqlite3 import Connection
|
||||||
|
import plotly.express as px
|
||||||
|
|
||||||
userDir = os.path.expanduser('~')
|
userDir = os.path.expanduser('~')
|
||||||
URI_SQLITE_DB = userDir + '/BirdNET-Pi/scripts/birds.db'
|
URI_SQLITE_DB = userDir + '/BirdNET-Pi/scripts/birds.db'
|
||||||
@@ -122,42 +123,43 @@ filt=df2['Com_Name']==specie
|
|||||||
|
|
||||||
df_counts=sum(df5==specie)
|
df_counts=sum(df5==specie)
|
||||||
|
|
||||||
fig = make_subplots(
|
|
||||||
|
|
||||||
|
|
||||||
|
if resample_time != '1D':
|
||||||
|
fig = make_subplots(
|
||||||
rows=3, cols =2,
|
rows=3, cols =2,
|
||||||
specs= [[{"type":"xy","rowspan":3}, {"type":"polar","rowspan":2}], [{"rowspan":1}, {"rowspan":1} ], [None, {"type":"xy","rowspan":1}]],
|
specs= [[{"type":"xy","rowspan":3}, {"type":"polar","rowspan":2}], [{"rowspan":1}, {"rowspan":1} ], [None, {"type":"xy","rowspan":1}]],
|
||||||
subplot_titles=('<b>Top '+ str(top_N) + ' Species in Date Range '+str(Date_Slider[0])+' to '+str(Date_Slider[1])+'</b>',
|
subplot_titles=('<b>Top '+ str(top_N) + ' Species in Date Range '+str(Date_Slider[0])+' to '+str(Date_Slider[1])+' for '+str(resample_sel)+' sampling interval.'+'</b>',
|
||||||
'Total Detect:'+str('{:,}'.format(df_counts))+
|
'Total Detect:'+str('{:,}'.format(df_counts))+
|
||||||
' Confidence Max:'+str('{:.2f}%'.format(max(df2[df2['Com_Name']==specie]['Confidence'])*100))+
|
' Confidence Max:'+str('{:.2f}%'.format(max(df2[df2['Com_Name']==specie]['Confidence'])*100))+
|
||||||
' '+' Median:'+str('{:.2f}%'.format(np.median(df2[df2['Com_Name']==specie]['Confidence'])*100))
|
' '+' Median:'+str('{:.2f}%'.format(np.median(df2[df2['Com_Name']==specie]['Confidence'])*100))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
fig.layout.annotations[1].update(x=0.7,y=0.25, font_size=15)
|
fig.layout.annotations[1].update(x=0.7,y=0.25, font_size=15)
|
||||||
|
|
||||||
#Plot seen species for selected date range and number of species
|
#Plot seen species for selected date range and number of species
|
||||||
fig.add_trace(go.Bar(y=top_N_species.index, x=top_N_species, orientation='h'), row=1,col=1)
|
fig.add_trace(go.Bar(y=top_N_species.index, x=top_N_species, orientation='h'), row=1,col=1)
|
||||||
|
|
||||||
fig.update_layout(
|
fig.update_layout(
|
||||||
margin=dict(l=0, r=0, t=50, b=0),
|
margin=dict(l=0, r=0, t=50, b=0),
|
||||||
yaxis={'categoryorder':'total ascending'})
|
yaxis={'categoryorder':'total ascending'})
|
||||||
|
|
||||||
|
|
||||||
# Set 360 degrees, 24 hours for polar plot
|
# Set 360 degrees, 24 hours for polar plot
|
||||||
theta = np.linspace(0.0, 360, 24, endpoint=False)
|
theta = np.linspace(0.0, 360, 24, endpoint=False)
|
||||||
|
|
||||||
specie_filt= df5==specie
|
specie_filt= df5==specie
|
||||||
df3=df5[specie_filt]
|
df3=df5[specie_filt]
|
||||||
|
|
||||||
detections2= pd.crosstab(df3, df3.index.hour)
|
detections2= pd.crosstab(df3, df3.index.hour)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
d=pd.DataFrame(np.zeros((23,1))).squeeze()
|
d=pd.DataFrame(np.zeros((23,1))).squeeze()
|
||||||
detections = hourly.loc[specie]
|
detections = hourly.loc[specie]
|
||||||
detections=(d+detections).fillna(0)
|
detections=(d+detections).fillna(0)
|
||||||
|
|
||||||
|
|
||||||
if resample_time != '1D':
|
|
||||||
fig.add_trace(go.Barpolar(r = detections, theta=theta), row=1, col=2)
|
fig.add_trace(go.Barpolar(r = detections, theta=theta), row=1, col=2)
|
||||||
fig.update_layout(
|
fig.update_layout(
|
||||||
autosize=False,
|
autosize=False,
|
||||||
@@ -191,15 +193,18 @@ if resample_time != '1D':
|
|||||||
else:
|
else:
|
||||||
fig = make_subplots(
|
fig = make_subplots(
|
||||||
rows=1, cols =2,
|
rows=1, cols =2,
|
||||||
# specs= [[{"type":"xy","rowspan":1}],
|
specs= [[{"type":"xy","rowspan":1},{"type":"xy","rowspan":1}]],
|
||||||
# [{"rowspan":1}],
|
|
||||||
# ],
|
|
||||||
# subplot_titles=('<b>Top '+ str(top_N) + ' Species in Date Range '+str(Date_Slider[0])+' to '+str(Date_Slider[1])+'</b>',
|
subplot_titles=('<b>Daily Top '+ str(top_N) + ' Species in Date Range '+str(Date_Slider[0])+' to '+str(Date_Slider[1])+'</b>',
|
||||||
|
'<b>Daily ' + specie+ ' Detections on 15 minute intervals </b>'),
|
||||||
# 'Total Detect:'+str('{:,}'.format(df_counts))+
|
# 'Total Detect:'+str('{:,}'.format(df_counts))+
|
||||||
# ' Confidence Max:'+str('{:.2f}%'.format(max(df2[df2['Com_Name']==specie]['Confidence'])*100))+
|
# ' Confidence Max:'+str('{:.2f}%'.format(max(df2[df2['Com_Name']==specie]['Confidence'])*100))+
|
||||||
# ' '+' Median:'+str('{:.2f}%'.format(np.median(df2[df2['Com_Name']==specie]['Confidence'])*100))
|
# ' '+' Median:'+str('{:.2f}%'.format(np.median(df2[df2['Com_Name']==specie]['Confidence'])*100))
|
||||||
# )
|
# )
|
||||||
)
|
)
|
||||||
|
|
||||||
|
fig.add_trace(go.Bar(y=top_N_species.index, x=top_N_species, orientation='h'), row=1,col=1)
|
||||||
df4=df2['Com_Name'][df2['Com_Name']==specie].resample('15min').count()
|
df4=df2['Com_Name'][df2['Com_Name']==specie].resample('15min').count()
|
||||||
df4.index=[df4.index.date, df4.index.time]
|
df4.index=[df4.index.date, df4.index.time]
|
||||||
day_hour_freq=df4.unstack().fillna(0)
|
day_hour_freq=df4.unstack().fillna(0)
|
||||||
@@ -208,11 +213,13 @@ else:
|
|||||||
fig_y = [h.strftime('%H:%M') for h in day_hour_freq.columns.tolist()]
|
fig_y = [h.strftime('%H:%M') for h in day_hour_freq.columns.tolist()]
|
||||||
fig_z = day_hour_freq.values.transpose()
|
fig_z = day_hour_freq.values.transpose()
|
||||||
fig_heatmap = go.Figure(data=go.Heatmap(x=fig_x,y=fig_y,z=fig_z))
|
fig_heatmap = go.Figure(data=go.Heatmap(x=fig_x,y=fig_y,z=fig_z))
|
||||||
fig.add_trace(go.Bar(y=top_N_species.index, x=top_N_species, orientation='h'), row=1,col=1)
|
|
||||||
fig.update_layout(
|
fig.update_layout(
|
||||||
margin=dict(l=0, r=0, t=50, b=0),
|
margin=dict(l=0, r=0, t=50, b=0),
|
||||||
yaxis={'categoryorder':'total ascending'})
|
yaxis={'categoryorder':'total ascending'})
|
||||||
fig.add_trace(go.Heatmap(x=fig_x,y=fig_y,z=fig_z, autocolorscale = False, colorscale = 'blackbody'), row=1, col=2)
|
color_pals= px.colors.named_colorscales()
|
||||||
|
selected_pal = cols2.selectbox('Select Color Pallet for Daily Detections', color_pals)
|
||||||
|
fig.add_trace(go.Heatmap(x=fig_x,y=fig_y,z=fig_z, autocolorscale = False, colorscale = selected_pal), row=1, col=2)
|
||||||
# container=st.container()
|
# container=st.container()
|
||||||
# config={'displayModelBar': False}
|
# config={'displayModelBar': False}
|
||||||
st.plotly_chart(fig, use_container_width=True) #, config=config)
|
st.plotly_chart(fig, use_container_width=True) #, config=config)
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ sudo pkill server.py
|
|||||||
sudo systemctl stop birdnet_recording.service
|
sudo systemctl stop birdnet_recording.service
|
||||||
services=(web_terminal.service
|
services=(web_terminal.service
|
||||||
spectrogram_viewer.service
|
spectrogram_viewer.service
|
||||||
pushed_notifications.service
|
|
||||||
livestream.service
|
livestream.service
|
||||||
icecast2.service
|
icecast2.service
|
||||||
extraction.service
|
extraction.service
|
||||||
@@ -22,6 +21,6 @@ sudo systemctl restart "${i}"
|
|||||||
done
|
done
|
||||||
until grep 5050 <(netstat -tulpn 2>&1);do
|
until grep 5050 <(netstat -tulpn 2>&1);do
|
||||||
sudo systemctl restart birdnet_server.service
|
sudo systemctl restart birdnet_server.service
|
||||||
sleep 30
|
sleep 45
|
||||||
done
|
done
|
||||||
sudo systemctl restart birdnet_analysis.service
|
sudo systemctl restart birdnet_analysis.service
|
||||||
|
|||||||
@@ -243,6 +243,33 @@ def sendAppriseNotifications(species,confidence):
|
|||||||
title=title,
|
title=title,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if str(str(str([i for i in this_run if i.startswith('APPRISE_NOTIFY_NEW_SPECIES')]).split('=')[1]).split('\\')[0]) == "1":
|
||||||
|
try:
|
||||||
|
con = sqlite3.connect(userDir + '/BirdNET-Pi/scripts/birds.db')
|
||||||
|
con.row_factory = lambda cursor, row: row[0]
|
||||||
|
cur = con.cursor()
|
||||||
|
cur.execute("SELECT DISTINCT(Com_Name) FROM detections")
|
||||||
|
known_species = cur.fetchall()
|
||||||
|
sciName,comName = species.split("_")
|
||||||
|
|
||||||
|
print("\ncomName: ",comName)
|
||||||
|
print("\nknown_species: ",known_species)
|
||||||
|
if comName not in known_species:
|
||||||
|
apobj = apprise.Apprise()
|
||||||
|
config = apprise.AppriseConfig()
|
||||||
|
config.add(userDir + '/BirdNET-Pi/apprise.txt')
|
||||||
|
apobj.add(config)
|
||||||
|
|
||||||
|
apobj.notify(
|
||||||
|
body=body.replace("$sciname",species.split("_")[0]).replace("$comname",species.split("_")[1]).replace("$confidence",confidence),
|
||||||
|
title=title,
|
||||||
|
)
|
||||||
|
|
||||||
|
con.close()
|
||||||
|
except:
|
||||||
|
print("Database busy")
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
def writeResultsToFile(detections, min_conf, path):
|
def writeResultsToFile(detections, min_conf, path):
|
||||||
|
|
||||||
print('WRITING RESULTS TO', path, '...', end=' ')
|
print('WRITING RESULTS TO', path, '...', end=' ')
|
||||||
|
|||||||
@@ -73,13 +73,6 @@
|
|||||||
<button type="submit" name="submit" value="sudo systemctl disable --now spectrogram_viewer.service">Disable</button>
|
<button type="submit" name="submit" value="sudo systemctl disable --now spectrogram_viewer.service">Disable</button>
|
||||||
<button type="submit" name="submit" value="sudo systemctl enable --now spectrogram_viewer.service">Enable</button>
|
<button type="submit" name="submit" value="sudo systemctl enable --now spectrogram_viewer.service">Enable</button>
|
||||||
</form>
|
</form>
|
||||||
<form action="" method="GET">
|
|
||||||
<h3>Pushed Notifications</h3>
|
|
||||||
<button type="submit" name="submit" value="sudo systemctl stop pushed_notifications.service">Stop</button>
|
|
||||||
<button type="submit" name="submit" value="sudo systemctl restart pushed_notifications.service">Restart</button>
|
|
||||||
<button type="submit" name="submit" value="sudo systemctl disable --now pushed_notifications.service">Disable</button>
|
|
||||||
<button type="submit" name="submit" value="sudo systemctl enable --now pushed_notifications.service">Enable</button>
|
|
||||||
</form>
|
|
||||||
<form action="" method="GET">
|
<form action="" method="GET">
|
||||||
<button type="submit" name="submit" value="stop_core_services.sh">Stop Core Services</button>
|
<button type="submit" name="submit" value="stop_core_services.sh">Stop Core Services</button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
+81
-6
@@ -4,16 +4,89 @@
|
|||||||
// UPDATE: there is a problem in chrome with starting audio context
|
// UPDATE: there is a problem in chrome with starting audio context
|
||||||
// before a user gesture. This fixes it.
|
// before a user gesture. This fixes it.
|
||||||
var started = null;
|
var started = null;
|
||||||
|
var player = null;
|
||||||
|
const ctx = null;
|
||||||
window.onload = function(){
|
window.onload = function(){
|
||||||
|
// if user agent includes iPhone or Mac use legacy mode
|
||||||
|
if(window.navigator.userAgent.includes("iPhone") || window.navigator.userAgent.includes("Mac")) {
|
||||||
|
document.getElementById("spectrogramimage").style.display="";
|
||||||
|
document.body.querySelector('canvas').remove();
|
||||||
|
document.getElementById('player').remove();
|
||||||
|
document.body.querySelector('h1').remove();
|
||||||
|
|
||||||
|
<?php
|
||||||
|
if (file_exists('./scripts/thisrun.txt')) {
|
||||||
|
$config = parse_ini_file('./scripts/thisrun.txt');
|
||||||
|
} elseif (file_exists('./scripts/firstrun.ini')) {
|
||||||
|
$config = parse_ini_file('./scripts/firstrun.ini');
|
||||||
|
}
|
||||||
|
$refresh = $config['RECORDING_LENGTH'];
|
||||||
|
$time = time();
|
||||||
|
?>
|
||||||
|
// every $refresh seconds, this loop will run and refresh the spectrogram image
|
||||||
|
window.setInterval(function(){
|
||||||
|
document.getElementById("spectrogramimage").src = "/spectrogram.png?nocache="+Date.now();
|
||||||
|
}, <?php echo $refresh; ?>*1000);
|
||||||
|
} else {
|
||||||
|
document.getElementById("spectrogramimage").remove();
|
||||||
|
|
||||||
|
var audioelement = window.parent.document.getElementsByTagName("audio")[0];
|
||||||
|
if (typeof(audioelement) != 'undefined') {
|
||||||
|
|
||||||
|
document.getElementById('player').remove();
|
||||||
|
|
||||||
|
player = audioelement;
|
||||||
|
} else {
|
||||||
|
player = document.getElementById('player');
|
||||||
|
}
|
||||||
|
player.play();
|
||||||
if (started) return;
|
if (started) return;
|
||||||
started = true;
|
started = true;
|
||||||
initialize();
|
initialize();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function fitTextOnCanvas(text,fontface,yPosition){
|
||||||
|
var fontsize=300;
|
||||||
|
do{
|
||||||
|
fontsize--;
|
||||||
|
CTX.font=fontsize+"px "+fontface;
|
||||||
|
}while(CTX.measureText(text).width>document.body.querySelector('canvas').width)
|
||||||
|
CTX.font = CTX.font=(fontsize*0.35)+"px "+fontface;
|
||||||
|
CTX.fillText(text,document.body.querySelector('canvas').width - (document.body.querySelector('canvas').width * 0.50),yPosition);
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyText(text) {
|
||||||
|
CTX.fillStyle = 'white';
|
||||||
|
CTX.font = '25px Roboto Flex';
|
||||||
|
fitTextOnCanvas(text,"Roboto Flex",document.body.querySelector('canvas').scrollHeight * 0.35)
|
||||||
|
CTX.fillStyle = 'hsl(280, 100%, 10%)';
|
||||||
|
}
|
||||||
|
|
||||||
|
var previous_detection_identifier = null;
|
||||||
|
function loadDetectionIfNewExists() {
|
||||||
|
const xhttp = new XMLHttpRequest();
|
||||||
|
xhttp.onload = function() {
|
||||||
|
// if there's a new detection that needs to be updated to the page
|
||||||
|
if(this.responseText.length > 0 && !this.responseText.includes("Database")) {
|
||||||
|
if(previous_detection_identifier != null){
|
||||||
|
applyText(this.responseText.split(",")[0].replace("_"," "));
|
||||||
|
}
|
||||||
|
previous_detection_identifier = this.responseText.split(",")[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
xhttp.open("GET", "overview.php?ajax_detections=true&previous_detection_identifier="+previous_detection_identifier+"&only_name=true", true);
|
||||||
|
xhttp.send();
|
||||||
|
}
|
||||||
|
|
||||||
|
window.setInterval(function(){
|
||||||
|
loadDetectionIfNewExists();
|
||||||
|
}, 2500);
|
||||||
|
|
||||||
function initialize() {
|
function initialize() {
|
||||||
document.body.querySelector('h1').remove();
|
document.body.querySelector('h1').remove();
|
||||||
const CVS = document.body.querySelector('canvas');
|
const CVS = document.body.querySelector('canvas');
|
||||||
const CTX = CVS.getContext('2d');
|
CTX = CVS.getContext('2d');
|
||||||
const W = CVS.width = window.innerWidth;
|
const W = CVS.width = window.innerWidth;
|
||||||
const H = CVS.height = window.innerHeight;
|
const H = CVS.height = window.innerHeight;
|
||||||
|
|
||||||
@@ -25,12 +98,12 @@ function initialize() {
|
|||||||
process();
|
process();
|
||||||
|
|
||||||
function process() {
|
function process() {
|
||||||
const SOURCE = ACTX.createMediaElementSource(document.getElementById('player'));
|
const SOURCE = ACTX.createMediaElementSource(player);
|
||||||
SOURCE.connect(ANALYSER);
|
SOURCE.connect(ANALYSER);
|
||||||
SOURCE.connect(ACTX.destination)
|
SOURCE.connect(ACTX.destination)
|
||||||
const DATA = new Uint8Array(ANALYSER.frequencyBinCount);
|
const DATA = new Uint8Array(ANALYSER.frequencyBinCount);
|
||||||
const LEN = DATA.length;
|
const LEN = DATA.length;
|
||||||
const h = H / LEN;
|
const h = (H / LEN + 0.9);
|
||||||
const x = W - 1;
|
const x = W - 1;
|
||||||
CTX.fillStyle = 'hsl(280, 100%, 10%)';
|
CTX.fillStyle = 'hsl(280, 100%, 10%)';
|
||||||
CTX.fillRect(0, 0, W, H);
|
CTX.fillRect(0, 0, W, H);
|
||||||
@@ -40,11 +113,12 @@ function initialize() {
|
|||||||
function loop() {
|
function loop() {
|
||||||
window.requestAnimationFrame(loop);
|
window.requestAnimationFrame(loop);
|
||||||
let imgData = CTX.getImageData(1, 0, W - 1, H);
|
let imgData = CTX.getImageData(1, 0, W - 1, H);
|
||||||
|
|
||||||
CTX.fillRect(0, 0, W, H);
|
CTX.fillRect(0, 0, W, H);
|
||||||
CTX.putImageData(imgData, 0, 0);
|
CTX.putImageData(imgData, 0, 0);
|
||||||
ANALYSER.getByteFrequencyData(DATA);
|
ANALYSER.getByteFrequencyData(DATA);
|
||||||
for (let i = 0; i < LEN; i++) {
|
for (let i = 0; i < LEN; i++) {
|
||||||
let rat = DATA[i] / 128;
|
let rat = DATA[i] / 128 ;
|
||||||
let hue = Math.round((rat * 120) + 280 % 360);
|
let hue = Math.round((rat * 120) + 280 % 360);
|
||||||
let sat = '100%';
|
let sat = '100%';
|
||||||
let lit = 10 + (70 * rat) + '%';
|
let lit = 10 + (70 * rat) + '%';
|
||||||
@@ -79,7 +153,8 @@ h1 {
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<audio style="display:none" controls="" crossorigin="anonymous" id='player' autoplay=""><source src="/stream"></audio>
|
<img id="spectrogramimage" style="width:100%;height:100%;display:none" src="/spectrogram.png?nocache=<?php echo $time;?>">
|
||||||
|
|
||||||
|
<audio style="display:none" controls="" crossorigin="anonymous" id='player' preload="none"><source src="/stream"></audio>
|
||||||
<h1>Loading...</h1>
|
<h1>Loading...</h1>
|
||||||
<canvas></canvas>
|
<canvas></canvas>
|
||||||
|
|
||||||
|
|||||||
+19
-17
@@ -56,17 +56,9 @@ if(isset($_GET['species'])){
|
|||||||
$user = shell_exec("awk -F: '/1000/{print $1}' /etc/passwd");
|
$user = shell_exec("awk -F: '/1000/{print $1}' /etc/passwd");
|
||||||
$home = shell_exec("awk -F: '/1000/{print $6}' /etc/passwd");
|
$home = shell_exec("awk -F: '/1000/{print $6}' /etc/passwd");
|
||||||
$home = trim($home);
|
$home = trim($home);
|
||||||
if(!file_exists($home."/BirdNET-Pi/scripts/disk_check_exclude.txt")) {
|
if(!file_exists($home."/BirdNET-Pi/scripts/disk_check_exclude.txt") || strpos(file_get_contents($home."/BirdNET-Pi/scripts/disk_check_exclude.txt"),"##start") === false) {
|
||||||
file_put_contents($home."/BirdNET-Pi/scripts/disk_check_exclude.txt", "##start\n##end");
|
file_put_contents($home."/BirdNET-Pi/scripts/disk_check_exclude.txt", "");
|
||||||
}
|
file_put_contents($home."/BirdNET-Pi/scripts/disk_check_exclude.txt", "##start\n##end\n");
|
||||||
function editfile( $sourcefile, $start='##start', $end='##end', $data=array() ){
|
|
||||||
$lines=array_filter( file( $sourcefile , FILE_SKIP_EMPTY_LINES | FILE_IGNORE_NEW_LINES ) );
|
|
||||||
$output=array_merge(
|
|
||||||
array_splice( $lines, 0, array_search( strtolower( $start ), array_map('strtolower', $lines ) ) + 1 ),
|
|
||||||
$data,
|
|
||||||
array_splice( $lines, array_search( strtolower( $end ), array_map('strtolower', $lines ) ) )
|
|
||||||
);
|
|
||||||
file_put_contents( $sourcefile, implode( PHP_EOL, $output ) );
|
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
|
||||||
@@ -89,10 +81,10 @@ function editfile( $sourcefile, $start='##start', $end='##end', $data=array() ){
|
|||||||
<input type="hidden" name="sort" value="<?php if(isset($_GET['sort'])){echo $_GET['sort'];}?>">
|
<input type="hidden" name="sort" value="<?php if(isset($_GET['sort'])){echo $_GET['sort'];}?>">
|
||||||
<input type="hidden" name="view" value="Species Stats">
|
<input type="hidden" name="view" value="Species Stats">
|
||||||
<button <?php if(!isset($_GET['sort']) || $_GET['sort'] == "alphabetical"){ echo "style='background:#9fe29b !important;'"; }?> class="sortbutton" type="submit" name="sort" value="alphabetical">
|
<button <?php if(!isset($_GET['sort']) || $_GET['sort'] == "alphabetical"){ echo "style='background:#9fe29b !important;'"; }?> class="sortbutton" type="submit" name="sort" value="alphabetical">
|
||||||
<img src="images/sort_abc.svg" alt="Sort by alphabetical">
|
<img src="images/sort_abc.svg" title="Sort by alphabetical" alt="Sort by alphabetical">
|
||||||
</button>
|
</button>
|
||||||
<button <?php if(isset($_GET['sort']) && $_GET['sort'] == "occurrences"){ echo "style='background:#9fe29b !important;'"; }?> class="sortbutton" type="submit" name="sort" value="occurrences">
|
<button <?php if(isset($_GET['sort']) && $_GET['sort'] == "occurrences"){ echo "style='background:#9fe29b !important;'"; }?> class="sortbutton" type="submit" name="sort" value="occurrences">
|
||||||
<img src="images/sort_occ.svg" alt="Sort by occurrences">
|
<img src="images/sort_occ.svg" title="Sort by occurrences" alt="Sort by occurrences">
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@@ -181,19 +173,27 @@ while($results=$result3->fetchArray(SQLITE3_ASSOC)){
|
|||||||
} elseif (file_exists('./scripts/firstrun.ini')) {
|
} elseif (file_exists('./scripts/firstrun.ini')) {
|
||||||
$config = parse_ini_file('./scripts/firstrun.ini');
|
$config = parse_ini_file('./scripts/firstrun.ini');
|
||||||
}
|
}
|
||||||
|
if (! empty($config["FLICKR_API_KEY"])) {
|
||||||
$flickrjson = json_decode(file_get_contents("https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key=".$config["FLICKR_API_KEY"]."&text=\"".str_replace('_', '+', $comname)."\"&license=2%2C3%2C4%2C5%2C6%2C9&sort=relevance&per_page=15&format=json&nojsoncallback=1"), true)["photos"]["photo"];
|
$flickrjson = json_decode(file_get_contents("https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key=".$config["FLICKR_API_KEY"]."&text=\"".str_replace('_', '+', $comname)."\"&license=2%2C3%2C4%2C5%2C6%2C9&sort=relevance&per_page=15&format=json&nojsoncallback=1"), true)["photos"]["photo"];
|
||||||
|
|
||||||
foreach ($flickrjson as $val) {
|
foreach ($flickrjson as $val) {
|
||||||
|
|
||||||
$iter++;
|
$iter++;
|
||||||
$modaltext = "https://flickr.com/photos/".$val["owner"]."/".$val["id"];
|
$modaltext = "https://flickr.com/photos/".$val["owner"]."/".$val["id"];
|
||||||
$authorlink = "https://flickr.com/people/".$val["owner"];
|
$authorlink = "https://flickr.com/people/".$val["owner"];
|
||||||
$imageurl = 'http://farm' .$val["farm"]. '.static.flickr.com/' .$val["server"]. '/' .$val["id"]. '_' .$val["secret"]. '.jpg';
|
$imageurl = 'https://farm' .$val["farm"]. '.static.flickr.com/' .$val["server"]. '/' .$val["id"]. '_' .$val["secret"]. '.jpg';
|
||||||
echo "<img style='vertical-align:top' src=\"$imageurl\"><span style='cursor:pointer;color:blue;text-decoration:underline;' onclick='setModalText(".$iter.",\"".$val["title"]."\",\"".$modaltext."\", \"".$authorlink."\")'>".$iter."</span>";
|
echo "<span style='cursor:pointer;' onclick='setModalText(".$iter.",\"".$val["title"]."\",\"".$modaltext."\", \"".$authorlink."\")'><img style='vertical-align:top' src=\"$imageurl\"></span>";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<br><br><br>
|
<?php if(isset($_GET['species'])){?>
|
||||||
|
<br><br>
|
||||||
|
<div class="brbanner">Best Recordings for Other Species:</div><br>
|
||||||
|
<?php } else {?>
|
||||||
|
<hr><br>
|
||||||
|
<?php } ?>
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<?php
|
<?php
|
||||||
@@ -216,8 +216,10 @@ array_push($excludelines, $results['Date']."/".$comname."/".$results['File_Name'
|
|||||||
<b>Best Recording:</b> <?php echo $results['Date']." ".$results['Time'];?><br><video 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;?>" type="audio/mp3"></video></td>
|
<b>Best Recording:</b> <?php echo $results['Date']." ".$results['Time'];?><br><video 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;?>" type="audio/mp3"></video></td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php
|
<?php
|
||||||
editfile($home."/BirdNET-Pi/scripts/disk_check_exclude.txt","##start","##end",$excludelines);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$file = file_get_contents($home."/BirdNET-Pi/scripts/disk_check_exclude.txt");
|
||||||
|
file_put_contents($home."/BirdNET-Pi/scripts/disk_check_exclude.txt", "##start"."\n".implode("\n",$excludelines)."\n".substr($file, strpos($file, "##end")));
|
||||||
?>
|
?>
|
||||||
</table>
|
</table>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
ini_set('session.gc_maxlifetime', 7200);
|
||||||
|
session_set_cookie_params(7200);
|
||||||
|
session_start();
|
||||||
ini_set('display_errors', 1);
|
ini_set('display_errors', 1);
|
||||||
ini_set('display_startup_errors', 1);
|
ini_set('display_startup_errors', 1);
|
||||||
error_reporting(E_ALL);
|
error_reporting(E_ALL);
|
||||||
@@ -67,7 +70,7 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) {
|
|||||||
$statement0 = $db->prepare('SELECT Time, Com_Name, Sci_Name, Confidence, File_Name FROM detections WHERE Date == Date(\'now\', \'localtime\') '.$searchquery.' ORDER BY Time DESC LIMIT '.(intval($_GET['display_limit'])-40).',40');
|
$statement0 = $db->prepare('SELECT Time, Com_Name, Sci_Name, Confidence, File_Name FROM detections WHERE Date == Date(\'now\', \'localtime\') '.$searchquery.' ORDER BY Time DESC LIMIT '.(intval($_GET['display_limit'])-40).',40');
|
||||||
} else {
|
} else {
|
||||||
// legacy mode
|
// legacy mode
|
||||||
$statement0 = $db->prepare('SELECT Time, Com_Name, Sci_Name, Confidence, File_Name FROM detections WHERE Date == Date(\'now\', \'localtime\') '.$searchquery.' ORDER BY Time DESC '.$searchquery);
|
$statement0 = $db->prepare('SELECT Time, Com_Name, Sci_Name, Confidence, File_Name FROM detections WHERE Date == Date(\'now\', \'localtime\') '.$searchquery.' ORDER BY Time DESC');
|
||||||
}
|
}
|
||||||
if($statement0 == False){
|
if($statement0 == False){
|
||||||
echo "Database is busy";
|
echo "Database is busy";
|
||||||
@@ -77,7 +80,10 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) {
|
|||||||
|
|
||||||
?> <table>
|
?> <table>
|
||||||
<?php
|
<?php
|
||||||
$images = [];
|
|
||||||
|
if(!isset($_SESSION['images'])) {
|
||||||
|
$_SESSION['images'] = [];
|
||||||
|
}
|
||||||
$iterations = 0;
|
$iterations = 0;
|
||||||
|
|
||||||
if (file_exists('./scripts/thisrun.txt')) {
|
if (file_exists('./scripts/thisrun.txt')) {
|
||||||
@@ -97,16 +103,16 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) {
|
|||||||
|
|
||||||
if (!empty($config["FLICKR_API_KEY"])) {
|
if (!empty($config["FLICKR_API_KEY"])) {
|
||||||
// if we already searched flickr for this species before, use the previous image rather than doing an unneccesary api call
|
// if we already searched flickr for this species before, use the previous image rather than doing an unneccesary api call
|
||||||
$key = array_search($comname, array_column($images, 0));
|
$key = array_search($comname, array_column($_SESSION['images'], 0));
|
||||||
if($key !== false) {
|
if($key !== false) {
|
||||||
$image = $images[$key];
|
$image = $_SESSION['images'][$key];
|
||||||
} else {
|
} else {
|
||||||
$flickrjson = json_decode(file_get_contents("https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key=".$config["FLICKR_API_KEY"]."&text=".str_replace("_", "%20", $comname)."&license=2%2C3%2C4%2C5%2C6%2C9&sort=relevance&per_page=5&orientation=square,portrait&media=photos&format=json&nojsoncallback=1"), true)["photos"]["photo"][0];
|
$flickrjson = json_decode(file_get_contents("https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key=".$config["FLICKR_API_KEY"]."&text=".str_replace("_", "%20", $comname)."&license=2%2C3%2C4%2C5%2C6%2C9&sort=relevance&per_page=5&orientation=square,portrait&media=photos&format=json&nojsoncallback=1"), true)["photos"]["photo"][0];
|
||||||
$modaltext = "https://flickr.com/photos/".$flickrjson["owner"]."/".$flickrjson["id"];
|
$modaltext = "https://flickr.com/photos/".$flickrjson["owner"]."/".$flickrjson["id"];
|
||||||
$authorlink = "https://flickr.com/people/".$flickrjson["owner"];
|
$authorlink = "https://flickr.com/people/".$flickrjson["owner"];
|
||||||
$imageurl = 'http://farm' .$flickrjson["farm"]. '.static.flickr.com/' .$flickrjson["server"]. '/' .$flickrjson["id"]. '_' .$flickrjson["secret"]. '.jpg';
|
$imageurl = 'http://farm' .$flickrjson["farm"]. '.static.flickr.com/' .$flickrjson["server"]. '/' .$flickrjson["id"]. '_' .$flickrjson["secret"]. '.jpg';
|
||||||
array_push($images, array($comname,$imageurl,$flickrjson["title"], $modaltext, $authorlink));
|
array_push($_SESSION['images'], array($comname,$imageurl,$flickrjson["title"], $modaltext, $authorlink));
|
||||||
$image = $images[count($images)-1];
|
$image = $_SESSION['images'][count($_SESSION['images'])-1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
@@ -241,7 +247,11 @@ document.getElementById("searchterm").onkeydown = (function(e) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function switchViews(element) {
|
function switchViews(element) {
|
||||||
document.getElementById("detections_table").innerHTML = "";
|
if(searchterm == ""){
|
||||||
|
document.getElementById("detections_table").innerHTML = "<h3>Loading <?php echo $todaycount['COUNT(*)']; ?> detections...</h3>";
|
||||||
|
} else {
|
||||||
|
document.getElementById("detections_table").innerHTML = "<h3>Loading...</h3>";
|
||||||
|
}
|
||||||
if(element.innerHTML == "Legacy view") {
|
if(element.innerHTML == "Legacy view") {
|
||||||
element.innerHTML = "Normal view";
|
element.innerHTML = "Normal view";
|
||||||
loadDetections(undefined);
|
loadDetections(undefined);
|
||||||
@@ -253,7 +263,11 @@ function switchViews(element) {
|
|||||||
function searchDetections(searchvalue) {
|
function searchDetections(searchvalue) {
|
||||||
document.getElementById("detections_table").innerHTML = "<h3>Loading...</h3>";
|
document.getElementById("detections_table").innerHTML = "<h3>Loading...</h3>";
|
||||||
searchterm = searchvalue;
|
searchterm = searchvalue;
|
||||||
|
if(document.getElementsByClassName('legacyview')[0].innerHTML == "Normal view") {
|
||||||
|
loadDetections(undefined,undefined);
|
||||||
|
} else {
|
||||||
loadDetections(40,undefined);
|
loadDetections(40,undefined);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
function loadDetections(detections_limit, element=undefined) {
|
function loadDetections(detections_limit, element=undefined) {
|
||||||
const xhttp = new XMLHttpRequest();
|
const xhttp = new XMLHttpRequest();
|
||||||
@@ -267,7 +281,7 @@ function loadDetections(detections_limit, element=undefined) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if(searchterm !== ""){
|
if(searchterm != ""){
|
||||||
xhttp.open("GET", "todays_detections.php?ajax_detections=true&display_limit="+detections_limit+"&searchterm="+searchterm, true);
|
xhttp.open("GET", "todays_detections.php?ajax_detections=true&display_limit="+detections_limit+"&searchterm="+searchterm, true);
|
||||||
} else {
|
} else {
|
||||||
xhttp.open("GET", "todays_detections.php?ajax_detections=true&display_limit="+detections_limit, true);
|
xhttp.open("GET", "todays_detections.php?ajax_detections=true&display_limit="+detections_limit, true);
|
||||||
|
|||||||
@@ -35,7 +35,10 @@ if ! grep APPRISE_NOTIFICATION_BODY /etc/birdnet/birdnet.conf &>/dev/null;then
|
|||||||
sudo -u$USER echo "APPRISE_NOTIFICATION_BODY=\"A \$sciname \$comname was just detected with a confidence of \$confidence\"" >> /etc/birdnet/birdnet.conf
|
sudo -u$USER echo "APPRISE_NOTIFICATION_BODY=\"A \$sciname \$comname was just detected with a confidence of \$confidence\"" >> /etc/birdnet/birdnet.conf
|
||||||
fi
|
fi
|
||||||
if ! grep APPRISE_NOTIFY_EACH_DETECTION /etc/birdnet/birdnet.conf &>/dev/null;then
|
if ! grep APPRISE_NOTIFY_EACH_DETECTION /etc/birdnet/birdnet.conf &>/dev/null;then
|
||||||
sudo -u$USER echo "APPRISE_NOTIFY_EACH_DETECTION=false" >> /etc/birdnet/birdnet.conf
|
sudo -u$USER echo "APPRISE_NOTIFY_EACH_DETECTION=0 " >> /etc/birdnet/birdnet.conf
|
||||||
|
fi
|
||||||
|
if ! grep APPRISE_NOTIFY_NEW_SPECIES /etc/birdnet/birdnet.conf &>/dev/null;then
|
||||||
|
sudo -u$USER echo "APPRISE_NOTIFY_EACH_DETECTION=0 " >> /etc/birdnet/birdnet.conf
|
||||||
fi
|
fi
|
||||||
apprise_installation_status=$(~/BirdNET-Pi/birdnet/bin/python3 -c 'import pkgutil; print("installed" if pkgutil.find_loader("apprise") else "not installed")')
|
apprise_installation_status=$(~/BirdNET-Pi/birdnet/bin/python3 -c 'import pkgutil; print("installed" if pkgutil.find_loader("apprise") else "not installed")')
|
||||||
if [[ "$apprise_installation_status" = "not installed" ]];then
|
if [[ "$apprise_installation_status" = "not installed" ]];then
|
||||||
@@ -58,3 +61,8 @@ fi
|
|||||||
if ! grep FLICKR_API_KEY /etc/birdnet/birdnet.conf &>/dev/null;then
|
if ! grep FLICKR_API_KEY /etc/birdnet/birdnet.conf &>/dev/null;then
|
||||||
sudo -u$USER echo "FLICKR_API_KEY=" >> /etc/birdnet/birdnet.conf
|
sudo -u$USER echo "FLICKR_API_KEY=" >> /etc/birdnet/birdnet.conf
|
||||||
fi
|
fi
|
||||||
|
if systemctl list-unit-files pushed_notifications.service;then
|
||||||
|
sudo systemctl disable --now pushed_notifications.service
|
||||||
|
sudo rm -f /usr/lib/systemd/system/pushed_notifications.service
|
||||||
|
sudo rm $HOME/BirdNET-Pi/templates/pushed_notifications.service
|
||||||
|
fi
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
#birdnet
|
#birdnet
|
||||||
*/5 * * * * $USER /usr/local/bin/disk_check.sh &> /dev/null
|
*/5 * * * * $USER /usr/local/bin/disk_check.sh >/dev/null 2>&1
|
||||||
#birdnet
|
#birdnet
|
||||||
*/3 * * * * $USER /usr/local/bin/cleanup.sh &> /dev/null
|
*/3 * * * * $USER /usr/local/bin/cleanup.sh >/dev/null 2>&1
|
||||||
#birdnet
|
#birdnet
|
||||||
@reboot $USER /usr/local/bin/cleanup.sh &> /dev/null
|
@reboot $USER /usr/local/bin/cleanup.sh >/dev/null 2>&1
|
||||||
|
|||||||
Reference in New Issue
Block a user