Merge branch 'mcguirepr89:main' into main
This commit is contained in:
+21
-1
@@ -1,4 +1,24 @@
|
|||||||
<?php
|
<?php
|
||||||
|
$sys_timezone = "";
|
||||||
|
// If we can get the timezome from the systems timezone file ust that
|
||||||
|
if (file_exists('/etc/timezone')) {
|
||||||
|
$tz_data = file_get_contents('/etc/timezone');
|
||||||
|
if ($tz_data !== false) {
|
||||||
|
$sys_timezone = trim($tz_data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Else get timezone from the timedatectl command
|
||||||
|
$tz_data = shell_exec('timedatectl show');
|
||||||
|
$tz_data_array = parse_ini_string($tz_data);
|
||||||
|
if (is_array($tz_data_array) && array_key_exists('Timezone', $tz_data_array)) {
|
||||||
|
$sys_timezone = $tz_data_array['Timezone'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Finally if we have a valod timezone, set it as the one PHP uses
|
||||||
|
if ($sys_timezone !== "") {
|
||||||
|
date_default_timezone_set($sys_timezone);
|
||||||
|
}
|
||||||
|
|
||||||
if (file_exists('./scripts/thisrun.txt')) {
|
if (file_exists('./scripts/thisrun.txt')) {
|
||||||
$config = parse_ini_file('./scripts/thisrun.txt');
|
$config = parse_ini_file('./scripts/thisrun.txt');
|
||||||
} elseif (file_exists('./scripts/firstrun.ini')) {
|
} elseif (file_exists('./scripts/firstrun.ini')) {
|
||||||
@@ -17,7 +37,7 @@ body::-webkit-scrollbar {
|
|||||||
display:none
|
display:none
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<link rel="stylesheet" href="style.css?v=1.20.23">
|
<link rel="stylesheet" href="style.css?v=4.06.23">
|
||||||
<link rel="stylesheet" type="text/css" href="static/dialog-polyfill.css" />
|
<link rel="stylesheet" type="text/css" href="static/dialog-polyfill.css" />
|
||||||
<body>
|
<body>
|
||||||
<div class="banner">
|
<div class="banner">
|
||||||
|
|||||||
+16
-2
@@ -409,8 +409,8 @@ button:hover {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#body::-webkit-scrollbar {
|
#body::-webkit-scrollbar {
|
||||||
# display:none
|
/*display:none*/
|
||||||
#}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 1290px) {
|
@media screen and (max-width: 1290px) {
|
||||||
.column1,.column2,.column3,.column4 {
|
.column1,.column2,.column3,.column4 {
|
||||||
@@ -563,6 +563,11 @@ button:hover {
|
|||||||
height:25px !important;
|
height:25px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.copyimage-mobile {
|
||||||
|
width: 16px !important;
|
||||||
|
height: 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
.relative {
|
.relative {
|
||||||
position:relative;
|
position:relative;
|
||||||
}
|
}
|
||||||
@@ -814,6 +819,15 @@ pre#timer.bash {
|
|||||||
background-color:#9fe29b
|
background-color:#9fe29b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#newrtspstream{
|
||||||
|
cursor: pointer;
|
||||||
|
margin-left: 2px;
|
||||||
|
height: 5px;
|
||||||
|
line-height: 5px;
|
||||||
|
padding: 3px;
|
||||||
|
background-color: #9fe29b;
|
||||||
|
}
|
||||||
|
|
||||||
#ddnewline::before {
|
#ddnewline::before {
|
||||||
content: none;
|
content: none;
|
||||||
}
|
}
|
||||||
+22
-2
@@ -1,4 +1,24 @@
|
|||||||
<?php
|
<?php
|
||||||
|
$sys_timezone = "";
|
||||||
|
// If we can get the timezome from the systems timezone file ust that
|
||||||
|
if (file_exists('/etc/timezone')) {
|
||||||
|
$tz_data = file_get_contents('/etc/timezone');
|
||||||
|
if ($tz_data !== false) {
|
||||||
|
$sys_timezone = trim($tz_data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Else get timezone from the timedatectl command
|
||||||
|
$tz_data = shell_exec('timedatectl show');
|
||||||
|
$tz_data_array = parse_ini_string($tz_data);
|
||||||
|
if (is_array($tz_data_array) && array_key_exists('Timezone', $tz_data_array)) {
|
||||||
|
$sys_timezone = $tz_data_array['Timezone'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//Finally if we have a valod timezone, set it as the one PHP uses
|
||||||
|
if ($sys_timezone !== "") {
|
||||||
|
date_default_timezone_set($sys_timezone);
|
||||||
|
}
|
||||||
|
|
||||||
session_start();
|
session_start();
|
||||||
$user = shell_exec("awk -F: '/1000/{print $1}' /etc/passwd");
|
$user = shell_exec("awk -F: '/1000/{print $1}' /etc/passwd");
|
||||||
$user = trim($user);
|
$user = trim($user);
|
||||||
@@ -31,7 +51,7 @@ if (file_exists('./scripts/thisrun.txt')) {
|
|||||||
$config = parse_ini_file('./scripts/firstrun.ini');
|
$config = parse_ini_file('./scripts/firstrun.ini');
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<link rel="stylesheet" href="style.css?v=1.20.23">
|
<link rel="stylesheet" href="style.css?v=4.06.23">
|
||||||
<style>
|
<style>
|
||||||
body::-webkit-scrollbar {
|
body::-webkit-scrollbar {
|
||||||
display:none
|
display:none
|
||||||
|
|||||||
+100
-4
@@ -76,6 +76,22 @@ if(isset($_GET['submit'])) {
|
|||||||
exec('sudo systemctl restart livestream.service');
|
exec('sudo systemctl restart livestream.service');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isset($_GET["rtsp_stream_to_livestream"])) {
|
||||||
|
$rtsp_stream_selected = trim($_GET["rtsp_stream_to_livestream"]);
|
||||||
|
|
||||||
|
//Setting exists already, see if the value changed
|
||||||
|
if (strcmp($rtsp_stream_selected, $config['RTSP_STREAM_TO_LIVESTREAM']) !== 0) {
|
||||||
|
$contents = preg_replace("/RTSP_STREAM_TO_LIVESTREAM=.*/", "RTSP_STREAM_TO_LIVESTREAM=\"$rtsp_stream_selected\"", $contents);
|
||||||
|
$contents2 = preg_replace("/RTSP_STREAM_TO_LIVESTREAM=.*/", "RTSP_STREAM_TO_LIVESTREAM=\"$rtsp_stream_selected\"", $contents2);
|
||||||
|
$fh = fopen("/etc/birdnet/birdnet.conf", "w");
|
||||||
|
$fh2 = fopen("./scripts/thisrun.txt", "w");
|
||||||
|
fwrite($fh, $contents);
|
||||||
|
fwrite($fh2, $contents2);
|
||||||
|
sleep(1);
|
||||||
|
exec("sudo systemctl restart livestream.service");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(isset($_GET["overlap"])) {
|
if(isset($_GET["overlap"])) {
|
||||||
$overlap = $_GET["overlap"];
|
$overlap = $_GET["overlap"];
|
||||||
@@ -269,6 +285,58 @@ if (file_exists('./scripts/thisrun.txt')) {
|
|||||||
output.innerHTML = this.value;
|
output.innerHTML = this.value;
|
||||||
document.getElementById("predictionCount").innerHTML = parseInt((this.value * <?php echo $count; ?>)/100);
|
document.getElementById("predictionCount").innerHTML = parseInt((this.value * <?php echo $count; ?>)/100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Keep track of how many new input fields were added
|
||||||
|
var number_of_new_rtsp_urls_added = 0;
|
||||||
|
//Function to insert new input fields
|
||||||
|
function addNewrtspInput() {
|
||||||
|
//Find the placeholder input field
|
||||||
|
var url_template_element = document.getElementById('rtsp_stream_url_placeholder');
|
||||||
|
var new_url_input_template = url_template_element.cloneNode();
|
||||||
|
var br_seperator = document.createElement("BR");
|
||||||
|
|
||||||
|
//Fix up the new element so it's visible, set the style so it's sligned correctly
|
||||||
|
new_url_input_template.setAttribute("id", "rtsp_stream_url_new_" + number_of_new_rtsp_urls_added);
|
||||||
|
new_url_input_template.setAttribute("name", "rtsp_stream_new_" + number_of_new_rtsp_urls_added);
|
||||||
|
new_url_input_template.removeAttribute("style");
|
||||||
|
|
||||||
|
//Insert the new input field before the button to add new urls
|
||||||
|
var newrtspstream_button = document.getElementById('newrtspstream_button_container');
|
||||||
|
//Insert the new input element before the newrtspstream button
|
||||||
|
newrtspstream_button.parentNode.insertBefore(new_url_input_template, newrtspstream_button);
|
||||||
|
//Add a separator before the button
|
||||||
|
newrtspstream_button.parentNode.insertBefore(br_seperator, newrtspstream_button);
|
||||||
|
|
||||||
|
//Increment the counter
|
||||||
|
number_of_new_rtsp_urls_added++;
|
||||||
|
}
|
||||||
|
|
||||||
|
var rtsp_stream_string = "";
|
||||||
|
var rtsp_stream_string_array = [];
|
||||||
|
//Collect all the rtsp urls that have been set, concat them into a single string and set it into the rtsp_stream input field so it gets saved
|
||||||
|
function collectrtspUrls() {
|
||||||
|
//Reset the array and string so we don't get duplicates
|
||||||
|
rtsp_stream_string = "";
|
||||||
|
rtsp_stream_string_array = [];
|
||||||
|
|
||||||
|
//Get the inputs by name (which is similar across
|
||||||
|
var existing_rtsp_stream_urls = document.querySelectorAll('[name^="rtsp_stream_"]');
|
||||||
|
//Loop over the result and get the values
|
||||||
|
for (let i = 0; i < existing_rtsp_stream_urls.length; i++) {
|
||||||
|
//Only collect results that re not empty and add them to the array
|
||||||
|
if (existing_rtsp_stream_urls[i].value !== 'undefined' && existing_rtsp_stream_urls[i].value !== "") {
|
||||||
|
rtsp_stream_string_array.push(existing_rtsp_stream_urls[i].value.trim());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//if the array is not empty, then implode the array joining all the values by a comma
|
||||||
|
if (rtsp_stream_string_array.length !== 0) {
|
||||||
|
rtsp_stream_string = rtsp_stream_string_array.join(',');
|
||||||
|
//Locate the hidden rtsp_stream input field that we'll populate with the full string which will get saved to the config file
|
||||||
|
var rtsp_stream_input = document.querySelector('[name=rtsp_stream]');
|
||||||
|
rtsp_stream_input.setAttribute('value',rtsp_stream_string);
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<p>If a Human is predicted anywhere among the top <span id="predictionCount"><?php echo $newconfig['PRIVACY_THRESHOLD'] == 0 ? "threshold % of" : intval(($newconfig['PRIVACY_THRESHOLD'] * $count)/100); ?></span> predictions, the sample will be considered of human origin and no data will be collected. Start with 1% and move up as needed.</p>
|
<p>If a Human is predicted anywhere among the top <span id="predictionCount"><?php echo $newconfig['PRIVACY_THRESHOLD'] == 0 ? "threshold % of" : intval(($newconfig['PRIVACY_THRESHOLD'] * $count)/100); ?></span> predictions, the sample will be considered of human origin and no data will be collected. Start with 1% and move up as needed.</p>
|
||||||
<label>Full Disk Behavior: </label>
|
<label>Full Disk Behavior: </label>
|
||||||
@@ -283,9 +351,37 @@ 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>
|
<label id="rtsp_stream_input_label" for="rtsp_stream">RTSP Stream: </label>
|
||||||
<input name="rtsp_stream" type="url" value="<?php echo $newconfig['RTSP_STREAM'];?>"</input><br>
|
<br>
|
||||||
<p>If you place an RTSP stream URL here, BirdNET-Pi will use that as its audio source.</p>
|
<input style="display: none;" name="rtsp_stream" type="url" value="">
|
||||||
|
<input style="display: none;" id="rtsp_stream_url_placeholder" name="rtsp_stream_placeholder" type="url" size="60" value="">
|
||||||
|
<?php
|
||||||
|
//Print out the rtsp urls in their own input fields
|
||||||
|
//Explode the stream into an array at the comma
|
||||||
|
$rtsp_streams = explode(",", $newconfig['RTSP_STREAM']);
|
||||||
|
//Print out existing streams
|
||||||
|
foreach ($rtsp_streams as $stream_idx => $stream_url) {
|
||||||
|
//For the first input keep the element mostly the same as the original but without styling to align it
|
||||||
|
if ($stream_idx === 0) {
|
||||||
|
?>
|
||||||
|
<input id="rtsp_stream_url_0" name="rtsp_stream_0" type="url" size="60" value="<?php echo $stream_url; ?>">
|
||||||
|
<br>
|
||||||
|
<?php
|
||||||
|
} else {
|
||||||
|
//For every other input field, change the id to reflect the URL's index in the array
|
||||||
|
?>
|
||||||
|
<input id="rtsp_stream_url_<?php echo $stream_idx; ?>" name="rtsp_stream_<?php echo $stream_idx; ?>" type="url" size="60"
|
||||||
|
value="<?php echo $stream_url; ?>">
|
||||||
|
<br>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<div id="newrtspstream_button_container">
|
||||||
|
<br>
|
||||||
|
<span id="newrtspstream" onclick="addNewrtspInput();">add</span><br>
|
||||||
|
</div>
|
||||||
|
<p>If you place an RTSP stream URL here, BirdNET-Pi will use that as its audio source.<br>Multiple streams are allowed but may have a impact on rPi performance.<br>Analyze ffmpeg CPU/Memory usage with <b>top</b> or <b>htop</b> if necessary.<br>To remove all and use the soundcard again, just delete the RTSP entries and click Save at the bottom.</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>
|
||||||
@@ -389,7 +485,7 @@ foreach($formats as $format){
|
|||||||
</p>
|
</p>
|
||||||
<br><br>
|
<br><br>
|
||||||
<input type="hidden" name="view" value="Advanced">
|
<input type="hidden" name="view" value="Advanced">
|
||||||
<button onclick="if(<?php print($newconfig['PRIVACY_THRESHOLD']);?> != document.getElementById('privacy_threshold').value){return confirm('This will take about 90 seconds.')}" type="submit" name="submit" value="advanced">
|
<button onclick="if(<?php print($newconfig['PRIVACY_THRESHOLD']);?> != document.getElementById('privacy_threshold').value){return confirm('This will take about 90 seconds.')} collectrtspUrls();" type="submit" name="submit" value="advanced">
|
||||||
<?php
|
<?php
|
||||||
if(isset($_GET['submit'])){
|
if(isset($_GET['submit'])){
|
||||||
echo "Success!";
|
echo "Success!";
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
# Performs the recording from the specified RSTP stream or soundcard
|
||||||
set -x
|
set -x
|
||||||
source /etc/birdnet/birdnet.conf
|
source /etc/birdnet/birdnet.conf
|
||||||
|
|
||||||
@@ -6,10 +7,35 @@ source /etc/birdnet/birdnet.conf
|
|||||||
|
|
||||||
if [ ! -z $RTSP_STREAM ];then
|
if [ ! -z $RTSP_STREAM ];then
|
||||||
[ -d $RECS_DIR/StreamData ] || mkdir -p $RECS_DIR/StreamData
|
[ -d $RECS_DIR/StreamData ] || mkdir -p $RECS_DIR/StreamData
|
||||||
|
# Explode the RSPT steam setting into an array so we can count the number we have
|
||||||
|
RTSP_STREAMS_EXPLODED_ARRAY=(${RTSP_STREAM//,/ })
|
||||||
|
|
||||||
while true;do
|
while true;do
|
||||||
for i in ${RTSP_STREAM//,/ };do
|
# Original loop
|
||||||
ffmpeg -nostdin -i ${i} -t ${RECORDING_LENGTH} -vn -acodec pcm_s16le -ac 2 -ar 48000 file:${RECS_DIR}/StreamData/$(date "+%F")-birdnet-$(date "+%H:%M:%S").wav
|
# for i in ${RTSP_STREAM//,/ };do
|
||||||
|
# ffmpeg -nostdin -i ${i} -t ${RECORDING_LENGTH} -vn -acodec pcm_s16le -ac 2 -ar 48000 file:${RECS_DIR}/StreamData/$(date "+%F")-birdnet-$(date "+%H:%M:%S").wav
|
||||||
|
# done
|
||||||
|
|
||||||
|
# Initially start the count off at 1 - our very first stream
|
||||||
|
RTSP_STREAMS_STARTED_COUNT=1
|
||||||
|
FFMPEG_PARAMS=""
|
||||||
|
|
||||||
|
# Loop over the streams
|
||||||
|
for i in "${RTSP_STREAMS_EXPLODED_ARRAY[@]}"
|
||||||
|
do
|
||||||
|
# Map id used to map input to output, this is 0 based in ffmpeg decrement
|
||||||
|
MAP_ID=$((RTSP_STREAMS_STARTED_COUNT-1))
|
||||||
|
# Build up the parameters to process the RSTP stream, including mapping for the output
|
||||||
|
FFMPEG_PARAMS+="-vn -thread_queue_size 512 -i ${i} -map ${MAP_ID} -t ${RECORDING_LENGTH} -acodec pcm_s16le -ac 2 -ar 48000 file:${RECS_DIR}/StreamData/$(date "+%F")-birdnet-RTSP_${RTSP_STREAMS_STARTED_COUNT}-$(date "+%H:%M:%S").wav "
|
||||||
|
# Increment counter
|
||||||
|
((RTSP_STREAMS_STARTED_COUNT += 1))
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# Make sure were passing something valid to ffmpeg, ffmpeg will run interactive and control our look by waiting ${RECORDING_LENGTH} between loops
|
||||||
|
if [ -n "$FFMPEG_PARAMS" ];then
|
||||||
|
ffmpeg -nostdin $FFMPEG_PARAMS
|
||||||
|
fi
|
||||||
|
|
||||||
done
|
done
|
||||||
else
|
else
|
||||||
if ! pulseaudio --check;then pulseaudio --start;fi
|
if ! pulseaudio --check;then pulseaudio --start;fi
|
||||||
|
|||||||
+1
-1
@@ -82,7 +82,7 @@ if(isset($_GET["latitude"])){
|
|||||||
echo "<script>setTimeout(
|
echo "<script>setTimeout(
|
||||||
function() {
|
function() {
|
||||||
const xhttp = new XMLHttpRequest();
|
const xhttp = new XMLHttpRequest();
|
||||||
xhttp.open(\"GET\", \"scripts/config.php?restart_php=true\", true);
|
xhttp.open(\"GET\", \"./config.php?restart_php=true\", true);
|
||||||
xhttp.send();
|
xhttp.send();
|
||||||
}, 1000);</script>";
|
}, 1000);</script>";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
<div class="customlabels column1">
|
<div class="customlabels column1">
|
||||||
<form action="" method="GET" id="add">
|
<form action="" method="GET" id="add">
|
||||||
<h3>All Species Labels</h3>
|
<h3>All Species Labels</h3>
|
||||||
|
<input autocomplete="off" size="18" type="text" placeholder="Search Species..." id="exclude_species_searchterm" name="exclude_species_searchterm">
|
||||||
<select name="species[]" id="species" multiple size="auto">
|
<select name="species[]" id="species" multiple size="auto">
|
||||||
<option>Choose a species below to add to the Excluded Species List</option>
|
<option>Choose a species below to add to the Excluded Species List</option>
|
||||||
<?php
|
<?php
|
||||||
@@ -53,5 +54,73 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var search_term = document.querySelector("input#exclude_species_searchterm");
|
||||||
|
search_term.addEventListener("keydown", doSearch);
|
||||||
|
//Index where we found a match
|
||||||
|
var search_match_idx = 1;
|
||||||
|
var last_search_term = "";
|
||||||
|
|
||||||
|
function doSearch(eventObj) {
|
||||||
|
//Don't do anything if the user is till composing
|
||||||
|
if (eventObj.isComposing || eventObj.keyCode === 229) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//If the key pressed is the enter key capture it, stop the form submitting and do the search
|
||||||
|
if (eventObj.key === 'Enter' || eventObj.keyCode === 13) {
|
||||||
|
eventObj.preventDefault();
|
||||||
|
|
||||||
|
//User wants to submit the text as a search
|
||||||
|
var search_text = search_term.value.toLowerCase();
|
||||||
|
|
||||||
|
//Now look at the select list, loop over the options and try find part of the text in the option's name/text
|
||||||
|
var species_select_list = document.querySelector('select#species');
|
||||||
|
|
||||||
|
//if the search text differs from last time start the search from the begining of te list
|
||||||
|
if (search_text !== last_search_term) {
|
||||||
|
//Also unselect the last match
|
||||||
|
species_select_list[search_match_idx].removeAttribute('selected');
|
||||||
|
search_match_idx = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Start the loop at 1 so we skip the very initial value asking the user to select a option
|
||||||
|
for (let i = search_match_idx; i < species_select_list.length; i++) {
|
||||||
|
// if (species_select_list[i] !== 'undefined') {
|
||||||
|
option_text = species_select_list[i].value;
|
||||||
|
search_match_text = option_text.toLowerCase().includes(search_text)
|
||||||
|
|
||||||
|
//Check if the item is already selected, that could mean that user may be searching the same phrase
|
||||||
|
//again, we want to search further so let's unselect it and move to the next index
|
||||||
|
if (species_select_list[search_match_idx].getAttribute('selected') === true || species_select_list[search_match_idx].getAttribute('selected') === "true") {
|
||||||
|
species_select_list[search_match_idx].removeAttribute('selected');
|
||||||
|
//Go to the next item
|
||||||
|
i++
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//There was a match,
|
||||||
|
if (search_match_text === true) {
|
||||||
|
//already on this item so skip it and continue with list
|
||||||
|
if (search_match_idx === i) {
|
||||||
|
i++
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
//Finally we havent found this item before
|
||||||
|
search_match_idx = i;
|
||||||
|
|
||||||
|
//Scroll into view and select it
|
||||||
|
species_select_list[search_match_idx].scrollIntoView();
|
||||||
|
species_select_list[search_match_idx].setAttribute('selected', true);
|
||||||
|
//break the loop
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
//Track what search term was used so we know when to start over
|
||||||
|
last_search_term = search_text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
+59
-55
@@ -4,63 +4,67 @@
|
|||||||
echo "........................................IPs....................................."
|
echo "........................................IPs....................................."
|
||||||
echo "LAN IP: $(hostname -I|cut -d' ' -f1)"
|
echo "LAN IP: $(hostname -I|cut -d' ' -f1)"
|
||||||
echo "Public IP: $(curl -s4 ifconfig.co)"
|
echo "Public IP: $(curl -s4 ifconfig.co)"
|
||||||
echo "..................................\`vcgencmd stats\`.............................."
|
if [ ! "$(dpkg -l | ! grep -q "vcgencmd")" ]
|
||||||
sudo -u$USER vcgencmd get_throttled
|
then
|
||||||
hex=$(sudo -u$USER vcgencmd get_throttled|cut -d'x' -f2)
|
echo "..................................\`vcgencmd stats\`.............................."
|
||||||
binary=$(echo "ibase=16;obase=2;$hex"|bc)
|
sudo -u$USER vcgencmd get_throttled
|
||||||
echo "Binary: $binary";
|
hex=$(sudo -u$USER vcgencmd get_throttled | cut -d'x' -f2)
|
||||||
revbinary=$(echo $binary|rev)
|
binary=$(echo "ibase=16;obase=2;$hex" | bc)
|
||||||
if echo $binary | grep 1 ;then
|
echo "Binary: $binary"
|
||||||
echo "ISSUES DETECTED"
|
revbinary=$(echo $binary | rev)
|
||||||
if [ ${revbinary:0:1} -eq 1 &> /dev/null ];then
|
if echo $binary | grep 1; then
|
||||||
message="Under-voltage detected"
|
echo "ISSUES DETECTED"
|
||||||
echo "$message"
|
if [ ${revbinary:0:1} -eq 1 ] &>/dev/null; then
|
||||||
dmesg -H | grep -i voltage
|
message="Under-voltage detected"
|
||||||
fi
|
echo "$message"
|
||||||
if [ ${revbinary:1:1} -eq 1 &> /dev/null ];then
|
dmesg -H | grep -i voltage
|
||||||
message="Arm frequency capped"
|
fi
|
||||||
echo "$message"
|
if [ ${revbinary:1:1} -eq 1 ] &>/dev/null; then
|
||||||
dmesg -H | grep -i frequen
|
message="Arm frequency capped"
|
||||||
fi
|
echo "$message"
|
||||||
if [ ${revbinary:2:1} -eq 1 &> /dev/null ];then
|
dmesg -H | grep -i frequen
|
||||||
message="Currently Throttled"
|
fi
|
||||||
echo "$message"
|
if [ ${revbinary:2:1} -eq 1 ] &>/dev/null; then
|
||||||
dmesg -H | grep -i throttl
|
message="Currently Throttled"
|
||||||
fi
|
echo "$message"
|
||||||
if [ ${revbinary:3:1} -eq 1 &> /dev/null ];then
|
dmesg -H | grep -i throttl
|
||||||
message="Soft temperatue limit active"
|
fi
|
||||||
echo "$message"
|
if [ ${revbinary:3:1} -eq 1 ] &>/dev/null; then
|
||||||
dmesg -H | grep -i temperature
|
message="Soft temperatue limit active"
|
||||||
fi
|
echo "$message"
|
||||||
if [ ${revbinary:16:1} -eq 1 &> /dev/null ];then
|
dmesg -H | grep -i temperature
|
||||||
message="Under-voltage has occurred"
|
fi
|
||||||
echo "$message"
|
if [ ${revbinary:16:1} -eq 1 ] &>/dev/null; then
|
||||||
dmesg -H | grep -i voltage
|
message="Under-voltage has occurred"
|
||||||
fi
|
echo "$message"
|
||||||
if [ ${revbinary:17:1} -eq 1 &> /dev/null ];then
|
dmesg -H | grep -i voltage
|
||||||
message="Arm frequency capping has occurred"
|
fi
|
||||||
echo "$message"
|
if [ ${revbinary:17:1} -eq 1 ] &>/dev/null; then
|
||||||
dmesg -H | grep -i frequen
|
message="Arm frequency capping has occurred"
|
||||||
fi
|
echo "$message"
|
||||||
if [ ${revbinary:18:1} -eq 1 &> /dev/null ];then
|
dmesg -H | grep -i frequen
|
||||||
message="Throttling has occurred"
|
fi
|
||||||
echo "$message"
|
if [ ${revbinary:18:1} -eq 1 ] &>/dev/null; then
|
||||||
dmesg -H | grep -i throttl
|
message="Throttling has occurred"
|
||||||
fi
|
echo "$message"
|
||||||
if [ ${revbinary:19:1} -eq 1 &> /dev/null ];then
|
dmesg -H | grep -i throttl
|
||||||
message="Soft temperature limit has occurred"
|
fi
|
||||||
echo "$message"
|
if [ ${revbinary:19:1} -eq 1 ] &>/dev/null; then
|
||||||
dmesg -H | grep -i temperature
|
message="Soft temperature limit has occurred"
|
||||||
|
echo "$message"
|
||||||
|
dmesg -H | grep -i temperature
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo "....................................Clock Speeds................................"
|
||||||
|
for i in arm core h264 isp v3d uart pwm emmc pixel vec hdmi dpi; do
|
||||||
|
echo -e "${i}:\t$(sudo -u$USER vcgencmd measure_clock ${i})"
|
||||||
|
done
|
||||||
|
echo "........................................Volts..................................."
|
||||||
|
for i in core sdram_c sdram_i sdram_p; do
|
||||||
|
echo -e "${i}:\t$(sudo -u$USER vcgencmd measure_volts ${i})"
|
||||||
|
done
|
||||||
fi
|
fi
|
||||||
echo "....................................Clock Speeds................................"
|
|
||||||
for i in arm core h264 isp v3d uart pwm emmc pixel vec hdmi dpi;do
|
|
||||||
echo -e "${i}:\t$(sudo -u$USER vcgencmd measure_clock ${i})"
|
|
||||||
done
|
|
||||||
echo "........................................Volts..................................."
|
|
||||||
for i in core sdram_c sdram_i sdram_p;do
|
|
||||||
echo -e "${i}:\t$(sudo -u$USER vcgencmd measure_volts ${i})"
|
|
||||||
done
|
|
||||||
echo ".....................................Caddyfile.................................."
|
echo ".....................................Caddyfile.................................."
|
||||||
cat /etc/caddy/Caddyfile
|
cat /etc/caddy/Caddyfile
|
||||||
echo ".................................... Crontab...................................."
|
echo ".................................... Crontab...................................."
|
||||||
|
|||||||
+18
-1
@@ -5,7 +5,24 @@ source /etc/birdnet/birdnet.conf
|
|||||||
if [ -z ${REC_CARD} ];then
|
if [ -z ${REC_CARD} ];then
|
||||||
echo "Stream not supported"
|
echo "Stream not supported"
|
||||||
elif [[ ! -z ${RTSP_STREAM} ]];then
|
elif [[ ! -z ${RTSP_STREAM} ]];then
|
||||||
ffmpeg -nostdin -loglevel 32 -ac ${CHANNELS} -i ${RTSP_STREAM} -acodec libmp3lame \
|
# Explode the RSPT steam setting into an array so we can count the number we have
|
||||||
|
RSTP_STREAMS_EXPLODED_ARRAY=(${RTSP_STREAM//,/ })
|
||||||
|
|
||||||
|
# If for some reason the RTSP_STREAM_TO_LIVESTREAM is not set, then init it to 0 to use the first stream
|
||||||
|
if [[ -z ${RTSP_STREAM_TO_LIVESTREAM} ]];then
|
||||||
|
RTSP_STREAM_TO_LIVESTREAM=0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Get the RSTP stream at the specified array index
|
||||||
|
SELECTED_RSTP_STREAM=${RSTP_STREAMS_EXPLODED_ARRAY[RTSP_STREAM_TO_LIVESTREAM]}
|
||||||
|
|
||||||
|
# If for some reason the RTSP stream url is null
|
||||||
|
if [[ -z ${SELECTED_RSTP_STREAM} ]];then
|
||||||
|
# Try select the first stream
|
||||||
|
SELECTED_RSTP_STREAM=${RSTP_STREAMS_EXPLODED_ARRAY[0]}
|
||||||
|
fi
|
||||||
|
|
||||||
|
ffmpeg -nostdin -loglevel 32 -ac ${CHANNELS} -i ${SELECTED_RSTP_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
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -214,8 +214,8 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" && isse
|
|||||||
<?php } ?>
|
<?php } ?>
|
||||||
<form action="" method="GET">
|
<form action="" method="GET">
|
||||||
<input type="hidden" name="view" value="Species Stats">
|
<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><img style="width: unset !important;display: inline;height: 1em;cursor:pointer" title="View species stats" onclick="generateMiniGraph(this, '<?php echo $comname; ?>')" width=25 src="images/chart.svg"></br>
|
<button type="submit" name="species" value="<?php echo $mostrecent['Com_Name'];?>"><?php echo $mostrecent['Com_Name'];?></button><img style="width: unset !important;display: inline;height: 1em;cursor:pointer" title="View species stats" onclick="generateMiniGraph(this, '<?php echo $comname; ?>')" width=25 src="images/chart.svg"><br>
|
||||||
<a href="https://wikipedia.org/wiki/<?php echo $sciname;?>" target="_blank"/><i><?php echo $mostrecent['Sci_Name'];?></i></a>
|
<a href="https://wikipedia.org/wiki/<?php echo $sciname;?>" target="_blank"><i><?php echo $mostrecent['Sci_Name'];?></i></a>
|
||||||
<br>Confidence: <?php echo $percent = round((float)round($mostrecent['Confidence'],2) * 100 ) . '%';?><br></div><br>
|
<br>Confidence: <?php echo $percent = round((float)round($mostrecent['Confidence'],2) * 100 ) . '%';?><br></div><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>
|
<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>
|
</form>
|
||||||
|
|||||||
+29
-4
@@ -1,3 +1,4 @@
|
|||||||
|
import re
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from tzlocal import get_localzone
|
from tzlocal import get_localzone
|
||||||
import datetime
|
import datetime
|
||||||
@@ -395,16 +396,40 @@ def handle_client(conn, addr):
|
|||||||
|
|
||||||
birdweather_id = args.birdweather_id
|
birdweather_id = args.birdweather_id
|
||||||
|
|
||||||
# Read audio data
|
# Read audio data & handle errors
|
||||||
audioData = readAudioData(args.i, args.overlap)
|
try:
|
||||||
|
audioData = readAudioData(args.i, args.overlap)
|
||||||
|
|
||||||
|
except (NameError, TypeError) as e:
|
||||||
|
print(f"Error with the following info: {e}")
|
||||||
|
open('~/BirdNET-Pi/analyzing_now.txt', 'w').close()
|
||||||
|
|
||||||
|
finally:
|
||||||
|
pass
|
||||||
|
|
||||||
# Get Date/Time from filename in case Pi gets behind
|
# Get Date/Time from filename in case Pi gets behind
|
||||||
# now = datetime.now()
|
# now = datetime.now()
|
||||||
full_file_name = args.i
|
full_file_name = args.i
|
||||||
# print('FULL FILENAME: -' + full_file_name + '-')
|
# print('FULL FILENAME: -' + full_file_name + '-')
|
||||||
file_name = Path(full_file_name).stem
|
file_name = Path(full_file_name).stem
|
||||||
|
|
||||||
|
# Get the RSTP stream identifier from the filename if it exists
|
||||||
|
RTSP_ident_for_fn = ""
|
||||||
|
RTSP_ident = re.search("RTSP_[0-9]+-", file_name)
|
||||||
|
if RTSP_ident is not None:
|
||||||
|
RTSP_ident_for_fn = RTSP_ident.group()
|
||||||
|
|
||||||
|
# Find and remove the identifier for the RSTP stream url it was from that is added when more than one
|
||||||
|
# RSTP stream is recorded simultaneously, in order to make the filenames unique as filenames are all
|
||||||
|
# generated at the same time
|
||||||
|
file_name = re.sub("RTSP_[0-9]+-", "", file_name)
|
||||||
|
|
||||||
|
# Now we can read the date and time as normal
|
||||||
|
# First portion of the filename contaning the date in Y m d
|
||||||
file_date = file_name.split('-birdnet-')[0]
|
file_date = file_name.split('-birdnet-')[0]
|
||||||
|
# Second portion of the filename containing the time in H:M:S
|
||||||
file_time = file_name.split('-birdnet-')[1]
|
file_time = file_name.split('-birdnet-')[1]
|
||||||
|
# Join the date and time together to get a complete string representing when the audio was recorded
|
||||||
date_time_str = file_date + ' ' + file_time
|
date_time_str = file_date + ' ' + file_time
|
||||||
date_time_obj = datetime.datetime.strptime(date_time_str, '%Y-%m-%d %H:%M:%S')
|
date_time_obj = datetime.datetime.strptime(date_time_str, '%Y-%m-%d %H:%M:%S')
|
||||||
# print('Date:', date_time_obj.date())
|
# print('Date:', date_time_obj.date())
|
||||||
@@ -463,7 +488,7 @@ def handle_client(conn, addr):
|
|||||||
Overlap = str(args.overlap)
|
Overlap = str(args.overlap)
|
||||||
Com_Name = Com_Name.replace("'", "")
|
Com_Name = Com_Name.replace("'", "")
|
||||||
File_Name = Com_Name.replace(" ", "_") + '-' + Confidence + '-' + \
|
File_Name = Com_Name.replace(" ", "_") + '-' + Confidence + '-' + \
|
||||||
Date.replace("/", "-") + '-birdnet-' + Time + audiofmt
|
Date.replace("/", "-") + '-birdnet-' + RTSP_ident_for_fn + Time + audiofmt
|
||||||
|
|
||||||
# Connect to SQLite Database
|
# Connect to SQLite Database
|
||||||
for attempt_number in range(3):
|
for attempt_number in range(3):
|
||||||
@@ -560,7 +585,7 @@ def handle_client(conn, addr):
|
|||||||
post_algorithm = "\"algorithm\": " + "\"2p2\"" + ","
|
post_algorithm = "\"algorithm\": " + "\"2p2\"" + ","
|
||||||
else:
|
else:
|
||||||
post_algorithm = "\"algorithm\": " + "\"alpha\"" + ","
|
post_algorithm = "\"algorithm\": " + "\"alpha\"" + ","
|
||||||
|
|
||||||
post_confidence = "\"confidence\": " + str(entry[1])
|
post_confidence = "\"confidence\": " + str(entry[1])
|
||||||
post_end = " }"
|
post_end = " }"
|
||||||
|
|
||||||
|
|||||||
+177
-11
@@ -1,30 +1,78 @@
|
|||||||
<?php
|
<?php
|
||||||
error_reporting(E_ERROR);
|
error_reporting(E_ERROR);
|
||||||
ini_set('display_errors',1);
|
ini_set('display_errors',1);
|
||||||
if(isset($_GET['ajax_csv'])) {
|
|
||||||
|
|
||||||
if (file_exists('./scripts/thisrun.txt')) {
|
if (file_exists('./scripts/thisrun.txt')) {
|
||||||
$config = parse_ini_file('./scripts/thisrun.txt');
|
$config = parse_ini_file('./scripts/thisrun.txt');
|
||||||
} 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(isset($_GET['ajax_csv'])) {
|
||||||
$RECS_DIR = $config["RECS_DIR"];
|
$RECS_DIR = $config["RECS_DIR"];
|
||||||
|
|
||||||
$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);
|
||||||
$files = scandir($RECS_DIR."/".date('F-Y')."/".date('d-l')."/", SCANDIR_SORT_ASCENDING);
|
|
||||||
|
//Replace variables to Fix up the file paths just in case the ENV environment variables don't resolve via PHP
|
||||||
|
$RECS_DIR = str_replace("\$HOME", $home, $RECS_DIR);
|
||||||
|
$STREAM_DATA_DIR = $RECS_DIR . "/StreamData/";
|
||||||
|
|
||||||
|
//Try find the latest file out of the soundcard recording folder
|
||||||
|
$look_in_directory = $RECS_DIR."/".date('F-Y')."/".date('d-l')."/";
|
||||||
|
$files = scandir($look_in_directory, SCANDIR_SORT_ASCENDING);
|
||||||
|
//Extract the filename, positions 0 and 1 are the folder hierarchy '.' and '..'
|
||||||
$newest_file = $files[2];
|
$newest_file = $files[2];
|
||||||
|
|
||||||
|
//Couldn't find under e.g /home/pi/April-2023/03-Monday/ (where USB audio streams are recorded
|
||||||
|
//look in the StreamData directory (RTSP streams are recorded here)
|
||||||
|
if (empty($files) || array_key_exists(2, $files) === false) {
|
||||||
|
$look_in_directory = $STREAM_DATA_DIR;
|
||||||
|
|
||||||
|
//Load the file in the directory
|
||||||
|
$files = scandir($look_in_directory, SCANDIR_SORT_ASCENDING);
|
||||||
|
|
||||||
|
//Because there might be more than 1 stream, we can't really assume the file at index 2 is the latest, or even for the stream being listened to
|
||||||
|
//Read the RTSP_STREAM_TO_LIVESTREAM setting, then try to find that CSV file
|
||||||
|
if(!empty($config['RTSP_STREAM_TO_LIVESTREAM']) && is_numeric($config['RTSP_STREAM_TO_LIVESTREAM'])){
|
||||||
|
//The stored setting of RTSP_STREAM_TO_LIVESTREAM is 0 based, but filenames are 1's based, so just add 1 to the config value
|
||||||
|
//so we can match up the stream the user is listening to with the appropriate filename
|
||||||
|
$RTSP_STREAM_LISTENED_TO = ($config['RTSP_STREAM_TO_LIVESTREAM'] + 1);
|
||||||
|
}else{
|
||||||
|
//Setting is invalid somehow
|
||||||
|
//The stored setting of RTSP_STREAM_TO_LIVESTREAM is 0 based, but filenames are 1's based, so just add 1 to the config value
|
||||||
|
//This will be the first stream
|
||||||
|
$RTSP_STREAM_LISTENED_TO = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//The RTSP streams contain 'RTSP_X' in the filename, were X is the stream url index in the comma separated list of RTSP streams
|
||||||
|
//We can use this to locate the file for this stream
|
||||||
|
foreach ($files as $file_idx => $stream_file_name) {
|
||||||
|
//Skip the folder hierarchy entries
|
||||||
|
if ($stream_file_name != "." && $stream_file_name != "..") {
|
||||||
|
//See if the filename contains the correct RTSP name, also only check .wav files by excluding the csv files with the filter .wav.csv
|
||||||
|
if (stripos($stream_file_name, 'RTSP_' . $RTSP_STREAM_LISTENED_TO) !== false && stripos($stream_file_name, '.wav.csv') === false) {
|
||||||
|
//Found a match - set it as the newest file
|
||||||
|
$newest_file = $stream_file_name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//If the newest file param has been supplied and it's the same as the newest file found
|
||||||
|
//then stop processing
|
||||||
if($newest_file == $_GET['newest_file']) {
|
if($newest_file == $_GET['newest_file']) {
|
||||||
die();
|
die();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Print out the filename
|
||||||
echo "file,".$newest_file."\n";
|
echo "file,".$newest_file."\n";
|
||||||
|
|
||||||
|
//Print out the detected birds as CSV
|
||||||
$row = 1;
|
$row = 1;
|
||||||
if (($handle = fopen($RECS_DIR."/".date('F-Y')."/".date('d-l')."/".$newest_file.".csv", "r")) !== FALSE) {
|
if (($handle = fopen($look_in_directory . $newest_file . ".csv", "r")) !== FALSE) {
|
||||||
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
|
while (($data = fgetcsv($handle, 1000, ",")) !== FALSE) {
|
||||||
if($row != 1){
|
if($row != 1){
|
||||||
$num = count($data);
|
$num = count($data);
|
||||||
@@ -37,8 +85,29 @@ if (($handle = fopen($RECS_DIR."/".date('F-Y')."/".date('d-l')."/".$newest_file.
|
|||||||
}
|
}
|
||||||
fclose($handle);
|
fclose($handle);
|
||||||
}
|
}
|
||||||
|
//Kill the script so no further processing or output is done
|
||||||
die();
|
die();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Hold the array of RTSP steams once they are exploded
|
||||||
|
$RTSP_Stream_Config = array();
|
||||||
|
|
||||||
|
//Load the birdnet config so we can read the RTSP setting
|
||||||
|
// Valid config data
|
||||||
|
if (is_array($config) && array_key_exists('RTSP_STREAM',$config)) {
|
||||||
|
if (is_null($config['RTSP_STREAM']) === false && $config['RTSP_STREAM'] !== "") {
|
||||||
|
$RTSP_Stream_Config_Data = explode(",", $config['RTSP_STREAM']);
|
||||||
|
|
||||||
|
//Process the stream further
|
||||||
|
//we need to able to ID it (just do this by position), get the hostname to show in the dropdown box
|
||||||
|
foreach ($RTSP_Stream_Config_Data as $stream_idx => $stream_url) {
|
||||||
|
//$stream_idx is the array position of the the RSP stream URL, idx of 0 is the first, 1 - second etc
|
||||||
|
$RTSP_stream_url = parse_url($stream_url);
|
||||||
|
$RTSP_Stream_Config[$stream_idx] = $RTSP_stream_url['host'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
<script>
|
<script>
|
||||||
// CREDITS: https://codepen.io/jakealbaugh/pen/jvQweW
|
// CREDITS: https://codepen.io/jakealbaugh/pen/jvQweW
|
||||||
@@ -139,21 +208,27 @@ function applyText(text,x,y,opacity) {
|
|||||||
|
|
||||||
var add =0;
|
var add =0;
|
||||||
var newest_file;
|
var newest_file;
|
||||||
|
var newest_file_tmp;
|
||||||
var lastbird;
|
var lastbird;
|
||||||
function loadDetectionIfNewExists() {
|
function loadDetectionIfNewExists() {
|
||||||
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")) {
|
if(this.responseText.length > 0 && !this.responseText.includes("Database")) {
|
||||||
|
// Case insensitive match for RTSP_X
|
||||||
|
var RTSP_regex = /RTSP_[0-9]+-/i;
|
||||||
|
var RTSP_regex_match = false;
|
||||||
var split = this.responseText.split("\n")
|
var split = this.responseText.split("\n")
|
||||||
for(var i = 1;i < split.length; i++) {
|
for(var i = 1;i < split.length; i++) {
|
||||||
if(parseInt(split[i].split(",")[0]) >= 0){
|
if(parseInt(split[i].split(",")[0]) >= 0){
|
||||||
|
|
||||||
newest_file = split[0].split(",")[1]
|
newest_file = split[0].split(",")[1]
|
||||||
|
newest_file_tmp = newest_file;//Copy the file name var so we something to work with
|
||||||
|
//Remove the string that denotes the RTSP stream from the filename to make things easier, it's not really needed
|
||||||
|
RTSP_regex_match = RTSP_regex.test(newest_file_tmp)
|
||||||
|
newest_file_tmp = newest_file_tmp.replace(RTSP_regex, "")
|
||||||
//applyText(split[i].split(",")[1],document.body.querySelector('canvas').width - ((parseInt(split[i].split(",")[0]))*avgfps), (document.body.querySelector('canvas').height * 0.50))
|
//applyText(split[i].split(",")[1],document.body.querySelector('canvas').width - ((parseInt(split[i].split(",")[0]))*avgfps), (document.body.querySelector('canvas').height * 0.50))
|
||||||
|
d1 = new Date(newest_file_tmp.split("-")[0]+"/"+newest_file_tmp.split("-")[1]+"/"+newest_file_tmp.split("-")[2]+ " "+newest_file_tmp.split("-")[4].replace(".wav",""))
|
||||||
d1 = new Date(newest_file.split("-")[0]+"/"+newest_file.split("-")[1]+"/"+newest_file.split("-")[2]+ " "+newest_file.split("-")[4].replace(".wav",""))
|
|
||||||
console.log("d1 "+d1)
|
console.log("d1 "+d1)
|
||||||
d2 = new Date(xhttp.getResponseHeader("Date"));
|
d2 = new Date(xhttp.getResponseHeader("Date"));
|
||||||
console.log("d2 "+d2)
|
console.log("d2 "+d2)
|
||||||
@@ -173,7 +248,13 @@ function loadDetectionIfNewExists() {
|
|||||||
console.log(add)
|
console.log(add)
|
||||||
|
|
||||||
// Date csv file was created + relative detection time of bird + mic delay
|
// Date csv file was created + relative detection time of bird + mic delay
|
||||||
secago = Math.abs(timeDiff) - split[i].split(",")[0] - 6.8;
|
//If we can't find the regex in the filename, then the RTSP_X string doesn't exist, unlikely to be a RTSP stream
|
||||||
|
if (RTSP_regex_match == false){
|
||||||
|
secago = (Math.abs(timeDiff) - split[i].split(",")[0]) - 6.8;
|
||||||
|
}else{
|
||||||
|
//half the delay for RTSP streams ~ just a rough guess
|
||||||
|
secago = (Math.abs(timeDiff) - split[i].split(",")[0]) - 4;
|
||||||
|
}
|
||||||
|
|
||||||
x = document.body.querySelector('canvas').width - ((parseInt(secago))*avgfps);
|
x = document.body.querySelector('canvas').width - ((parseInt(secago))*avgfps);
|
||||||
// if the text is too close to the right side of the canvas and will be cut off, wait 3 seconds before adding text
|
// if the text is too close to the right side of the canvas and will be cut off, wait 3 seconds before adding text
|
||||||
@@ -340,6 +421,46 @@ h1 {
|
|||||||
<img id="spectrogramimage" style="width:100%;height:100%;display:none" src="/spectrogram.png?nocache=<?php echo $time;?>">
|
<img id="spectrogramimage" style="width:100%;height:100%;display:none" src="/spectrogram.png?nocache=<?php echo $time;?>">
|
||||||
|
|
||||||
<div class="centered">
|
<div class="centered">
|
||||||
|
<?php
|
||||||
|
if (isset($RTSP_Stream_Config) && !empty($RTSP_Stream_Config)) {
|
||||||
|
?>
|
||||||
|
<div style="display:inline" id="RTSP_streams">
|
||||||
|
<label>RTSP Stream: </label>
|
||||||
|
<select id="rtsp_stream_select" name="RTSP Streams">
|
||||||
|
<?php
|
||||||
|
//The setting representing which livestream to stream is more than the number of RTSP streams available
|
||||||
|
//maybe the list of streams has been modified
|
||||||
|
//This isn't the ideal for this, but needed a way to fix this setting without calling the advanced setting page
|
||||||
|
if (array_key_exists($config['RTSP_STREAM_TO_LIVESTREAM'], $RTSP_Stream_Config) === false) {
|
||||||
|
$contents = file_get_contents('/etc/birdnet/birdnet.conf');
|
||||||
|
$contents2 = file_get_contents('./scripts/thisrun.txt');
|
||||||
|
$contents = preg_replace("/RTSP_STREAM_TO_LIVESTREAM=.*/", "RTSP_STREAM_TO_LIVESTREAM=\"0\"", $contents);
|
||||||
|
$contents2 = preg_replace("/RTSP_STREAM_TO_LIVESTREAM=.*/", "RTSP_STREAM_TO_LIVESTREAM=\"0\"", $contents2);
|
||||||
|
$fh = fopen("/etc/birdnet/birdnet.conf", "w");
|
||||||
|
$fh2 = fopen("./scripts/thisrun.txt", "w");
|
||||||
|
fwrite($fh, $contents);
|
||||||
|
fwrite($fh2, $contents2);
|
||||||
|
exec("sudo systemctl restart livestream.service");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Print out the dropdown list for the RTSP streams
|
||||||
|
foreach ($RTSP_Stream_Config as $stream_id => $stream_host) {
|
||||||
|
$isSelected = "";
|
||||||
|
//Match up the selected value saved in config so we can preselect it
|
||||||
|
if ($config['RTSP_STREAM_TO_LIVESTREAM'] == $stream_id) {
|
||||||
|
$isSelected = 'selected="selected"';
|
||||||
|
}
|
||||||
|
//Create the select option
|
||||||
|
echo "<option value=" . $stream_id . " $isSelected >" . $stream_host . "</option>";
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
—
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
?>
|
||||||
<div style="display:inline" id="gain" >
|
<div style="display:inline" id="gain" >
|
||||||
<label>Gain: </label>
|
<label>Gain: </label>
|
||||||
<span class="slidecontainer">
|
<span class="slidecontainer">
|
||||||
@@ -347,7 +468,7 @@ h1 {
|
|||||||
<span id="gain_value"></span>%
|
<span id="gain_value"></span>%
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
—
|
—
|
||||||
<div style="display:inline" id="comp" >
|
<div style="display:inline" id="comp" >
|
||||||
<label>Compression: </label>
|
<label>Compression: </label>
|
||||||
<input name="compression" type="checkbox" id="compression" disabled>
|
<input name="compression" type="checkbox" id="compression" disabled>
|
||||||
@@ -355,10 +476,55 @@ h1 {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<audio style="display:none" controls="" crossorigin="anonymous" id='player' preload="none"><source id="playersrc" src="/stream"></audio>
|
<audio style="display:none" controls="" crossorigin="anonymous" id='player' preload="none"><source id="playersrc" src="/stream"></audio>
|
||||||
<h1>Loading...</h1>
|
<h1 id="loading-h1">Loading...</h1>
|
||||||
<canvas></canvas>
|
<canvas></canvas>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
var rtsp_stream_select = document.getElementById("rtsp_stream_select");
|
||||||
|
//When the dropdown selection is changed set the new value is settings, then restart the livestream service so it broadcasts newly selected RTSP stream
|
||||||
|
rtsp_stream_select.onchange = function() {
|
||||||
|
if (this.value !== 'undefined'){
|
||||||
|
// Get the audio player element
|
||||||
|
var audio_player = document.querySelector('audio#player');
|
||||||
|
var central_controls_element = document.getElementsByClassName('centered')[0];
|
||||||
|
|
||||||
|
//Create the loading header again as a placeholder while we're waiting to reload the stream
|
||||||
|
var h1_loading = document.createElement("H1");
|
||||||
|
var h1_loading_text = document.createTextNode("Loading...");
|
||||||
|
h1_loading.setAttribute("id","loading-h1");
|
||||||
|
h1_loading.setAttribute("style","font-size:48px; font-weight: bolder; color: #FFF");
|
||||||
|
h1_loading.appendChild(h1_loading_text);
|
||||||
|
|
||||||
|
// Create the XMLHttpRequest object.
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
// Initialize the request
|
||||||
|
xhr.open("GET", './views.php?rtsp_stream_to_livestream='+ this.value +'&view=Advanced&submit=advanced');
|
||||||
|
// Send the request
|
||||||
|
xhr.send();
|
||||||
|
// Fired once the request completes successfully
|
||||||
|
xhr.onload = function(e) {
|
||||||
|
// Check if the request was a success
|
||||||
|
if (this.readyState === XMLHttpRequest.DONE && this.status === 200) {
|
||||||
|
// Restart the audio player in case it stopped working while the livestream service was restarted
|
||||||
|
if(audio_player !== 'undefined'){
|
||||||
|
central_controls_element.appendChild(h1_loading);
|
||||||
|
//Wait 5 seconds before restarting the stream
|
||||||
|
setTimeout(function () {
|
||||||
|
audio_player.pause();
|
||||||
|
audio_player.setAttribute('src', '/stream');
|
||||||
|
audio_player.load();
|
||||||
|
audio_player.play();
|
||||||
|
|
||||||
|
document.getElementById('loading-h1').remove()
|
||||||
|
},
|
||||||
|
10000
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var slider = document.getElementById("gain_input");
|
var slider = document.getElementById("gain_input");
|
||||||
var output = document.getElementById("gain_value");
|
var output = document.getElementById("gain_value");
|
||||||
output.innerHTML = slider.value; // Display the default slider value
|
output.innerHTML = slider.value; // Display the default slider value
|
||||||
|
|||||||
@@ -2,5 +2,7 @@
|
|||||||
# Make sox spectrogram
|
# Make sox spectrogram
|
||||||
source /etc/birdnet/birdnet.conf
|
source /etc/birdnet/birdnet.conf
|
||||||
analyzing_now="$(cat $HOME/BirdNET-Pi/analyzing_now.txt)"
|
analyzing_now="$(cat $HOME/BirdNET-Pi/analyzing_now.txt)"
|
||||||
spectrogram_png=${EXTRACTED}/spectrogram.png
|
if [ ! -z "${analyzing_now}" ] && [ -f "${analyzing_now}" ]; then
|
||||||
sox -V1 "${analyzing_now}" -n remix 1 rate 24k spectrogram -c "${analyzing_now//$HOME\/}" -o "${spectrogram_png}"
|
spectrogram_png=${EXTRACTED}/spectrogram.png
|
||||||
|
sox -V1 "${analyzing_now}" -n remix 1 rate 24k spectrogram -c "${analyzing_now//$HOME\/}" -o "${spectrogram_png}"
|
||||||
|
fi
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) {
|
|||||||
$_SESSION['images'] = [];
|
$_SESSION['images'] = [];
|
||||||
}
|
}
|
||||||
$iterations = 0;
|
$iterations = 0;
|
||||||
$lines;
|
$lines=null;
|
||||||
$licenses_urls = array();
|
$licenses_urls = array();
|
||||||
|
|
||||||
if (file_exists('./scripts/thisrun.txt')) {
|
if (file_exists('./scripts/thisrun.txt')) {
|
||||||
@@ -324,7 +324,8 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) {
|
|||||||
</td>
|
</td>
|
||||||
<?php } else { //legacy mode ?>
|
<?php } else { //legacy mode ?>
|
||||||
<tr class="relative" id="<?php echo $iterations; ?>">
|
<tr class="relative" id="<?php echo $iterations; ?>">
|
||||||
<td><?php if($_GET['kiosk'] == true) { echo relativeTime(strtotime($todaytable['Time'])); } else {echo $todaytable['Time'];}?><br></td><td id="recent_detection_middle_td">
|
<td><?php if($_GET['kiosk'] == true) { echo relativeTime(strtotime($todaytable['Time'])); } else {echo $todaytable['Time'];}?><br></td>
|
||||||
|
<td id="recent_detection_middle_td">
|
||||||
<div>
|
<div>
|
||||||
<div>
|
<div>
|
||||||
<?php if(!empty($config["FLICKR_API_KEY"]) && (isset($_GET['hard_limit']) || $_GET['kiosk'] == true) && strlen($image[2]) > 0) { ?>
|
<?php if(!empty($config["FLICKR_API_KEY"]) && (isset($_GET['hard_limit']) || $_GET['kiosk'] == true) && strlen($image[2]) > 0) { ?>
|
||||||
@@ -332,14 +333,31 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) {
|
|||||||
<?php } ?>
|
<?php } ?>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<b><a class="a2" <?php if($_GET['kiosk'] == false){?>href="https://allaboutbirds.org/guide/<?php echo $comname;?>"<?php } else {echo "style='color:blue;'";} ?> target="top"><?php echo $todaytable['Com_Name'];?></a></b> <img style="height: 1em;cursor:pointer;float:unset;display:inline" title="View species stats" onclick="generateMiniGraph(this, '<?php echo $comname; ?>')" width=25 src="images/chart.svg"><br>
|
<b><a class="a2" <?php if($_GET['kiosk'] == false){?>href="https://allaboutbirds.org/guide/<?php echo $comname;?>"<?php } else {echo "style='color:blue;'";} ?> target="top"><?php echo $todaytable['Com_Name'];?></a></b>
|
||||||
<a class="a2" <?php if($_GET['kiosk'] == false){?>href="https://wikipedia.org/wiki/<?php echo $sciname;?>"<?php } else {echo "style='color:blue;'";} ?> target="top"><i><?php echo $todaytable['Sci_Name'];?></i></a><br></td>
|
<?php
|
||||||
</div></div>
|
//If on mobile, add in a icon to link off to the recording so the user can see more info
|
||||||
|
if (isset($_GET['mobile'])) {
|
||||||
|
?>
|
||||||
|
<br>
|
||||||
|
<img style="height: 1em;cursor:pointer;float:unset;display:inline" title="View species stats" onclick="generateMiniGraph(this, '<?php echo $comname; ?>')" width=25 src="images/chart.svg">
|
||||||
|
<a target="_blank" href="index.php?filename=<?php echo $todaytable['File_Name']; ?>"><img style="height: 1em;cursor:pointer;float:unset;display:inline" class="copyimage-mobile" title="Open in new tab" width=16 src="images/copy.png"></a>'
|
||||||
|
<?php
|
||||||
|
}else{
|
||||||
|
//Else just put the species stats icon
|
||||||
|
?>
|
||||||
|
<img style="height: 1em;cursor:pointer;float:unset;display:inline" title="View species stats" onclick="generateMiniGraph(this, '<?php echo $comname; ?>')" width=25 src="images/chart.svg">
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<br>
|
||||||
|
<a class="a2" <?php if($_GET['kiosk'] == false){?>href="https://wikipedia.org/wiki/<?php echo $sciname;?>"<?php } else {echo "style='color:blue;'";} ?> target="top"><i><?php echo $todaytable['Sci_Name'];?></i></a><br>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
<td><b>Confidence:</b> <?php echo round((float)round($todaytable['Confidence'],2) * 100 ) . '%';?><br></td>
|
<td><b>Confidence:</b> <?php echo round((float)round($todaytable['Confidence'],2) * 100 ) . '%';?><br></td>
|
||||||
<?php if(!isset($_GET['mobile'])) { ?>
|
<?php if(!isset($_GET['mobile'])) { ?>
|
||||||
<td style="min-width:180px"><audio controls preload="none" title="<?php echo $filename;?>"><source preload="none" src="<?php echo $filename;?>"></video>
|
<td style="min-width:180px"><audio controls preload="none" title="<?php echo $filename;?>"><source preload="none" src="<?php echo $filename;?>"></audio></td>
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
</td>
|
|
||||||
<?php } ?>
|
<?php } ?>
|
||||||
<?php }?>
|
<?php }?>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
Executable → Regular
+4
-1
@@ -41,6 +41,9 @@ sudo_with_user () {
|
|||||||
set +x
|
set +x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Get current HEAD hash
|
||||||
|
commit_hash=$(sudo_with_user git -C $HOME/BirdNET-Pi rev-parse HEAD)
|
||||||
|
|
||||||
# Reset current HEAD to remove any local changes
|
# Reset current HEAD to remove any local changes
|
||||||
sudo_with_user git -C $HOME/BirdNET-Pi reset --hard
|
sudo_with_user git -C $HOME/BirdNET-Pi reset --hard
|
||||||
|
|
||||||
@@ -51,7 +54,7 @@ sudo_with_user git -C $HOME/BirdNET-Pi fetch $remote $branch
|
|||||||
sudo_with_user git -C $HOME/BirdNET-Pi switch -C $branch --track $remote/$branch
|
sudo_with_user git -C $HOME/BirdNET-Pi switch -C $branch --track $remote/$branch
|
||||||
|
|
||||||
# Prints out changes
|
# Prints out changes
|
||||||
sudo_with_user git -C $HOME/BirdNET-Pi diff --stat HEAD^ HEAD
|
sudo_with_user git -C $HOME/BirdNET-Pi diff --stat $commit_hash HEAD
|
||||||
|
|
||||||
sudo systemctl daemon-reload
|
sudo systemctl daemon-reload
|
||||||
sudo ln -sf $my_dir/* /usr/local/bin/
|
sudo ln -sf $my_dir/* /usr/local/bin/
|
||||||
|
|||||||
@@ -188,6 +188,10 @@ if ! grep APPRISE_ONLY_NOTIFY_SPECIES_NAMES /etc/birdnet/birdnet.conf &>/dev/nul
|
|||||||
sudo -u$USER echo "APPRISE_ONLY_NOTIFY_SPECIES_NAMES=\"\"" >> /etc/birdnet/birdnet.conf
|
sudo -u$USER echo "APPRISE_ONLY_NOTIFY_SPECIES_NAMES=\"\"" >> /etc/birdnet/birdnet.conf
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if ! grep RTSP_STREAM_TO_LIVESTREAM /etc/birdnet/birdnet.conf &>/dev/null;then
|
||||||
|
sudo -u$USER echo "RTSP_STREAM_TO_LIVESTREAM=\"0\"" >> /etc/birdnet/birdnet.conf
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
sudo systemctl daemon-reload
|
sudo systemctl daemon-reload
|
||||||
restart_services.sh
|
restart_services.sh
|
||||||
|
|||||||
Reference in New Issue
Block a user