@@ -60,7 +60,12 @@ RTSP_STREAM=
|
||||
|
||||
APPRISE_NOTIFICATION_TITLE="New BirdNET-Pi Detection"
|
||||
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_API_KEY=
|
||||
|
||||
################################################################################
|
||||
#-------------------------------- Defaults ----------------------------------#
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
@@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 330 330" style="enable-background:new 0 0 330 330;" xml:space="preserve">
|
||||
<g id="XMLID_504_">
|
||||
<path id="XMLID_505_" d="M65,330h200c8.284,0,15-6.716,15-15V145c0-8.284-6.716-15-15-15h-15V85c0-46.869-38.131-85-85-85
|
||||
S80,38.131,80,85v45H65c-8.284,0-15,6.716-15,15v170C50,323.284,56.716,330,65,330z M207.481,219.356l-42.5,42.5
|
||||
c-2.929,2.929-6.768,4.394-10.606,4.394s-7.678-1.465-10.606-4.394l-21.25-21.25c-5.858-5.858-5.858-15.354,0-21.213
|
||||
c5.857-5.858,15.355-5.858,21.213,0l10.644,10.643l31.894-31.893c5.857-5.858,15.355-5.858,21.213,0
|
||||
C213.34,204.002,213.34,213.498,207.481,219.356z M110,85c0-30.327,24.673-55,55-55s55,24.673,55,55v45H110V85z"/>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 466.008 466.008" style="enable-background:new 0 0 466.008 466.008;" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<path d="M233.004,0C104.224,0,0,104.212,0,233.004c0,128.781,104.212,233.004,233.004,233.004
|
||||
c128.782,0,233.004-104.212,233.004-233.004C466.008,104.222,361.796,0,233.004,0z M244.484,242.659l-63.512,75.511
|
||||
c-5.333,6.34-14.797,7.156-21.135,1.824c-6.34-5.333-7.157-14.795-1.824-21.135l59.991-71.325V58.028c0-8.284,6.716-15,15-15
|
||||
s15,6.716,15,15v174.976h0C248.004,236.536,246.757,239.956,244.484,242.659z"/>
|
||||
</g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 946 B |
@@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 330 330" style="enable-background:new 0 0 330 330;" xml:space="preserve">
|
||||
<g id="XMLID_516_">
|
||||
<path id="XMLID_517_" d="M15,160c8.284,0,15-6.716,15-15V85c0-30.327,24.673-55,55-55c30.327,0,55,24.673,55,55v45h-25
|
||||
c-8.284,0-15,6.716-15,15v170c0,8.284,6.716,15,15,15h200c8.284,0,15-6.716,15-15V145c0-8.284-6.716-15-15-15H170V85
|
||||
c0-46.869-38.131-85-85-85S0,38.131,0,85v60C0,153.284,6.716,160,15,160z"/>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
<g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 829 B |
+4
-4
@@ -5,7 +5,7 @@ body::-webkit-scrollbar {
|
||||
display:none
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
<link rel="stylesheet" href="style.css?v=14">
|
||||
<body>
|
||||
<div class="banner">
|
||||
<div class="logo">
|
||||
@@ -36,7 +36,7 @@ if(isset($_GET['stream'])){
|
||||
echo "
|
||||
<audio controls autoplay><source src=\"/stream\"></audio>
|
||||
</div>
|
||||
<h1><a href=\"/\">BirdNET-Pi</a></h1>
|
||||
<h1><a href=\"/\"><img class=\"topimage\" src=\"images/bnp.png\"></a></h1>
|
||||
</div>";
|
||||
} else {
|
||||
header('WWW-Authenticate: Basic realm="My Realm"');
|
||||
@@ -46,12 +46,12 @@ if(isset($_GET['stream'])){
|
||||
}
|
||||
}
|
||||
} else {
|
||||
echo "
|
||||
echo "
|
||||
<form action=\"\" method=\"GET\">
|
||||
<button type=\"submit\" name=\"stream\" value=\"play\">Live Audio</button>
|
||||
</form>
|
||||
</div>
|
||||
<h1><a href=\"/\">BirdNET-Pi</a></h1>
|
||||
<h1><a href=\"/\"><img class=\"topimage\" src=\"images/bnp.png\"></a></h1>
|
||||
</div>";
|
||||
}
|
||||
if(isset($_GET['filename'])) {
|
||||
|
||||
Binary file not shown.
+116
-12
@@ -1,6 +1,10 @@
|
||||
@font-face {
|
||||
font-family: 'Roboto Flex' ;
|
||||
src: url('static/RobotoFlex-Regular.ttf') format('truetype');
|
||||
}
|
||||
|
||||
* {
|
||||
font-family: 'Arial', 'Gill Sans', 'Gill Sans MT',
|
||||
' Calibri', 'Trebuchet MS', 'sans-serif';
|
||||
font-family: 'Roboto Flex', sans-serif;
|
||||
box-sizing: border-box;
|
||||
font-size: medium;
|
||||
}
|
||||
@@ -37,6 +41,9 @@ table {
|
||||
border-spacing: 0;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
box-shadow: 0px 0px 17px 1px rgba(0, 0, 0, 0.10);
|
||||
border-radius:3px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
td {
|
||||
@@ -44,7 +51,6 @@ td {
|
||||
vertical-align: top;
|
||||
background-color: rgb(219, 255, 235);
|
||||
font-weight: lighter;
|
||||
border: 2px solid black;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -64,11 +70,16 @@ label {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
hr {
|
||||
border-color:black;
|
||||
}
|
||||
|
||||
button {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
color: black;
|
||||
cursor: pointer;
|
||||
transition:background-color 0.2s;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
@@ -132,6 +143,13 @@ button:hover {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-bottom: 15px;
|
||||
box-shadow: 0px 0px 28px 1px rgba(0, 0, 0, 0.10); !important;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.topimage {
|
||||
width:175px;
|
||||
display:initial !important;
|
||||
}
|
||||
|
||||
.topnav form {
|
||||
@@ -173,12 +191,11 @@ button:hover {
|
||||
}
|
||||
|
||||
.stats table {
|
||||
width: 75%;
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
.overview th {
|
||||
background-color: rgb(219, 255, 235);
|
||||
border: 2px solid black;
|
||||
text-align: center;
|
||||
padding: 12px;
|
||||
}
|
||||
@@ -238,14 +255,16 @@ button:hover {
|
||||
}
|
||||
|
||||
.views .centered button {
|
||||
border: 2px solid black;
|
||||
background-color: rgb(219, 255, 235);
|
||||
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 {
|
||||
background-color: rgb(159, 226, 155);
|
||||
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 {
|
||||
@@ -257,7 +276,6 @@ button:hover {
|
||||
}
|
||||
|
||||
.settings button {
|
||||
border: 2px solid black;
|
||||
background-color: rgb(219, 255, 235);
|
||||
padding: 12px;
|
||||
}
|
||||
@@ -284,7 +302,7 @@ button:hover {
|
||||
.customlabels button,.customlabels2 button {
|
||||
padding: 12px;
|
||||
background-color: rgb(219, 255, 235);
|
||||
border: 2px solid black;
|
||||
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -339,7 +357,7 @@ button:hover {
|
||||
}
|
||||
|
||||
.systemcontrols button,.servicecontrols button {
|
||||
border: 2px solid black;
|
||||
|
||||
background-color: rgb(219, 255, 235);
|
||||
padding: 12px;
|
||||
width: 50%;
|
||||
@@ -541,7 +559,7 @@ button:hover {
|
||||
font-size:x-large;
|
||||
background:#dbffeb;
|
||||
padding:5px;
|
||||
border: 2px solid black;
|
||||
box-shadow: 0px 0px 5px 2px rgba(0, 0, 0, 0.10);
|
||||
}
|
||||
button.legacyview {
|
||||
color:gray;
|
||||
@@ -552,12 +570,98 @@ button.legacyview {
|
||||
font-size:small;
|
||||
background:#dbffeb;
|
||||
padding:5px;
|
||||
border: 2px solid black;
|
||||
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 {
|
||||
margin-top:10px;
|
||||
font-size:x-large;
|
||||
background:#dbffeb;
|
||||
padding:10px;
|
||||
border: 2px solid black;
|
||||
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 {
|
||||
background-color:#9fe29b;
|
||||
}
|
||||
.history.centered form {
|
||||
display:flex;
|
||||
justify-content: center;
|
||||
}
|
||||
.history.centered input {
|
||||
margin-right:5px;
|
||||
border:0px;
|
||||
}
|
||||
.centered form#views button {
|
||||
box-shadow: 0px 0px 5px 2px rgba(0, 0, 0, 0.10);
|
||||
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 {
|
||||
box-shadow: 0px 0px 17px 1px rgba(0, 0, 0, 0.10);
|
||||
}
|
||||
dialog {
|
||||
border:none;
|
||||
}
|
||||
dialog::backdrop {
|
||||
background: repeating-linear-gradient(
|
||||
30deg,
|
||||
rgba(24, 194, 236, 0.2),
|
||||
rgba(24, 194, 236, 0.2) 1px,
|
||||
rgba(24, 194, 236, 0.3) 1px,
|
||||
rgba(24, 194, 236, 0.3) 20px
|
||||
);
|
||||
backdrop-filter: blur(1px)
|
||||
}
|
||||
.centered_image_container {
|
||||
font-size:19px !important;
|
||||
display:inline-block;
|
||||
position:relative;
|
||||
margin-bottom:3px;
|
||||
}
|
||||
.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;
|
||||
height:95%;
|
||||
position:absolute;
|
||||
right:110%;
|
||||
top:0px;
|
||||
border-radius: 5px;
|
||||
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 * {
|
||||
font-size:19px !important;
|
||||
}
|
||||
.centered_image_container form {
|
||||
margin-bottom:0px;
|
||||
}
|
||||
.brbanner {
|
||||
padding:15px;
|
||||
background-color:rgb(159, 226, 155);
|
||||
text-align:center;
|
||||
font-size:large;
|
||||
}
|
||||
+110
-42
@@ -37,16 +37,27 @@ body::-webkit-scrollbar {
|
||||
</div>
|
||||
|
||||
<script>
|
||||
var topbuttons = document.querySelectorAll("button[form='views']");
|
||||
if(window.location.search.substr(1) != '') {
|
||||
for (var i = 0; i < topbuttons.length; i++) {
|
||||
if(topbuttons[i].value == decodeURIComponent(window.location.search.substr(1)).replace(/\+/g,' ').split('=').pop()) {
|
||||
topbuttons[i].classList.add("button-hover");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
topbuttons[0].classList.add("button-hover");
|
||||
var topbuttons = document.querySelectorAll("button[form='views']");
|
||||
if(window.location.search.substr(1) != '') {
|
||||
for (var i = 0; i < topbuttons.length; i++) {
|
||||
if(topbuttons[i].value == decodeURIComponent(window.location.search.substr(1)).replace(/\+/g,' ').split('=').pop()) {
|
||||
topbuttons[i].classList.add("button-hover");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
topbuttons[0].classList.add("button-hover");
|
||||
}
|
||||
function copyOutput(elem) {
|
||||
elem.innerHTML = 'Copied!';
|
||||
const copyText = document.getElementsByTagName("pre")[0].textContent;
|
||||
const textArea = document.createElement('textarea');
|
||||
textArea.style.position = 'absolute';
|
||||
textArea.style.left = '-100%';
|
||||
textArea.textContent = copyText;
|
||||
document.body.append(textArea);
|
||||
textArea.select();
|
||||
document.execCommand("copy");
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="views">
|
||||
@@ -59,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'] == "Overview"){include('overview.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'] == "Daily Charts"){include('history.php');}
|
||||
if($_GET['view'] == "Tools"){
|
||||
@@ -80,18 +91,18 @@ if(isset($_GET['view'])){
|
||||
if($submittedpwd == $caddypwd && $submitteduser == 'birdnet'){
|
||||
$url = $_SERVER['SERVER_NAME']."/scripts/adminer.php";
|
||||
echo "<div class=\"centered\">
|
||||
<form action=\"\" method=\"GET\" id=\"views\">
|
||||
<button type=\"submit\" name=\"view\" value=\"Settings\" form=\"views\">Settings</button>
|
||||
<button type=\"submit\" name=\"view\" value=\"System Info\" form=\"views\">System Info</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=\"File\" form=\"views\">File Manager</button>
|
||||
<a href=\"scripts/adminer.php\" target=\"_top\"><button type=\"submit\" form=\"\">Database Maintenanace</button></a>
|
||||
<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=\"Excluded\" form=\"views\">Excluded Species List</button>
|
||||
</form>
|
||||
</div>";
|
||||
<form action=\"\" method=\"GET\" id=\"views\">
|
||||
<button type=\"submit\" name=\"view\" value=\"Settings\" form=\"views\">Settings</button>
|
||||
<button type=\"submit\" name=\"view\" value=\"System Info\" form=\"views\">System Info</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=\"File\" form=\"views\">File Manager</button>
|
||||
<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=\"Included\" form=\"views\">Custom Species List</button>
|
||||
<button type=\"submit\" name=\"view\" value=\"Excluded\" form=\"views\">Excluded Species List</button>
|
||||
</form>
|
||||
</div>";
|
||||
} else {
|
||||
header('WWW-Authenticate: Basic realm="My Realm"');
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
@@ -175,7 +186,7 @@ if(isset($_GET['view'])){
|
||||
$submitteduser = $_SERVER['PHP_AUTH_USER'];
|
||||
if($submittedpwd == $caddypwd && $submitteduser == 'birdnet'){
|
||||
#ACCESS THE WEB TERMINAL
|
||||
echo "<iframe src='/terminal'></iframe>";
|
||||
echo "<iframe src='/terminal'></iframe>";
|
||||
} else {
|
||||
header('WWW-Authenticate: Basic realm="My Realm"');
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
@@ -185,25 +196,82 @@ if(isset($_GET['view'])){
|
||||
}
|
||||
}
|
||||
} elseif(isset($_GET['submit'])) {
|
||||
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');
|
||||
}
|
||||
$caddypwd = $config['CADDY_PWD'];
|
||||
if (!isset($_SERVER['PHP_AUTH_USER'])) {
|
||||
header('WWW-Authenticate: Basic realm="My Realm"');
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
echo 'You cannot access the web terminal';
|
||||
exit;
|
||||
} else {
|
||||
$submittedpwd = $_SERVER['PHP_AUTH_PW'];
|
||||
$submitteduser = $_SERVER['PHP_AUTH_USER'];
|
||||
if($submittedpwd == $caddypwd && $submitteduser == 'birdnet'){
|
||||
$command = $_GET['submit'];
|
||||
if(isset($command)){
|
||||
$results = shell_exec("$command 2>&1");
|
||||
echo "<pre>$results</pre>";
|
||||
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');
|
||||
}
|
||||
$caddypwd = $config['CADDY_PWD'];
|
||||
if (!isset($_SERVER['PHP_AUTH_USER'])) {
|
||||
header('WWW-Authenticate: Basic realm="My Realm"');
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
echo 'You cannot access the web terminal';
|
||||
exit;
|
||||
} else {
|
||||
$submittedpwd = $_SERVER['PHP_AUTH_PW'];
|
||||
$submitteduser = $_SERVER['PHP_AUTH_USER'];
|
||||
$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'];
|
||||
if($submittedpwd == $caddypwd && $submitteduser == 'birdnet' && in_array($command,$allowedCommands)){
|
||||
if(isset($command)){
|
||||
$initcommand = $command;
|
||||
if (strpos($command, "systemctl") !== false) {
|
||||
$tmp = explode(" ",trim($command));
|
||||
$command .= "& sleep 3;sudo systemctl status ".end($tmp);
|
||||
}
|
||||
$results = shell_exec("$command 2>&1");
|
||||
$results = str_replace("FAILURE", "<span style='color:red'>FAILURE</span>", $results);
|
||||
$results = str_replace("failed", "<span style='color:red'>failed</span>",$results);
|
||||
$results = str_replace("active (running)", "<span style='color:green'><b>active (running)</b></span>",$results);
|
||||
if(strlen($results) == 0) {
|
||||
$results = "This command has no output.";
|
||||
}
|
||||
echo "<table style='min-width:70%;'><tr class='relative'><th>Output of command:`".$initcommand."`<button class='copyimage' style='right:40px' onclick='copyOutput(this);'>Copy</button></th></tr><tr><td><pre style='text-align:left'>$results</pre></td></tr></table>";
|
||||
} else {
|
||||
header('WWW-Authenticate: Basic realm="My Realm"');
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
|
||||
@@ -204,7 +204,7 @@ if (file_exists('./scripts/thisrun.txt')) {
|
||||
<input name="full_disk" type="radio" id="purge" value="purge" <?php if (strcmp($newconfig['FULL_DISK'], "purge") == 0) { echo "checked"; }?>>Purge</label>
|
||||
<label for="keep">
|
||||
<input name="full_disk" type="radio" id="keep" value="keep" <?php if (strcmp($newconfig['FULL_DISK'], "keep") == 0) { echo "checked"; }?>>Keep</label>
|
||||
<p>When the disk becomes full, you can choose to 'purge' old files to make room for new ones or 'keep' your data and stop all services instead.</p>
|
||||
<p>When the disk becomes full, you can choose to 'purge' old files to make room for new ones or 'keep' your data and stop all services instead.<br>Note: you can exclude specific files from 'purge' on the Recordings page.</p>
|
||||
<label for="rec_card">Audio Card: </label>
|
||||
<input name="rec_card" type="text" value="<?php print($newconfig['REC_CARD']);?>" required/><br>
|
||||
<p>Set Audio Card to 'default' to use PulseAudio (always recommended), or an ALSA recognized sound card device from the output of `aplay -L`.</p>
|
||||
|
||||
@@ -20,11 +20,13 @@ make_thisrun() {
|
||||
make_thisrun &> /dev/null
|
||||
if ! diff ${LAST_RUN} ${THIS_RUN};then
|
||||
echo "The birdnet.conf file has changed"
|
||||
echo "Reloading services"
|
||||
if grep REC <(diff $LAST_RUN $THIS_RUN);then
|
||||
echo "Recording element changed -- restarting 'birdnet_recording.service'"
|
||||
sudo systemctl stop birdnet_recording.service
|
||||
sudo rm -rf ${RECS_DIR}/$(date +%B-%Y/%d-%A)/*
|
||||
sudo systemctl start birdnet_recording.service
|
||||
fi
|
||||
cat ${THIS_RUN} > ${LAST_RUN}
|
||||
sudo systemctl stop birdnet_recording.service
|
||||
sudo rm -rf ${RECS_DIR}/$(date +%B-%Y/%d-%A)/*
|
||||
sudo systemctl start birdnet_recording.service
|
||||
fi
|
||||
|
||||
INCLUDE_LIST="$HOME/BirdNET-Pi/include_species_list.txt"
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#!/usr/bin/env bash
|
||||
journalctl --no-hostname -q -o short -fu birdnet_analysis -ubirdnet_server -uextraction | sed "s/$(date "+%b %d ")//g;s/${HOME//\//\\/}\///g"
|
||||
journalctl --no-hostname -q -o short -fu birdnet_analysis -ubirdnet_server -uextraction | sed "s/$(date "+%b %d ")//g;s/${HOME//\//\\/}\///g;/Line/d;/systemd/d;s/ .*\[.*\]: /---/"
|
||||
|
||||
+16
-6
@@ -10,15 +10,16 @@ $birdweather_id = $_GET["birdweather_id"];
|
||||
$apprise_input = $_GET['apprise_input'];
|
||||
$apprise_notification_title = $_GET['apprise_notification_title'];
|
||||
$apprise_notification_body = $_GET['apprise_notification_body'];
|
||||
$flickr_api_key = $_GET['flickr_api_key'];
|
||||
if(isset($_GET['apprise_notify_each_detection'])) {
|
||||
$apprise_notify_each_detection = 1;
|
||||
} else {
|
||||
$apprise_notify_each_detection = 0;
|
||||
}
|
||||
if(isset($_GET['apprise_notify_each_species'])) {
|
||||
exec('sudo systemctl start pushed_notifications.service');
|
||||
if(isset($_GET['apprise_notify_new_species'])) {
|
||||
$apprise_notify_new_species = 1;
|
||||
} 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
|
||||
@@ -45,6 +46,8 @@ $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_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_NEW_SPECIES=.*/", "APPRISE_NOTIFY_NEW_SPECIES=$apprise_notify_new_species", $contents);
|
||||
$contents = preg_replace("/FLICKR_API_KEY=.*/", "FLICKR_API_KEY=$flickr_api_key", $contents);
|
||||
|
||||
|
||||
$contents2 = file_get_contents("./scripts/thisrun.txt");
|
||||
@@ -54,6 +57,9 @@ $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_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_NEW_SPECIES=.*/", "APPRISE_NOTIFY_NEW_SPECIES=$apprise_notify_new_species", $contents2);
|
||||
$contents2 = preg_replace("/FLICKR_API_KEY=.*/", "FLICKR_API_KEY=$flickr_api_key", $contents2);
|
||||
|
||||
|
||||
$fh = fopen("/etc/birdnet/birdnet.conf", "w");
|
||||
$fh2 = fopen("./scripts/thisrun.txt", "w");
|
||||
@@ -76,7 +82,7 @@ if ($language != "none"){
|
||||
$home = shell_exec("awk -F: '/1000/{print $6}' /etc/passwd");
|
||||
$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_output = `sudo $command`;
|
||||
$command_output = `$command`;
|
||||
`sudo restart_services.sh`;
|
||||
}
|
||||
}
|
||||
@@ -140,10 +146,14 @@ https://discordapp.com/api/webhooks/{WebhookID}/{WebhookToken}
|
||||
<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>
|
||||
<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"; } ?>>
|
||||
<label for="apprise_notify_each_species">Notify each new species</label><br>
|
||||
<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_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"; };?> >
|
||||
<label for="apprise_notify_each_detection">Notify each new detection</label><br><br>
|
||||
<h3>Bird Photos from Flickr</h3>
|
||||
<label for="flickr_api_key">Flickr API Key: </label>
|
||||
<input name="flickr_api_key" type="text" value="<?php print($config['FLICKR_API_KEY']);?>"/><br>
|
||||
<p>Set your Flickr API key to enable the display of bird images next to detections. <a target="_blank" href="https://www.flickr.com/services/api/misc.api_keys.html">Get your free key here.</a></p>
|
||||
<h3>Localization</h3>
|
||||
<label for="language">Database Language: </label>
|
||||
<select name="language">
|
||||
|
||||
@@ -7,6 +7,8 @@ import matplotlib.pyplot as plt
|
||||
from matplotlib.colors import LogNorm
|
||||
from datetime import datetime
|
||||
import textwrap
|
||||
import matplotlib.font_manager as font_manager
|
||||
from matplotlib import rcParams
|
||||
|
||||
userDir = os.path.expanduser('~')
|
||||
conn = sqlite3.connect(userDir + '/BirdNET-Pi/scripts/birds.db')
|
||||
@@ -29,6 +31,14 @@ df['Hour of Day'] = [r.hour for r in df.Time]
|
||||
#Create separate dataframes for separate locations
|
||||
df_plt=df #Default to use the whole Dbase
|
||||
|
||||
# Add every font at the specified location
|
||||
font_dir = [userDir+'/BirdNET-Pi/homepage/static']
|
||||
for font in font_manager.findSystemFonts(font_dir):
|
||||
font_manager.fontManager.addfont(font)
|
||||
|
||||
# Set font family globally
|
||||
rcParams['font.family'] = 'Roboto Flex'
|
||||
|
||||
#Get todays readings
|
||||
now = datetime.now()
|
||||
df_plt_today = df_plt[df_plt['Date']==now.strftime("%Y-%m-%d")]
|
||||
|
||||
@@ -37,6 +37,7 @@ $totalcount = $result1->fetchArray(SQLITE3_ASSOC);
|
||||
<td><?php echo $totalcount['COUNT(*)'];?></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br><br>
|
||||
<?php
|
||||
if (file_exists('./Charts/'.$chart)) {
|
||||
echo "<img src=\"/Charts/$chart?nocache=time()\" >";
|
||||
|
||||
@@ -73,7 +73,12 @@ RTSP_STREAM=
|
||||
|
||||
APPRISE_NOTIFICATION_TITLE="New BirdNET-Pi Detection"
|
||||
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_API_KEY=
|
||||
|
||||
################################################################################
|
||||
#-------------------------------- Defaults ----------------------------------#
|
||||
|
||||
@@ -91,22 +91,6 @@ EOF
|
||||
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() {
|
||||
echo "Creating necessary directories"
|
||||
[ -d ${EXTRACTED} ] || sudo -u ${USER} mkdir -p ${EXTRACTED}
|
||||
@@ -436,7 +420,6 @@ install_services() {
|
||||
install_recording_service
|
||||
install_custom_recording_service # But does not enable
|
||||
install_extraction_service
|
||||
install_pushed_notifications
|
||||
install_spectrogram_service
|
||||
install_chart_viewer_service
|
||||
install_gotty_logs
|
||||
|
||||
+65
-13
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
ini_set('session.gc_maxlifetime', 7200);
|
||||
session_set_cookie_params(7200);
|
||||
session_start();
|
||||
$myDate = date('Y-m-d');
|
||||
$chart = "Combo-$myDate.png";
|
||||
|
||||
@@ -8,6 +11,12 @@ if($db == False) {
|
||||
header("refresh: 0;");
|
||||
}
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" && isset($_GET['previous_detection_identifier'])) {
|
||||
|
||||
$statement4 = $db->prepare('SELECT Com_Name, Sci_Name, Date, Time, Confidence, File_Name FROM detections ORDER BY Date DESC, Time DESC LIMIT 5');
|
||||
@@ -16,6 +25,10 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" && isse
|
||||
header("refresh: 0;");
|
||||
}
|
||||
$result4 = $statement4->execute();
|
||||
if(!isset($_SESSION['images'])) {
|
||||
$_SESSION['images'] = [];
|
||||
}
|
||||
$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
|
||||
while($mostrecent = $result4->fetchArray(SQLITE3_ASSOC)) {
|
||||
$comname = preg_replace('/ /', '_', $mostrecent['Com_Name']);
|
||||
@@ -37,6 +50,23 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" && isse
|
||||
// we've found our valid detection! ignore everything else from the database loop
|
||||
if(strpos($headers[0],'200')) {
|
||||
if($_GET['previous_detection_identifier'] == $filename) { die(); }
|
||||
if($_GET['only_name'] == "true") { echo $comname.",".$filename;die(); }
|
||||
|
||||
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
|
||||
$key = array_search($comname, array_column($_SESSION['images'], 0));
|
||||
if($key !== false) {
|
||||
$image = $_SESSION['images'][$key];
|
||||
} 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];
|
||||
$modaltext = "https://flickr.com/photos/".$flickrjson["owner"]."/".$flickrjson["id"];
|
||||
$authorlink = "https://flickr.com/people/".$flickrjson["owner"];
|
||||
$imageurl = 'https://farm' .$flickrjson["farm"]. '.static.flickr.com/' .$flickrjson["server"]. '/' .$flickrjson["id"]. '_' .$flickrjson["secret"]. '.jpg';
|
||||
array_push($_SESSION['images'], array($comname,$imageurl,$flickrjson["title"], $modaltext, $authorlink));
|
||||
$image = $_SESSION['images'][count($_SESSION['images'])-1];
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
<style>
|
||||
.fade-in {
|
||||
@@ -60,13 +90,17 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" && isse
|
||||
<h3>Most Recent Detection: <span style="font-weight: normal;"><?php echo $mostrecent['Date']." ".$mostrecent['Time'];?></span></h3>
|
||||
<tr>
|
||||
<td class="relative"><a target="_blank" href="index.php?filename=<?php echo $mostrecent['File_Name']; ?>"><img class="copyimage" width="25" height="25" src="images/copy.png"></a>
|
||||
<form action="" method="GET">
|
||||
<input type="hidden" name="view" value="Species Stats">
|
||||
<button type="submit" name="species" value="<?php echo $mostrecent['Com_Name'];?>"><?php echo $mostrecent['Com_Name'];?></button></br>
|
||||
<a href="https://wikipedia.org/wiki/<?php echo $sciname;?>" target="_blank"/><i><?php echo $mostrecent['Sci_Name'];?></i></a>
|
||||
<br>Confidence: <?php echo $mostrecent['Confidence'];?><br>
|
||||
<video style="margin-top:10px" onplay='setLiveStreamVolume(0)' onended='setLiveStreamVolume(1)' onpause='setLiveStreamVolume(1)' controls poster="<?php echo $filename.".png";?>" preload="none" title="<?php echo $filename;?>"><source src="<?php echo $filename;?>"></video></td>
|
||||
</form>
|
||||
<div class="centered_image_container" style="margin-bottom: 0px !important;">
|
||||
<?php if(!empty($config["FLICKR_API_KEY"])) { ?>
|
||||
<img onclick='setModalText(<?php echo $iterations; ?>,"<?php echo urlencode($image[2]); ?>", "<?php echo $image[3]; ?>", "<?php echo $image[4]; ?>", "<?php echo $image[1]; ?>")' src="<?php echo $image[1]; ?>" class="img1">
|
||||
<?php } ?>
|
||||
<form action="" method="GET">
|
||||
<input type="hidden" name="view" value="Species Stats">
|
||||
<button type="submit" name="species" value="<?php echo $mostrecent['Com_Name'];?>"><?php echo $mostrecent['Com_Name'];?></button></br>
|
||||
<a href="https://wikipedia.org/wiki/<?php echo $sciname;?>" target="_blank"/><i><?php echo $mostrecent['Sci_Name'];?></i></a>
|
||||
<br>Confidence: <?php echo $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>
|
||||
</form>
|
||||
</tr>
|
||||
</table> <?php break;
|
||||
}
|
||||
@@ -153,17 +187,35 @@ body::-webkit-scrollbar {
|
||||
</style>
|
||||
</head>
|
||||
<div class="overview">
|
||||
<dialog id="attribution-dialog">
|
||||
<h1 id="modalHeading"></h1>
|
||||
<p id="modalText"></p>
|
||||
<button onclick="hideDialog()">Close</button>
|
||||
</dialog>
|
||||
<script>
|
||||
var dialog = document.querySelector('dialog');
|
||||
dialogPolyfill.registerDialog(dialog);
|
||||
|
||||
function showDialog() {
|
||||
document.getElementById('attribution-dialog').showModal();
|
||||
}
|
||||
|
||||
function hideDialog() {
|
||||
document.getElementById('attribution-dialog').close();
|
||||
}
|
||||
|
||||
function setModalText(iter, title, text, authorlink, photolink) {
|
||||
document.getElementById('modalHeading').innerHTML = "Photo: \""+decodeURIComponent(title.replace("+"," "))+"\" Attribution";
|
||||
document.getElementById('modalText').innerHTML = "<div><img style='border-radius:5px' src='"+photolink+"'></div><br><div>Image link: <a target='_blank' href="+text+">"+text+"</a><br>Author link: <a target='_blank' href="+authorlink+">"+authorlink+"</a></div>";
|
||||
showDialog();
|
||||
}
|
||||
</script>
|
||||
<div class="overview-stats">
|
||||
<div class="left-column">
|
||||
</div>
|
||||
<div class="right-column">
|
||||
<div class="chart">
|
||||
<?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();
|
||||
if (file_exists('./Charts/'.$chart)) {
|
||||
@@ -192,7 +244,7 @@ function loadDetectionIfNewExists(previous_detection_identifier=undefined) {
|
||||
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 is busy.")) {
|
||||
if(this.responseText.length > 0 && !this.responseText.includes("Database is busy")) {
|
||||
document.getElementById("most_recent_detection").innerHTML = this.responseText;
|
||||
|
||||
// only going to load left chart if there's a new detection
|
||||
|
||||
+187
-35
@@ -1,7 +1,5 @@
|
||||
<?php
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
error_reporting(E_ALL);
|
||||
error_reporting(E_ERROR);
|
||||
|
||||
$db = new SQLite3('./scripts/birds.db', SQLITE3_OPEN_CREATE | SQLITE3_OPEN_READWRITE);
|
||||
if($db == False){
|
||||
@@ -9,18 +7,62 @@ if($db == False){
|
||||
header("refresh: 0;");
|
||||
}
|
||||
|
||||
#By Date
|
||||
if(isset($_GET['byfilename'])){
|
||||
$statement = $db->prepare('SELECT DISTINCT(Date) FROM detections GROUP BY Date');
|
||||
if($statement == False){
|
||||
echo "Database is busy";
|
||||
header("refresh: 0;");
|
||||
if (file_exists('./scripts/thisrun.txt')) {
|
||||
$config = parse_ini_file('./scripts/thisrun.txt');
|
||||
} elseif (file_exists('firstrun.ini')) {
|
||||
$config = parse_ini_file('firstrun.ini');
|
||||
}
|
||||
|
||||
$user = shell_exec("awk -F: '/1000/{print $1}' /etc/passwd");
|
||||
$home = shell_exec("awk -F: '/1000/{print $6}' /etc/passwd");
|
||||
$home = trim($home);
|
||||
|
||||
if(isset($_GET['excludefile'])) {
|
||||
if(isset($_SERVER['PHP_AUTH_USER'])) {
|
||||
$submittedpwd = $_SERVER['PHP_AUTH_PW'];
|
||||
$submitteduser = $_SERVER['PHP_AUTH_USER'];
|
||||
if($submittedpwd == $config['CADDY_PWD'] && $submitteduser == 'birdnet'){
|
||||
if(!file_exists($home."/BirdNET-Pi/scripts/disk_check_exclude.txt")) {
|
||||
file_put_contents($home."/BirdNET-Pi/scripts/disk_check_exclude.txt", "##start\n##end");
|
||||
}
|
||||
if(isset($_GET['exclude_add'])) {
|
||||
$myfile = fopen($home."/BirdNET-Pi/scripts/disk_check_exclude.txt", "a") or die("Unable to open file!");
|
||||
$txt = $_GET['excludefile'];
|
||||
fwrite($myfile, $txt."\n");
|
||||
fwrite($myfile, $txt.".png\n");
|
||||
fclose($myfile);
|
||||
echo "OK";
|
||||
die();
|
||||
} else {
|
||||
$lines = file($home."/BirdNET-Pi/scripts/disk_check_exclude.txt");
|
||||
$search = $_GET['excludefile'];
|
||||
|
||||
$result = '';
|
||||
foreach($lines as $line) {
|
||||
if(stripos($line, $search) === false && stripos($line, $search.".png") === false) {
|
||||
$result .= $line;
|
||||
}
|
||||
}
|
||||
file_put_contents($home."/BirdNET-Pi/scripts/disk_check_exclude.txt", $result);
|
||||
echo "OK";
|
||||
die();
|
||||
}
|
||||
} else {
|
||||
header('WWW-Authenticate: Basic realm="My Realm"');
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
echo 'You must be authenticated to change the protection of files.';
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
header('WWW-Authenticate: Basic realm="My Realm"');
|
||||
header('HTTP/1.0 401 Unauthorized');
|
||||
echo 'You must be authenticated to change the protection of files.';
|
||||
exit;
|
||||
}
|
||||
$result = $statement->execute();
|
||||
$view = "bydate";
|
||||
#By Date
|
||||
}elseif(isset($_GET['bydate'])){
|
||||
$statement = $db->prepare('SELECT DISTINCT(Date) FROM detections GROUP BY Date');
|
||||
}
|
||||
|
||||
if(isset($_GET['bydate'])){
|
||||
$statement = $db->prepare('SELECT DISTINCT(Date) FROM detections GROUP BY Date ORDER BY Date DESC');
|
||||
if($statement == False){
|
||||
echo "Database is busy";
|
||||
header("refresh: 0;");
|
||||
@@ -79,7 +121,6 @@ if(isset($_GET['byfilename'])){
|
||||
session_unset();
|
||||
$view = "choose";
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
<html>
|
||||
@@ -90,6 +131,31 @@ if(isset($_GET['byfilename'])){
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<script>
|
||||
function toggleLock(filename, type, elem) {
|
||||
const xhttp = new XMLHttpRequest();
|
||||
xhttp.onload = function() {
|
||||
if(this.responseText == "OK"){
|
||||
if(type == "add") {
|
||||
elem.setAttribute("src","images/lock.svg");
|
||||
elem.setAttribute("title", "This file is delete protected.");
|
||||
elem.setAttribute("onclick", elem.getAttribute("onclick").replace("add","del"));
|
||||
} else {
|
||||
elem.setAttribute("src","images/unlock.svg");
|
||||
elem.setAttribute("title", "This file is not delete protected.");
|
||||
elem.setAttribute("onclick", elem.getAttribute("onclick").replace("del","add"));
|
||||
}
|
||||
}
|
||||
}
|
||||
if(type == "add") {
|
||||
xhttp.open("GET", "play.php?excludefile="+filename+"&exclude_add=true", true);
|
||||
} else {
|
||||
xhttp.open("GET", "play.php?excludefile="+filename+"&exclude_del=true", true);
|
||||
}
|
||||
xhttp.send();
|
||||
}
|
||||
</script>
|
||||
|
||||
<?php
|
||||
#If no specific species
|
||||
if(!isset($_GET['species']) && !isset($_GET['filename'])){
|
||||
@@ -102,16 +168,15 @@ if(!isset($_GET['species']) && !isset($_GET['filename'])){
|
||||
<input type="hidden" name="view" value="Recordings">
|
||||
<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">
|
||||
<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 <?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>
|
||||
</form>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<form action="" method="GET">
|
||||
@@ -121,13 +186,15 @@ if(!isset($_GET['species']) && !isset($_GET['filename'])){
|
||||
if($view == "bydate") {
|
||||
while($results=$result->fetchArray(SQLITE3_ASSOC)){
|
||||
$date = $results['Date'];
|
||||
if(realpath($home."/BirdSongs/Extracted/By_Date/".$date) !== false){
|
||||
echo "<td>
|
||||
<button action=\"submit\" name=\"date\" value=\"$date\">$date</button></td></tr>";}
|
||||
<button action=\"submit\" name=\"date\" value=\"$date\">$date</button></td></tr>";}}
|
||||
|
||||
#By Species
|
||||
} elseif($view == "byspecies") {
|
||||
while($results=$result->fetchArray(SQLITE3_ASSOC)){
|
||||
$name = $results['Com_Name'];
|
||||
|
||||
echo "<td>
|
||||
<button action=\"submit\" name=\"species\" value=\"$name\">$name</button></td></tr>";}
|
||||
|
||||
@@ -135,8 +202,11 @@ if(!isset($_GET['species']) && !isset($_GET['filename'])){
|
||||
} elseif($view == "date") {
|
||||
while($results=$result->fetchArray(SQLITE3_ASSOC)){
|
||||
$name = $results['Com_Name'];
|
||||
echo "<td>
|
||||
<button action=\"submit\" name=\"species\" value=\"$name\">$name</button></td></tr>";}
|
||||
if(realpath($home."/BirdSongs/Extracted/By_Date/".$date."/".str_replace(" ", "_",$name)) !== false){
|
||||
echo "<td>
|
||||
<button action=\"submit\" name=\"species\" value=\"$name\">$name</button></td></tr>";
|
||||
}
|
||||
}
|
||||
|
||||
#Choose
|
||||
} else {
|
||||
@@ -151,13 +221,42 @@ if(!isset($_GET['species']) && !isset($_GET['filename'])){
|
||||
}
|
||||
|
||||
#Specific Species
|
||||
if(isset($_GET['species'])){
|
||||
if(isset($_GET['species'])){ ?>
|
||||
<div style="width: auto;
|
||||
text-align: center">
|
||||
<form action="" method="GET">
|
||||
<input type="hidden" name="view" value="Recordings">
|
||||
<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">
|
||||
<img width=35px src="images/sort_date.svg" title="Sort by date" alt="Sort by date">
|
||||
</button>
|
||||
<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" title="Sort by confidence" alt="Sort by confidence">
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<?php
|
||||
// add disk_check_exclude.txt lines into an array for grepping
|
||||
$fp = @fopen($home."/BirdNET-Pi/scripts/disk_check_exclude.txt", 'r');
|
||||
if ($fp) {
|
||||
$disk_check_exclude_arr = explode("\n", fread($fp, filesize($home."/BirdNET-Pi/scripts/disk_check_exclude.txt")));
|
||||
}
|
||||
|
||||
$name = $_GET['species'];
|
||||
if(isset($_SESSION['date'])) {
|
||||
$date = $_SESSION['date'];
|
||||
$statement2 = $db->prepare("SELECT * FROM detections where Com_Name == \"$name\" AND Date == \"$date\" ORDER BY Time DESC");
|
||||
if(isset($_GET['sort']) && $_GET['sort'] == "confidence") {
|
||||
$statement2 = $db->prepare("SELECT * FROM detections where Com_Name == \"$name\" AND Date == \"$date\" ORDER BY Confidence DESC");
|
||||
} else {
|
||||
$statement2 = $db->prepare("SELECT * FROM detections where Com_Name == \"$name\" AND Date == \"$date\" ORDER BY Time DESC");
|
||||
}
|
||||
} else {
|
||||
$statement2 = $db->prepare("SELECT * FROM detections where Com_Name == \"$name\" ORDER BY Date DESC, Time DESC");}
|
||||
if(isset($_GET['sort']) && $_GET['sort'] == "confidence") {
|
||||
$statement2 = $db->prepare("SELECT * FROM detections where Com_Name == \"$name\" ORDER BY Confidence DESC");
|
||||
} else {
|
||||
$statement2 = $db->prepare("SELECT * FROM detections where Com_Name == \"$name\" ORDER BY Date DESC, Time DESC");
|
||||
}
|
||||
}
|
||||
if($statement2 == False){
|
||||
echo "Database is busy";
|
||||
header("refresh: 0;");
|
||||
@@ -167,6 +266,7 @@ if(isset($_GET['species'])){
|
||||
<tr>
|
||||
<th>$name</th>
|
||||
</tr>";
|
||||
$iter=0;
|
||||
while($results=$result2->fetchArray(SQLITE3_ASSOC))
|
||||
{
|
||||
$comname = preg_replace('/ /', '_', $results['Com_Name']);
|
||||
@@ -176,13 +276,40 @@ if(isset($_GET['species'])){
|
||||
$sciname = preg_replace('/ /', '_', $results['Sci_Name']);
|
||||
$sci_name = $results['Sci_Name'];
|
||||
$time = $results['Time'];
|
||||
$confidence = $results['Confidence'];
|
||||
echo "<tr>
|
||||
<td class=\"relative\"><a target=\"_blank\" href=\"index.php?filename=".$results['File_Name']."\"><img class=\"copyimage\" width=25 src=\"images/copy.png\"></a>$date $time<br>$confidence<br>
|
||||
<video onplay='setLiveStreamVolume(0)' onended='setLiveStreamVolume(1)' onpause='setLiveStreamVolume(1)' controls poster=\"$filename.png\" preload=\"none\" title=\"$filename\"><source src=\"$filename\"></video></td>
|
||||
</tr>";
|
||||
$confidence = round((float)round($results['Confidence'],2) * 100 ) . '%';
|
||||
$filename_formatted = $date."/".$comname."/".$results['File_Name'];
|
||||
|
||||
}echo "</table>";}
|
||||
// file was deleted by disk check, no need to show the detection in recordings
|
||||
if(!file_exists($home."/BirdSongs/Extracted/".$filename)) {
|
||||
continue;
|
||||
}
|
||||
$iter++;
|
||||
|
||||
if($config["FULL_DISK"] == "purge") {
|
||||
if(!in_array($filename_formatted, $disk_check_exclude_arr)) {
|
||||
$imageicon = "images/unlock.svg";
|
||||
$title = "This file is not delete protected.";
|
||||
$type = "add";
|
||||
} else {
|
||||
$imageicon = "images/lock.svg";
|
||||
$title = "This file is delete protected.";
|
||||
$type = "del";
|
||||
}
|
||||
|
||||
echo "<tr>
|
||||
<td class='relative'>$date $time<br>$confidence<br><img style='cursor:pointer' onclick='toggleLock(\"".$filename_formatted."\",\"".$type."\", this)' class=\"copyimage\" width=25 title=\"".$title."\" src=\"".$imageicon."\">
|
||||
<a href=\"$filename\"><img src=\"$filename.png\"></a>
|
||||
</td>
|
||||
</tr>";
|
||||
} else {
|
||||
echo "<tr>
|
||||
<td class='relative'>$date $time<br>$confidence<br>
|
||||
<a href=\"$filename\"><img src=\"$filename.png\"></a>
|
||||
</td>
|
||||
</tr>";
|
||||
}
|
||||
|
||||
}if($iter == 0){ echo "<tr><td><b>No recordings were found.</b><br><br><span style='font-size:small'>They may have been deleted to make space for new recordings. You can modify this setting for the future in Tools -> Settings -> Advanced Settings -> Full Disk Behavior.</small></td></tr>";}echo "</table>";}
|
||||
|
||||
if(isset($_GET['filename'])){
|
||||
$name = $_GET['filename'];
|
||||
@@ -205,11 +332,36 @@ if(isset($_GET['filename'])){
|
||||
$sciname = preg_replace('/ /', '_', $results['Sci_Name']);
|
||||
$sci_name = $results['Sci_Name'];
|
||||
$time = $results['Time'];
|
||||
$confidence = $results['Confidence'];
|
||||
echo "<tr>
|
||||
<td>$date $time<br>$confidence<br>
|
||||
<video onplay='setLiveStreamVolume(0)' onended='setLiveStreamVolume(1)' onpause='setLiveStreamVolume(1)' controls poster=\"$filename.png\" preload=\"none\" title=\"$filename\"><source src=\"$filename\"></video></td>
|
||||
</tr>";
|
||||
$confidence = round((float)round($results['Confidence'],2) * 100 ) . '%';
|
||||
$filename_formatted = $date."/".$comname."/".$results['File_Name'];
|
||||
|
||||
// add disk_check_exclude.txt lines into an array for grepping
|
||||
$fp = @fopen($home."/BirdNET-Pi/scripts/disk_check_exclude.txt", 'r');
|
||||
if ($fp) {
|
||||
$disk_check_exclude_arr = explode("\n", fread($fp, filesize($home."/BirdNET-Pi/scripts/disk_check_exclude.txt")));
|
||||
}
|
||||
|
||||
if($config["FULL_DISK"] == "purge") {
|
||||
if(!in_array($filename_formatted, $disk_check_exclude_arr)) {
|
||||
$imageicon = "images/unlock.svg";
|
||||
$title = "This file is not delete protected.";
|
||||
$type = "add";
|
||||
} else {
|
||||
$imageicon = "images/lock.svg";
|
||||
$title = "This file is delete protected.";
|
||||
$type = "del";
|
||||
}
|
||||
|
||||
echo "<tr>
|
||||
<td class=\"relative\"><img style='cursor:pointer' onclick='toggleLock(\"".$filename_formatted."\",\"".$type."\", this)' class=\"copyimage\" width=25 title=\"".$title."\" src=\"".$imageicon."\">$date $time<br>$confidence<br>
|
||||
<video onplay='setLiveStreamVolume(0)' onended='setLiveStreamVolume(1)' onpause='setLiveStreamVolume(1)' controls poster=\"$filename.png\" preload=\"none\" title=\"$filename\"><source src=\"$filename\"></video></td>
|
||||
</tr>";
|
||||
} else {
|
||||
echo "<tr>
|
||||
<td class=\"relative\">$date $time<br>$confidence<br>
|
||||
<video onplay='setLiveStreamVolume(0)' onended='setLiveStreamVolume(1)' onpause='setLiveStreamVolume(1)' controls poster=\"$filename.png\" preload=\"none\" title=\"$filename\"><source src=\"$filename\"></video></td>
|
||||
</tr>";
|
||||
}
|
||||
|
||||
}echo "</table>";}?>
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,6 @@ sudo pkill server.py
|
||||
sudo systemctl stop birdnet_recording.service
|
||||
services=(web_terminal.service
|
||||
spectrogram_viewer.service
|
||||
pushed_notifications.service
|
||||
livestream.service
|
||||
icecast2.service
|
||||
extraction.service
|
||||
@@ -22,6 +21,6 @@ sudo systemctl restart "${i}"
|
||||
done
|
||||
until grep 5050 <(netstat -tulpn 2>&1);do
|
||||
sudo systemctl restart birdnet_server.service
|
||||
sleep 20
|
||||
sleep 45
|
||||
done
|
||||
sudo systemctl restart birdnet_analysis.service
|
||||
|
||||
+32
-5
@@ -243,6 +243,33 @@ def sendAppriseNotifications(species,confidence):
|
||||
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):
|
||||
|
||||
print('WRITING RESULTS TO', path, '...', end=' ')
|
||||
@@ -261,7 +288,7 @@ def writeResultsToFile(detections, min_conf, path):
|
||||
def handle_client(conn, addr):
|
||||
global INCLUDE_LIST
|
||||
global EXCLUDE_LIST
|
||||
print(f"[NEW CONNECTION] {addr} connected.")
|
||||
#print(f"[NEW CONNECTION] {addr} connected.")
|
||||
|
||||
connected = True
|
||||
while connected:
|
||||
@@ -335,7 +362,7 @@ def handle_client(conn, addr):
|
||||
# Get Date/Time from filename in case Pi gets behind
|
||||
#now = datetime.now()
|
||||
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_date = file_name.split('-birdnet-')[0]
|
||||
file_time = file_name.split('-birdnet-')[1]
|
||||
@@ -463,13 +490,13 @@ def start():
|
||||
global INTERPRETER, INCLUDE_LIST, EXCLUDE_LIST
|
||||
INTERPRETER = loadModel()
|
||||
server.listen()
|
||||
print(f"[LISTENING] Server is listening on {SERVER}")
|
||||
#print(f"[LISTENING] Server is listening on {SERVER}")
|
||||
while True:
|
||||
conn, addr = server.accept()
|
||||
thread = threading.Thread(target=handle_client, args=(conn, addr))
|
||||
thread.start()
|
||||
print(f"[ACTIVE CONNECTIONS] {threading.activeCount() - 1}")
|
||||
#print(f"[ACTIVE CONNECTIONS] {threading.activeCount() - 1}")
|
||||
|
||||
|
||||
print("[STARTING] server is starting...")
|
||||
#print("[STARTING] server is starting...")
|
||||
start()
|
||||
|
||||
@@ -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 enable --now spectrogram_viewer.service">Enable</button>
|
||||
</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">
|
||||
<button type="submit" name="submit" value="stop_core_services.sh">Stop Core Services</button>
|
||||
</form>
|
||||
|
||||
+157
-13
@@ -1,16 +1,160 @@
|
||||
<?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');
|
||||
<script>
|
||||
// CREDITS: https://codepen.io/jakealbaugh/pen/jvQweW
|
||||
|
||||
// UPDATE: there is a problem in chrome with starting audio context
|
||||
// before a user gesture. This fixes it.
|
||||
var started = null;
|
||||
var player = null;
|
||||
const ctx = null;
|
||||
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;
|
||||
started = true;
|
||||
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);
|
||||
}
|
||||
$refresh = $config['RECORDING_LENGTH'];
|
||||
$time = time();
|
||||
echo "<img id=\"spectrogramimage\" style=\"width:100%;height:100%\" src=\"/spectrogram.png?nocache=$time\">";
|
||||
?>
|
||||
<script>
|
||||
// every $refresh seconds, this loop will run and refresh the spectrogram image
|
||||
|
||||
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(){
|
||||
document.getElementById("spectrogramimage").src = "/spectrogram.png?nocache="+Date.now();
|
||||
}, <?php echo $refresh; ?>*1000);
|
||||
loadDetectionIfNewExists();
|
||||
}, 2500);
|
||||
|
||||
function initialize() {
|
||||
document.body.querySelector('h1').remove();
|
||||
const CVS = document.body.querySelector('canvas');
|
||||
CTX = CVS.getContext('2d');
|
||||
const W = CVS.width = window.innerWidth;
|
||||
const H = CVS.height = window.innerHeight;
|
||||
|
||||
const ACTX = new AudioContext();
|
||||
const ANALYSER = ACTX.createAnalyser();
|
||||
|
||||
ANALYSER.fftSize = 2048;
|
||||
|
||||
process();
|
||||
|
||||
function process() {
|
||||
const SOURCE = ACTX.createMediaElementSource(player);
|
||||
SOURCE.connect(ANALYSER);
|
||||
SOURCE.connect(ACTX.destination)
|
||||
const DATA = new Uint8Array(ANALYSER.frequencyBinCount);
|
||||
const LEN = DATA.length;
|
||||
const h = (H / LEN + 0.9);
|
||||
const x = W - 1;
|
||||
CTX.fillStyle = 'hsl(280, 100%, 10%)';
|
||||
CTX.fillRect(0, 0, W, H);
|
||||
|
||||
loop();
|
||||
|
||||
function loop() {
|
||||
window.requestAnimationFrame(loop);
|
||||
let imgData = CTX.getImageData(1, 0, W - 1, H);
|
||||
|
||||
CTX.fillRect(0, 0, W, H);
|
||||
CTX.putImageData(imgData, 0, 0);
|
||||
ANALYSER.getByteFrequencyData(DATA);
|
||||
for (let i = 0; i < LEN; i++) {
|
||||
let rat = DATA[i] / 128 ;
|
||||
let hue = Math.round((rat * 120) + 280 % 360);
|
||||
let sat = '100%';
|
||||
let lit = 10 + (70 * rat) + '%';
|
||||
CTX.beginPath();
|
||||
CTX.strokeStyle = `hsl(${hue}, ${sat}, ${lit})`;
|
||||
CTX.moveTo(x, H - (i * h));
|
||||
CTX.lineTo(x, H - (i * h + h));
|
||||
CTX.stroke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
<style>
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
canvas {
|
||||
display: block;
|
||||
height: 85%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
h1 {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<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>
|
||||
<canvas></canvas>
|
||||
|
||||
+64
-22
@@ -56,7 +56,10 @@ if(isset($_GET['species'])){
|
||||
$user = shell_exec("awk -F: '/1000/{print $1}' /etc/passwd");
|
||||
$home = shell_exec("awk -F: '/1000/{print $6}' /etc/passwd");
|
||||
$home = trim($home);
|
||||
file_put_contents($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", "");
|
||||
file_put_contents($home."/BirdNET-Pi/scripts/disk_check_exclude.txt", "##start\n##end\n");
|
||||
}
|
||||
?>
|
||||
|
||||
<html lang="en">
|
||||
@@ -78,10 +81,10 @@ file_put_contents($home."/BirdNET-Pi/scripts/disk_check_exclude.txt", "");
|
||||
<input type="hidden" name="sort" value="<?php if(isset($_GET['sort'])){echo $_GET['sort'];}?>">
|
||||
<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">
|
||||
<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 <?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>
|
||||
</form>
|
||||
</div>
|
||||
@@ -106,17 +109,40 @@ $filename = "/By_Date/".$results['Date']."/".$comname."/".$results['File_Name'];
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<dialog id="attribution-dialog">
|
||||
<h1 id="modalHeading"></h1>
|
||||
<p id="modalText"></p>
|
||||
<button onclick="hideDialog()">Close</button>
|
||||
</dialog>
|
||||
<script>
|
||||
var dialog = document.querySelector('dialog');
|
||||
dialogPolyfill.registerDialog(dialog);
|
||||
|
||||
function showDialog() {
|
||||
document.getElementById('attribution-dialog').showModal();
|
||||
}
|
||||
|
||||
function hideDialog() {
|
||||
document.getElementById('attribution-dialog').close();
|
||||
}
|
||||
|
||||
function setModalText(iter, title, text, authorlink) {
|
||||
document.getElementById('modalHeading').innerHTML = "Photo "+iter+": \""+title+"\" Attribution";
|
||||
document.getElementById('modalText').innerHTML = "Image link: <a target='_blank' href="+text+">"+text+"</a><br>Author link: <a target='_blank' href="+authorlink+">"+authorlink+"</a>";
|
||||
showDialog();
|
||||
}
|
||||
</script>
|
||||
<div class="column center">
|
||||
<?php if(!isset($_GET['species'])){
|
||||
?><p class="centered">Choose a species to load images from Wikimedia Commons.</p>
|
||||
?><p class="centered">Choose a species to load images from Flickr.</p>
|
||||
<?php
|
||||
};?>
|
||||
<?php if(isset($_GET['species'])){
|
||||
$species = $_GET['species'];
|
||||
|
||||
$iter=0;
|
||||
while($results=$result3->fetchArray(SQLITE3_ASSOC)){
|
||||
$count = $results['COUNT(*)'];
|
||||
$maxconf = $results['MAX(Confidence)'];
|
||||
$maxconf = round((float)round($results['MAX(Confidence)'],2) * 100 ) . '%';
|
||||
$date = $results['Date'];
|
||||
$time = $results['Time'];
|
||||
$name = $results['Com_Name'];
|
||||
@@ -136,51 +162,67 @@ while($results=$result3->fetchArray(SQLITE3_ASSOC)){
|
||||
<video onplay='setLiveStreamVolume(0)' onended='setLiveStreamVolume(1)' onpause='setLiveStreamVolume(1)' controls poster=\"$filename.png\" title=\"$filename\"><source src=\"$filename\"></video></td>
|
||||
</tr>
|
||||
</table>
|
||||
<p>Loading Images from <a href=\"https://commons.wikimedia.org/w/index.php?search=$linkname&title=Special:MediaSearch&go=Go&type=image\" target=\"_blank\">Wikimedia Commons</a></p>", '6096');
|
||||
<p>Loading Images from Flickr</p>", '6096');
|
||||
|
||||
echo "<script>document.getElementsByTagName(\"h3\")[0].scrollIntoView();</script>";
|
||||
|
||||
ob_flush();
|
||||
flush();
|
||||
$imagelink = "https://commons.wikimedia.org/w/index.php?search=$linkname&title=Special:MediaSearch&go=Go&type=image";
|
||||
$homepage = file_get_contents($imagelink);
|
||||
preg_match_all("{<img\\s*(.*?)src=('.*?'|\".*?\"|[^\\s]+)(.*?)\\s*/?>}ims", $homepage, $matches, PREG_SET_ORDER);
|
||||
foreach ($matches as $val) {
|
||||
$pos = strpos($val[2],"/");
|
||||
$link = substr($val[2],1,-1);
|
||||
if($pos !== 1 && strpos($link, "upload") == true && strpos($link, "CentralAutoLogin") == false)
|
||||
echo "<img src=\"$link\">";
|
||||
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');
|
||||
}
|
||||
}}
|
||||
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"];
|
||||
|
||||
foreach ($flickrjson as $val) {
|
||||
$iter++;
|
||||
$modaltext = "https://flickr.com/photos/".$val["owner"]."/".$val["id"];
|
||||
$authorlink = "https://flickr.com/people/".$val["owner"];
|
||||
$imageurl = 'https://farm' .$val["farm"]. '.static.flickr.com/' .$val["server"]. '/' .$val["id"]. '_' .$val["secret"]. '.jpg';
|
||||
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>
|
||||
<?php
|
||||
$excludelines = [];
|
||||
while($results=$result->fetchArray(SQLITE3_ASSOC))
|
||||
{
|
||||
$comname = preg_replace('/ /', '_', $results['Com_Name']);
|
||||
$comname = preg_replace('/\'/', '', $comname);
|
||||
$filename = "/By_Date/".$results['Date']."/".$comname."/".$results['File_Name'];
|
||||
|
||||
$excludefile = fopen($home."/BirdNET-Pi/scripts/disk_check_exclude.txt", "a") or die("Unable to open file!");
|
||||
$txt = $results['Date']."/".$comname."/".$results['File_Name']."\n".$results['Date']."/".$comname."/".$results['File_Name'].".png\n";
|
||||
fwrite($excludefile, $txt);
|
||||
array_push($excludelines, $results['Date']."/".$comname."/".$results['File_Name']);
|
||||
array_push($excludelines, $results['Date']."/".$comname."/".$results['File_Name'].".png");
|
||||
?>
|
||||
<tr>
|
||||
<form action="" method="GET">
|
||||
<input type="hidden" name="sort" value="<?php if(isset($_GET['sort'])){echo $_GET['sort'];}?>">
|
||||
<td class="relative"><a target="_blank" href="index.php?filename=<?php echo $results['File_Name']; ?>"><img class="copyimage" width=25 src="images/copy.png"></a><input type="hidden" name="view" value="Species Stats">
|
||||
<button type="submit" name="species" value="<?php echo $results['Com_Name'];?>"><?php echo $results['Com_Name'];?></button><br><b>Occurrences:</b> <?php echo $results['COUNT(*)'];?><br>
|
||||
<b>Max Confidence:</b> <?php echo $results['MAX(Confidence)'];?><br>
|
||||
<b>Max Confidence:</b> <?php echo $percent = round((float)round($results['MAX(Confidence)'],2) * 100 ) . '%';?><br>
|
||||
<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>
|
||||
<?php
|
||||
}
|
||||
|
||||
$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>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
<?php
|
||||
ini_set('session.gc_maxlifetime', 7200);
|
||||
session_set_cookie_params(7200);
|
||||
session_start();
|
||||
ini_set('display_errors', 1);
|
||||
ini_set('display_startup_errors', 1);
|
||||
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');
|
||||
} else {
|
||||
// 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){
|
||||
echo "Database is busy";
|
||||
@@ -77,7 +80,18 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) {
|
||||
|
||||
?> <table>
|
||||
<?php
|
||||
|
||||
if(!isset($_SESSION['images'])) {
|
||||
$_SESSION['images'] = [];
|
||||
}
|
||||
$iterations = 0;
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
while($todaytable=$result0->fetchArray(SQLITE3_ASSOC))
|
||||
{
|
||||
$iterations++;
|
||||
@@ -86,13 +100,35 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) {
|
||||
$comname = preg_replace('/\'/', '_', $comname);
|
||||
$filename = "/By_Date/".date('Y-m-d')."/".$comname."/".$todaytable['File_Name'];
|
||||
$sciname = preg_replace('/ /', '_', $todaytable['Sci_Name']);
|
||||
|
||||
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
|
||||
$key = array_search($comname, array_column($_SESSION['images'], 0));
|
||||
if($key !== false) {
|
||||
$image = $_SESSION['images'][$key];
|
||||
} 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];
|
||||
$modaltext = "https://flickr.com/photos/".$flickrjson["owner"]."/".$flickrjson["id"];
|
||||
$authorlink = "https://flickr.com/people/".$flickrjson["owner"];
|
||||
$imageurl = 'http://farm' .$flickrjson["farm"]. '.static.flickr.com/' .$flickrjson["server"]. '/' .$flickrjson["id"]. '_' .$flickrjson["secret"]. '.jpg';
|
||||
array_push($_SESSION['images'], array($comname,$imageurl,$flickrjson["title"], $modaltext, $authorlink));
|
||||
$image = $_SESSION['images'][count($_SESSION['images'])-1];
|
||||
}
|
||||
}
|
||||
?>
|
||||
<?php if(isset($_GET['display_limit']) && is_numeric($_GET['display_limit'])){ ?>
|
||||
<tr class="relative" id="<?php echo $iterations; ?>">
|
||||
<td class="relative"><a target="_blank" href="index.php?filename=<?php echo $todaytable['File_Name']; ?>"><img class="copyimage" width=25 src="images/copy.png"></a><?php echo $todaytable['Time'];?><br>
|
||||
<td class="relative"><a target="_blank" href="index.php?filename=<?php echo $todaytable['File_Name']; ?>"><img class="copyimage" width=25 src="images/copy.png"></a>
|
||||
|
||||
<div class="centered_image_container">
|
||||
<?php if(!empty($config["FLICKR_API_KEY"])) { ?>
|
||||
<img onclick='setModalText(<?php echo $iterations; ?>,"<?php echo urlencode($image[2]); ?>", "<?php echo $image[3]; ?>", "<?php echo $image[4]; ?>", "<?php echo $image[1]; ?>")' src="<?php echo $image[1]; ?>" class="img1">
|
||||
<?php } ?>
|
||||
|
||||
<?php echo $todaytable['Time'];?><br>
|
||||
<b><a class="a2" href="https://allaboutbirds.org/guide/<?php echo $comname;?>" target="top"><?php echo $todaytable['Com_Name'];?></a></b><br>
|
||||
<a class="a2" href="https://wikipedia.org/wiki/<?php echo $sciname;?>" target="top"><i><?php echo $todaytable['Sci_Name'];?></i></a><br>
|
||||
<b>Confidence:</b> <?php echo $todaytable['Confidence'];?><br>
|
||||
<b>Confidence:</b> <?php echo round((float)round($todaytable['Confidence'],2) * 100 ) . '%';?><br></div><br>
|
||||
<video onplay='setLiveStreamVolume(0)' onended='setLiveStreamVolume(1)' onpause='setLiveStreamVolume(1)' controls poster="<?php echo $filename.".png";?>" preload="none" title="<?php echo $filename;?>"><source preload="none" src="<?php echo $filename;?>"></video>
|
||||
</td>
|
||||
<?php } else { //legacy mode ?>
|
||||
@@ -100,7 +136,7 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) {
|
||||
<td><?php echo $todaytable['Time'];?><br></td><td>
|
||||
<b><a class="a2" href="https://allaboutbirds.org/guide/<?php echo $comname;?>" target="top"><?php echo $todaytable['Com_Name'];?></a></b><br>
|
||||
<a class="a2" href="https://wikipedia.org/wiki/<?php echo $sciname;?>" target="top"><i><?php echo $todaytable['Sci_Name'];?></i></a><br></td>
|
||||
<td><b>Confidence:</b> <?php echo $todaytable['Confidence'];?><br></td>
|
||||
<td><b>Confidence:</b> <?php echo round((float)round($todaytable['Confidence'],2) * 100 ) . '%';?><br></td>
|
||||
<td style="min-width:180px"><audio controls preload="none" title="<?php echo $filename;?>"><source preload="none" src="<?php echo $filename;?>"></video>
|
||||
</td>
|
||||
<?php } ?>
|
||||
@@ -132,6 +168,29 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) {
|
||||
</style>
|
||||
</head>
|
||||
<div class="viewdb">
|
||||
<dialog id="attribution-dialog">
|
||||
<h1 id="modalHeading"></h1>
|
||||
<p id="modalText"></p>
|
||||
<button onclick="hideDialog()">Close</button>
|
||||
</dialog>
|
||||
<script>
|
||||
var dialog = document.querySelector('dialog');
|
||||
dialogPolyfill.registerDialog(dialog);
|
||||
|
||||
function showDialog() {
|
||||
document.getElementById('attribution-dialog').showModal();
|
||||
}
|
||||
|
||||
function hideDialog() {
|
||||
document.getElementById('attribution-dialog').close();
|
||||
}
|
||||
|
||||
function setModalText(iter, title, text, authorlink, photolink) {
|
||||
document.getElementById('modalHeading').innerHTML = "Photo: \""+decodeURIComponent(title.replace("+"," "))+"\" Attribution";
|
||||
document.getElementById('modalText').innerHTML = "<div><img style='border-radius:5px' src='"+photolink+"'></div><br><div>Image link: <a target='_blank' href="+text+">"+text+"</a><br>Author link: <a target='_blank' href="+authorlink+">"+authorlink+"</a></div>";
|
||||
showDialog();
|
||||
}
|
||||
</script>
|
||||
<h3>Number of Detections</h3>
|
||||
<table>
|
||||
<tr>
|
||||
@@ -158,7 +217,7 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) {
|
||||
|
||||
<h3>Today's Detections — <input autocomplete="off" size="11" type="text" placeholder="Search..." id="searchterm" name="searchterm"></h3>
|
||||
|
||||
<div style="padding-bottom:10px" id="detections_table"></div>
|
||||
<div style="padding-bottom:10px" id="detections_table"><h3>Loading...</h3></div>
|
||||
|
||||
<button onclick="switchViews(this);" class="legacyview">Legacy view</button>
|
||||
|
||||
@@ -188,7 +247,11 @@ document.getElementById("searchterm").onkeydown = (function(e) {
|
||||
});
|
||||
|
||||
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") {
|
||||
element.innerHTML = "Normal view";
|
||||
loadDetections(undefined);
|
||||
@@ -200,7 +263,11 @@ function switchViews(element) {
|
||||
function searchDetections(searchvalue) {
|
||||
document.getElementById("detections_table").innerHTML = "<h3>Loading...</h3>";
|
||||
searchterm = searchvalue;
|
||||
loadDetections(40,undefined);
|
||||
if(document.getElementsByClassName('legacyview')[0].innerHTML == "Normal view") {
|
||||
loadDetections(undefined,undefined);
|
||||
} else {
|
||||
loadDetections(40,undefined);
|
||||
}
|
||||
}
|
||||
function loadDetections(detections_limit, element=undefined) {
|
||||
const xhttp = new XMLHttpRequest();
|
||||
@@ -214,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);
|
||||
} else {
|
||||
xhttp.open("GET", "todays_detections.php?ajax_detections=true&display_limit="+detections_limit, true);
|
||||
|
||||
@@ -30,7 +30,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
|
||||
fi
|
||||
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
|
||||
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
|
||||
@@ -49,3 +52,12 @@ if grep bash $HOME/BirdNET-Pi/templates/web_terminal.service;then
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl restart web_terminal.service
|
||||
fi
|
||||
[ -L ~/BirdSongs/Extracted/static ] || ln -sf ~/BirdNET-Pi/homepage/static ~/BirdSongs/Extracted
|
||||
if ! grep FLICKR_API_KEY /etc/birdnet/birdnet.conf &>/dev/null;then
|
||||
sudo -u$USER echo "FLICKR_API_KEY=" >> /etc/birdnet/birdnet.conf
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user