From b550421be0ddde37a4b34f1affa267b3c5000c76 Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Fri, 13 May 2022 14:09:34 -0400 Subject: [PATCH 01/76] UI tweaks --- homepage/static/RobotoFlex-Regular.ttf | Bin 0 -> 109812 bytes homepage/style.css | 47 +++++++++++++++++++------ scripts/daily_plot.py | 10 ++++++ scripts/history.php | 1 + 4 files changed, 47 insertions(+), 11 deletions(-) create mode 100644 homepage/static/RobotoFlex-Regular.ttf diff --git a/homepage/static/RobotoFlex-Regular.ttf b/homepage/static/RobotoFlex-Regular.ttf new file mode 100644 index 0000000000000000000000000000000000000000..3f13b17d867531f7b17cea65136ea80791bdf803 GIT binary patch literal 109812 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

=f%cE1mxgT^uPl7@6w*_~1eaMND|G?j0I{-c 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 literal 0 HcmV?d00001 diff --git a/homepage/style.css b/homepage/style.css index ba5e360..91547b0 100644 --- a/homepage/style.css +++ b/homepage/style.css @@ -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; } @@ -132,6 +138,8 @@ button:hover { margin-left: auto; margin-right: auto; margin-bottom: 15px; + box-shadow: 0px 0px 17px 1px rgba(0, 0, 0, 0.10); !important; + border-radius: 4px; } .topnav form { @@ -178,7 +186,6 @@ button:hover { .overview th { background-color: rgb(219, 255, 235); - border: 2px solid black; text-align: center; padding: 12px; } @@ -238,7 +245,6 @@ button:hover { } .views .centered button { - border: 2px solid black; background-color: rgb(219, 255, 235); padding: 12px; } @@ -257,7 +263,6 @@ button:hover { } .settings button { - border: 2px solid black; background-color: rgb(219, 255, 235); padding: 12px; } @@ -284,7 +289,7 @@ button:hover { .customlabels button,.customlabels2 button { padding: 12px; background-color: rgb(219, 255, 235); - border: 2px solid black; + width: 100%; } @@ -339,7 +344,7 @@ button:hover { } .systemcontrols button,.servicecontrols button { - border: 2px solid black; + background-color: rgb(219, 255, 235); padding: 12px; width: 50%; @@ -541,7 +546,7 @@ button:hover { font-size:x-large; background:#dbffeb; padding:5px; - border: 2px solid black; + } button.legacyview { color:gray; @@ -552,12 +557,32 @@ button.legacyview { font-size:small; background:#dbffeb; padding:5px; - border: 2px solid black; + } button.loadmore { margin-top:10px; font-size:x-large; background:#dbffeb; padding:10px; - border: 2px solid black; + } + +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; +} +input { + box-shadow: 0px 0px 17px 1px rgba(0, 0, 0, 0.10); +} + diff --git a/scripts/daily_plot.py b/scripts/daily_plot.py index e2147b0..2d80dc3 100755 --- a/scripts/daily_plot.py +++ b/scripts/daily_plot.py @@ -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 = ['$HOME/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")] diff --git a/scripts/history.php b/scripts/history.php index 9a5e1df..88ca352 100644 --- a/scripts/history.php +++ b/scripts/history.php @@ -37,6 +37,7 @@ $totalcount = $result1->fetchArray(SQLITE3_ASSOC); +

"; From ac3fb313e619d741ec6c4d6851675de3c6450551 Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Fri, 13 May 2022 15:04:30 -0400 Subject: [PATCH 02/76] symlink for fonts --- scripts/update_birdnet_snippets.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/update_birdnet_snippets.sh b/scripts/update_birdnet_snippets.sh index e9c89d3..eea92dc 100755 --- a/scripts/update_birdnet_snippets.sh +++ b/scripts/update_birdnet_snippets.sh @@ -49,3 +49,4 @@ 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 From d0516f4464ae491ef6896e9104771525ac26e79b Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Sat, 14 May 2022 13:20:59 -0400 Subject: [PATCH 03/76] Much prettier "Update" screen --- homepage/views.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/homepage/views.php b/homepage/views.php index 942f6bf..d0f2ab2 100644 --- a/homepage/views.php +++ b/homepage/views.php @@ -47,6 +47,15 @@ body::-webkit-scrollbar { } 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.textContent = copyText; + document.body.append(textArea); + textArea.select(); + document.execCommand("copy"); + }

@@ -203,7 +212,7 @@ if(isset($_GET['view'])){ $command = $_GET['submit']; if(isset($command)){ $results = shell_exec("$command 2>&1"); - echo "
$results
"; + echo "
Output of command:`".$command."`
$results
"; } else { header('WWW-Authenticate: Basic realm="My Realm"'); header('HTTP/1.0 401 Unauthorized'); From a7e09bb5e582d207e74f849bf7c0b3fbd9ea78a3 Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Sat, 14 May 2022 13:28:20 -0400 Subject: [PATCH 04/76] Much prettier every other command --- homepage/views.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/homepage/views.php b/homepage/views.php index d0f2ab2..67209ea 100644 --- a/homepage/views.php +++ b/homepage/views.php @@ -212,7 +212,10 @@ if(isset($_GET['view'])){ $command = $_GET['submit']; if(isset($command)){ $results = shell_exec("$command 2>&1"); - echo "
Output of command:`".$command."`
$results
"; + if(strlen($results) == 0) { + $results = "This command has no output."; + } + echo "
Output of command:`".$command."`
$results
"; } else { header('WWW-Authenticate: Basic realm="My Realm"'); header('HTTP/1.0 401 Unauthorized'); From 2c29cce4a221687b2e5c9af5eb35b54d4e8a57e3 Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Sat, 14 May 2022 14:58:40 -0400 Subject: [PATCH 05/76] Giving service control commands an output --- homepage/views.php | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/homepage/views.php b/homepage/views.php index 67209ea..e190569 100644 --- a/homepage/views.php +++ b/homepage/views.php @@ -51,6 +51,8 @@ body::-webkit-scrollbar { 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(); @@ -89,7 +91,7 @@ if(isset($_GET['view'])){ if($submittedpwd == $caddypwd && $submitteduser == 'birdnet'){ $url = $_SERVER['SERVER_NAME']."/scripts/adminer.php"; echo "
-
+ @@ -99,8 +101,8 @@ if(isset($_GET['view'])){ -
-
"; + +
"; } else { header('WWW-Authenticate: Basic realm="My Realm"'); header('HTTP/1.0 401 Unauthorized'); @@ -184,7 +186,7 @@ if(isset($_GET['view'])){ $submitteduser = $_SERVER['PHP_AUTH_USER']; if($submittedpwd == $caddypwd && $submitteduser == 'birdnet'){ #ACCESS THE WEB TERMINAL - echo ""; + echo ""; } else { header('WWW-Authenticate: Basic realm="My Realm"'); header('HTTP/1.0 401 Unauthorized'); @@ -210,12 +212,20 @@ if(isset($_GET['view'])){ $submitteduser = $_SERVER['PHP_AUTH_USER']; if($submittedpwd == $caddypwd && $submitteduser == 'birdnet'){ $command = $_GET['submit']; - if(isset($command)){ + 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", "FAILURE", $results); + $results = str_replace("failed", "failed",$results); + $results = str_replace("active (running)", "active (running)",$results); if(strlen($results) == 0) { $results = "This command has no output."; } - echo "
Output of command:`".$command."`
$results
"; + echo "
Output of command:`".$initcommand."`
$results
"; } else { header('WWW-Authenticate: Basic realm="My Realm"'); header('HTTP/1.0 401 Unauthorized'); From 470e5d142dd9cab16c778ddc5e49fef015896b0c Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Sat, 14 May 2022 15:48:03 -0400 Subject: [PATCH 06/76] Round confidence to 2 decimals --- scripts/overview.php | 2 +- scripts/play.php | 2 +- scripts/stats.php | 4 ++-- scripts/todays_detections.php | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/scripts/overview.php b/scripts/overview.php index cba8a9f..9087ead 100644 --- a/scripts/overview.php +++ b/scripts/overview.php @@ -64,7 +64,7 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" && isse
-
Confidence:
+
Confidence:
diff --git a/scripts/play.php b/scripts/play.php index ad869be..f6f84f5 100644 --- a/scripts/play.php +++ b/scripts/play.php @@ -176,7 +176,7 @@ if(isset($_GET['species'])){ $sciname = preg_replace('/ /', '_', $results['Sci_Name']); $sci_name = $results['Sci_Name']; $time = $results['Time']; - $confidence = $results['Confidence']; + $confidence = round($results['Confidence'],2); echo " $date $time
$confidence
diff --git a/scripts/stats.php b/scripts/stats.php index 230a54a..a136946 100644 --- a/scripts/stats.php +++ b/scripts/stats.php @@ -116,7 +116,7 @@ $filename = "/By_Date/".$results['Date']."/".$comname."/".$results['File_Name']; while($results=$result3->fetchArray(SQLITE3_ASSOC)){ $count = $results['COUNT(*)']; - $maxconf = $results['MAX(Confidence)']; + $maxconf = round($results['MAX(Confidence)'],2); $date = $results['Date']; $time = $results['Time']; $name = $results['Com_Name']; @@ -172,7 +172,7 @@ fwrite($excludefile, $txt);
Occurrences:
- Max Confidence:
+ Max Confidence:
Best Recording:



- Confidence:
+ Confidence:
From a6644c59aa554da094ebb974fe736a5be78c2b36 Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Sat, 14 May 2022 16:10:18 -0400 Subject: [PATCH 07/76] Allow sorting of specific species in recordings TODO: add actual svg files for sort icons --- scripts/play.php | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/scripts/play.php b/scripts/play.php index f6f84f5..7825dbc 100644 --- a/scripts/play.php +++ b/scripts/play.php @@ -151,13 +151,36 @@ if(!isset($_GET['species']) && !isset($_GET['filename'])){ } #Specific Species -if(isset($_GET['species'])){ +if(isset($_GET['species'])){ ?> +
+
+ + + + +
+
+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 +190,9 @@ if(isset($_GET['species'])){ $name "; + $user = shell_exec("awk -F: '/1000/{print $1}' /etc/passwd"); + $home = shell_exec("awk -F: '/1000/{print $6}' /etc/passwd"); + $home = trim($home); while($results=$result2->fetchArray(SQLITE3_ASSOC)) { $comname = preg_replace('/ /', '_', $results['Com_Name']); @@ -176,7 +202,13 @@ if(isset($_GET['species'])){ $sciname = preg_replace('/ /', '_', $results['Sci_Name']); $sci_name = $results['Sci_Name']; $time = $results['Time']; - $confidence = round($results['Confidence'],2); + $confidence = $results['Confidence']; + + // file was deleted by disk check, no need to show the detection in recordings + if(!file_exists($home."/BirdSongs/Extracted/".$filename)) { + continue; + } + echo " $date $time
$confidence
From 1e23ea2e51079aabc04739b1e6df831b975946fb Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Sat, 14 May 2022 16:17:20 -0400 Subject: [PATCH 08/76] User feedback for deleted recordings --- scripts/play.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/play.php b/scripts/play.php index 7825dbc..7418a95 100644 --- a/scripts/play.php +++ b/scripts/play.php @@ -193,6 +193,7 @@ 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); + $iter=0; while($results=$result2->fetchArray(SQLITE3_ASSOC)) { $comname = preg_replace('/ /', '_', $results['Com_Name']); @@ -208,13 +209,14 @@ if(isset($_GET['species'])){ ?> if(!file_exists($home."/BirdSongs/Extracted/".$filename)) { continue; } + $iter++; echo " $date $time
$confidence
"; - }echo "";} + }if($iter == 0){ echo "No recordings were found on this date.

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.";}echo "";} if(isset($_GET['filename'])){ $name = $_GET['filename']; From e16c62c1aabb7b242c127e027cab1777eeead20c Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Sat, 14 May 2022 16:21:25 -0400 Subject: [PATCH 09/76] Making recordings actually usable for huge amounts of detections --- scripts/play.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/scripts/play.php b/scripts/play.php index 7418a95..0c38486 100644 --- a/scripts/play.php +++ b/scripts/play.php @@ -212,8 +212,9 @@ if(isset($_GET['species'])){ ?> $iter++; echo " - $date $time
$confidence
- + $date $time
$confidence
+ + "; }if($iter == 0){ echo "No recordings were found on this date.

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.";}echo "";} @@ -242,7 +243,8 @@ if(isset($_GET['filename'])){ $confidence = $results['Confidence']; echo " $date $time
$confidence
- + + "; }echo "";}?> From 3cf41eeb889a4788802a1c64070504c8defab5bf Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Sat, 14 May 2022 17:39:53 -0400 Subject: [PATCH 10/76] adding icons --- homepage/images/sort_date.svg | 43 +++++++++++++++++++++++++++++++++++ scripts/play.php | 4 ++-- 2 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 homepage/images/sort_date.svg diff --git a/homepage/images/sort_date.svg b/homepage/images/sort_date.svg new file mode 100644 index 0000000..ab7fbd0 --- /dev/null +++ b/homepage/images/sort_date.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/scripts/play.php b/scripts/play.php index 0c38486..2b4058d 100644 --- a/scripts/play.php +++ b/scripts/play.php @@ -158,10 +158,10 @@ if(isset($_GET['species'])){ ?> From d6bdb5c3457f4d712c06c0884117561ff44c764c Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Mon, 16 May 2022 08:16:33 -0400 Subject: [PATCH 11/76] Don't show dates that don't have any recordings --- scripts/play.php | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/scripts/play.php b/scripts/play.php index 2b4058d..87912a8 100644 --- a/scripts/play.php +++ b/scripts/play.php @@ -9,18 +9,9 @@ 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;"); - } - $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 +70,9 @@ if(isset($_GET['byfilename'])){ session_unset(); $view = "choose"; } - +$user = shell_exec("awk -F: '/1000/{print $1}' /etc/passwd"); +$home = shell_exec("awk -F: '/1000/{print $6}' /etc/passwd"); +$home = trim($home); ?> @@ -121,13 +114,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 " - ";} + ";}} #By Species } elseif($view == "byspecies") { while($results=$result->fetchArray(SQLITE3_ASSOC)){ $name = $results['Com_Name']; + echo " ";} @@ -135,8 +130,11 @@ if(!isset($_GET['species']) && !isset($_GET['filename'])){ } elseif($view == "date") { while($results=$result->fetchArray(SQLITE3_ASSOC)){ $name = $results['Com_Name']; - echo " - ";} + if(realpath($home."/BirdSongs/Extracted/By_Date/".$date."/".str_replace(" ", "_",$name)) !== false){ + echo " + "; + } + } #Choose } else { @@ -190,9 +188,6 @@ if(isset($_GET['species'])){ ?> $name "; - $user = shell_exec("awk -F: '/1000/{print $1}' /etc/passwd"); - $home = shell_exec("awk -F: '/1000/{print $6}' /etc/passwd"); - $home = trim($home); $iter=0; while($results=$result2->fetchArray(SQLITE3_ASSOC)) { From f59d04a7bcf8ba1c13bccd302f9e43471155600a Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Mon, 16 May 2022 10:58:04 -0400 Subject: [PATCH 12/76] Allow specific recordings to be "delete protected" from disk-check.sh @mcguirepr89 I'm very happy with how this turned out! :smile: --- homepage/images/lock.svg | 42 +++++++++++++ homepage/images/unlock.svg | 40 ++++++++++++ scripts/advanced.php | 2 +- scripts/play.php | 123 ++++++++++++++++++++++++++++++++----- scripts/stats.php | 23 +++++-- 5 files changed, 209 insertions(+), 21 deletions(-) create mode 100644 homepage/images/lock.svg create mode 100644 homepage/images/unlock.svg diff --git a/homepage/images/lock.svg b/homepage/images/lock.svg new file mode 100644 index 0000000..a3bd577 --- /dev/null +++ b/homepage/images/lock.svg @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/homepage/images/unlock.svg b/homepage/images/unlock.svg new file mode 100644 index 0000000..e8ddb69 --- /dev/null +++ b/homepage/images/unlock.svg @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/scripts/advanced.php b/scripts/advanced.php index 9f67d46..657cb99 100644 --- a/scripts/advanced.php +++ b/scripts/advanced.php @@ -204,7 +204,7 @@ if (file_exists('./scripts/thisrun.txt')) { >Purge -

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.

+

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.
Note: you can exclude specific files from 'purge' on the Recordings page.


Set Audio Card to 'default' to use PulseAudio (always recommended), or an ALSA recognized sound card device from the output of `aplay -L`.

diff --git a/scripts/play.php b/scripts/play.php index 87912a8..2115253 100644 --- a/scripts/play.php +++ b/scripts/play.php @@ -9,6 +9,43 @@ if($db == False){ 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(!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(); + } +} if(isset($_GET['bydate'])){ $statement = $db->prepare('SELECT DISTINCT(Date) FROM detections GROUP BY Date ORDER BY Date DESC'); @@ -70,9 +107,6 @@ if(isset($_GET['bydate'])){ session_unset(); $view = "choose"; } -$user = shell_exec("awk -F: '/1000/{print $1}' /etc/passwd"); -$home = shell_exec("awk -F: '/1000/{print $6}' /etc/passwd"); -$home = trim($home); ?> @@ -83,6 +117,29 @@ $home = trim($home); + + - @@ -199,6 +255,7 @@ if(isset($_GET['species'])){ ?> $sci_name = $results['Sci_Name']; $time = $results['Time']; $confidence = $results['Confidence']; + $filename_formatted = $date."/".$comname."/".$results['File_Name']; // file was deleted by disk check, no need to show the detection in recordings if(!file_exists($home."/BirdSongs/Extracted/".$filename)) { @@ -206,13 +263,31 @@ if(isset($_GET['species'])){ ?> } $iter++; - echo " - - "; + if($config["FULL_DISK"] == "purge") { + if(trim(shell_exec("cat ".$home."/BirdNET-Pi/scripts/disk_check_exclude.txt | grep \"".$filename_formatted."\" | wc -l")) == "0") { + $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"; + } - }if($iter == 0){ echo "";}echo "
$date $time
$confidence
- -
No recordings were found on this date.

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.
";} + echo " + $date $time
$confidence
+ + + "; + } else { + echo " + $date $time
$confidence
+ + + "; + } + + }if($iter == 0){ echo "No recordings were found.

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.";}echo "";} if(isset($_GET['filename'])){ $name = $_GET['filename']; @@ -236,11 +311,29 @@ if(isset($_GET['filename'])){ $sci_name = $results['Sci_Name']; $time = $results['Time']; $confidence = $results['Confidence']; - echo " - $date $time
$confidence
- - - "; + $filename_formatted = $date."/".$comname."/".$results['File_Name']; + + if($config["FULL_DISK"] == "purge") { + if(trim(shell_exec("cat ".$home."/BirdNET-Pi/scripts/disk_check_exclude.txt | grep \"".$filename_formatted."\" | wc -l")) == "0") { + $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 " + $date $time
$confidence
+ + "; + } else { + echo " + $date $time
$confidence
+ + "; + } }echo "";}?> diff --git a/scripts/stats.php b/scripts/stats.php index a136946..3f41a22 100644 --- a/scripts/stats.php +++ b/scripts/stats.php @@ -56,7 +56,18 @@ 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")) { + file_put_contents($home."/BirdNET-Pi/scripts/disk_check_exclude.txt", "##start\n##end"); +} +function editfile( $sourcefile, $start='##start', $end='##end', $data=array() ){ + $lines=array_filter( file( $sourcefile , FILE_SKIP_EMPTY_LINES | FILE_IGNORE_NEW_LINES ) ); + $output=array_merge( + array_splice( $lines, 0, array_search( strtolower( $start ), array_map('strtolower', $lines ) ) + 1 ), + $data, + array_splice( $lines, array_search( strtolower( $end ), array_map('strtolower', $lines ) ) ) + ); + file_put_contents( $sourcefile, implode( PHP_EOL, $output ) ); +} ?> @@ -151,21 +162,22 @@ while($results=$result3->fetchArray(SQLITE3_ASSOC)){ if($pos !== 1 && strpos($link, "upload") == true && strpos($link, "CentralAutoLogin") == false) echo ""; } -}} +} +} ?>


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"); ?> @@ -176,6 +188,7 @@ fwrite($excludefile, $txt); Best Recording:
From 29f6de47aa696e29f3b3820353e58b5d00bf2612 Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Mon, 16 May 2022 15:15:39 -0400 Subject: [PATCH 13/76] lazy loading --- scripts/play.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/play.php b/scripts/play.php index 2115253..d86fe34 100644 --- a/scripts/play.php +++ b/scripts/play.php @@ -276,13 +276,13 @@ if(isset($_GET['species'])){ ?> echo " $date $time
$confidence
- + "; } else { echo " $date $time
$confidence
- + "; } From a92119175f692e6f3991dea2eba29f694ca83fed Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Mon, 16 May 2022 19:50:36 -0400 Subject: [PATCH 14/76] Update todays_detections.php --- scripts/todays_detections.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/todays_detections.php b/scripts/todays_detections.php index 1651332..d2f5cfe 100644 --- a/scripts/todays_detections.php +++ b/scripts/todays_detections.php @@ -67,7 +67,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 '.$searchquery); } if($statement0 == False){ echo "Database is busy"; From ee675c4de2b7c35b37877cc616d66290a85a62c9 Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Tue, 17 May 2022 11:16:55 -0400 Subject: [PATCH 15/76] Efficiency! --- scripts/play.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/play.php b/scripts/play.php index d86fe34..1e73cbf 100644 --- a/scripts/play.php +++ b/scripts/play.php @@ -220,6 +220,12 @@ if(isset($_GET['species'])){ ?> $iter++; if($config["FULL_DISK"] == "purge") { - if(trim(shell_exec("cat ".$home."/BirdNET-Pi/scripts/disk_check_exclude.txt | grep \"".$filename_formatted."\" | wc -l")) == "0") { + if(!in_array($filename_formatted, $disk_check_exclude_arr)) { $imageicon = "images/unlock.svg"; $title = "This file is not delete protected."; $type = "add"; @@ -314,7 +320,7 @@ if(isset($_GET['filename'])){ $filename_formatted = $date."/".$comname."/".$results['File_Name']; if($config["FULL_DISK"] == "purge") { - if(trim(shell_exec("cat ".$home."/BirdNET-Pi/scripts/disk_check_exclude.txt | grep \"".$filename_formatted."\" | wc -l")) == "0") { + if(!in_array($filename_formatted, $disk_check_exclude_arr)) { $imageicon = "images/unlock.svg"; $title = "This file is not delete protected."; $type = "add"; From f7ce7545abeb9828a410afee984edc3a8ec36dbd Mon Sep 17 00:00:00 2001 From: Patrick McGuire <60325264+mcguirepr89@users.noreply.github.com> Date: Tue, 17 May 2022 15:11:52 -0400 Subject: [PATCH 16/76] iOS doesn't seem to support lazy loading on my iPhone, Safari and Chrome wouldn't load with the `loading="lazy"` method specified. Removing it fixes that -- I want to change it back for now, but then maybe figure out how to make it work on iOS ( I assume it is more resourceful to use lazy loading?) --- scripts/play.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/play.php b/scripts/play.php index 1e73cbf..91e6b1c 100644 --- a/scripts/play.php +++ b/scripts/play.php @@ -282,13 +282,13 @@ if(isset($_GET['species'])){ ?> echo " $date $time
$confidence
- + "; } else { echo " $date $time
$confidence
- + "; } From 8b8688d3d271cc4aaf346d03a5d61cf64349d017 Mon Sep 17 00:00:00 2001 From: mcguirepr89 Date: Tue, 17 May 2022 15:36:18 -0400 Subject: [PATCH 17/76] these are the changes from small_tweaks --- scripts/birdnet_log.sh | 2 +- scripts/restart_services.sh | 2 +- scripts/server.py | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/birdnet_log.sh b/scripts/birdnet_log.sh index e480664..1d49023 100755 --- a/scripts/birdnet_log.sh +++ b/scripts/birdnet_log.sh @@ -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/ .*\[.*\]: /---/" diff --git a/scripts/restart_services.sh b/scripts/restart_services.sh index f0cead9..98993af 100755 --- a/scripts/restart_services.sh +++ b/scripts/restart_services.sh @@ -22,6 +22,6 @@ sudo systemctl restart "${i}" done until grep 5050 <(netstat -tulpn 2>&1);do sudo systemctl restart birdnet_server.service -sleep 20 +sleep 30 done sudo systemctl restart birdnet_analysis.service diff --git a/scripts/server.py b/scripts/server.py index 6c96e12..35833e1 100755 --- a/scripts/server.py +++ b/scripts/server.py @@ -261,7 +261,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 +335,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 +463,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() From 5178a9876695cd73f8eea99884bde1e7a462e463 Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Tue, 17 May 2022 18:54:48 -0400 Subject: [PATCH 18/76] Efficiency, the sequel! --- scripts/play.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/scripts/play.php b/scripts/play.php index 1e73cbf..c32c7d7 100644 --- a/scripts/play.php +++ b/scripts/play.php @@ -319,6 +319,12 @@ if(isset($_GET['filename'])){ $confidence = $results['Confidence']; $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"; From fb703030c777523af7e88042a2dd3fa662032435 Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Wed, 18 May 2022 14:03:49 -0400 Subject: [PATCH 19/76] Flickr Implementation --- birdnet.conf-defaults | 4 ++ homepage/style.css | 34 ++++++++++++++- scripts/config.php | 8 ++++ scripts/install_config.sh | 4 ++ scripts/overview.php | 70 +++++++++++++++++++++++++----- scripts/stats.php | 44 ++++++++++++++----- scripts/todays_detections.php | 57 +++++++++++++++++++++++- scripts/update_birdnet_snippets.sh | 3 ++ 8 files changed, 198 insertions(+), 26 deletions(-) diff --git a/birdnet.conf-defaults b/birdnet.conf-defaults index 2b6f9f3..e75cda1 100644 --- a/birdnet.conf-defaults +++ b/birdnet.conf-defaults @@ -62,6 +62,10 @@ 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 +#---------------------- Flickr Images API Configuration -----------------------# + +FLICKR_API_KEY= + ################################################################################ #-------------------------------- Defaults ----------------------------------# ################################################################################ diff --git a/homepage/style.css b/homepage/style.css index 91547b0..0eed7bc 100644 --- a/homepage/style.css +++ b/homepage/style.css @@ -585,4 +585,36 @@ tr { 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 { + cursor:pointer; + height:95%; + position:absolute; + right:110%; + top:0px; + border-radius: 5px; +} +.centered_image_container * { + font-size:19px !important; +} +.centered_image_container form { + margin-bottom:0px; +} \ No newline at end of file diff --git a/scripts/config.php b/scripts/config.php index b925780..cabaa7e 100644 --- a/scripts/config.php +++ b/scripts/config.php @@ -10,6 +10,7 @@ $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 { @@ -45,6 +46,7 @@ $contents = preg_replace("/BIRDWEATHER_ID=.*/", "BIRDWEATHER_ID=$birdweather_id" $contents = preg_replace("/APPRISE_NOTIFICATION_TITLE=.*/", "APPRISE_NOTIFICATION_TITLE=\"$apprise_notification_title\"", $contents); $contents = preg_replace("/APPRISE_NOTIFICATION_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("/FLICKR_API_KEY=.*/", "FLICKR_API_KEY=$flickr_api_key", $contents); $contents2 = file_get_contents("./scripts/thisrun.txt"); @@ -54,6 +56,8 @@ $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("/FLICKR_API_KEY=.*/", "FLICKR_API_KEY=$flickr_api_key", $contents2); + $fh = fopen("/etc/birdnet/birdnet.conf", "w"); $fh2 = fopen("./scripts/thisrun.txt", "w"); @@ -144,6 +148,10 @@ https://discordapp.com/api/webhooks/{WebhookID}/{WebhookToken}
>

+

Bird Photos from Flickr

+ +
+

Set your Flickr API key to enable the display of bird images next to detections. Get your free key here.

Localization

-
- -
Confidence:
- - +
+ + + +
+ +
+ +
Confidence:

+ +
+ +

+

+ +
+
+ +

+

+ +
+

Choose a species to load images from Wikimedia Commons.

+?>

Choose a species to load images from Flickr.

fetchArray(SQLITE3_ASSOC)){ $count = $results['COUNT(*)']; $maxconf = round($results['MAX(Confidence)'],2); @@ -147,20 +170,19 @@ while($results=$result3->fetchArray(SQLITE3_ASSOC)){ -

Loading Images from Wikimedia Commons

", '6096'); +

Loading Images from Flickr

", '6096'); echo ""; 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("{}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 ""; + $flickrjson = json_decode(file_get_contents("https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key=2158f6c5d66e89778bd0d340953f1bcf&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 = 'http://farm' .$val["farm"]. '.static.flickr.com/' .$val["server"]. '/' .$val["id"]. '_' .$val["secret"]. '.jpg'; + echo "".$iter.""; } } } diff --git a/scripts/todays_detections.php b/scripts/todays_detections.php index d2f5cfe..6daea3a 100644 --- a/scripts/todays_detections.php +++ b/scripts/todays_detections.php @@ -77,7 +77,15 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) { ?> fetchArray(SQLITE3_ASSOC)) { $iterations++; @@ -86,13 +94,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($images, 0)); + if($key !== false) { + $image = $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=".$comname."&license=7%2C9%2C10&sort=relevance&per_page=5&orientation=landscape,square&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($images, array($comname,$imageurl,$flickrjson["title"], $modaltext, $authorlink)); + $image = $images[count($images)-1]; + } + } ?> - @@ -132,6 +162,29 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) {
+ +

+

+ +
+

Number of Detections


+
+ +
+ + + + +


- Confidence:
+ Confidence:

diff --git a/scripts/update_birdnet_snippets.sh b/scripts/update_birdnet_snippets.sh index eea92dc..0082ca2 100755 --- a/scripts/update_birdnet_snippets.sh +++ b/scripts/update_birdnet_snippets.sh @@ -50,3 +50,6 @@ if grep bash $HOME/BirdNET-Pi/templates/web_terminal.service;then 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 From 94c16d09703554f57533936644144dd207b7a288 Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Wed, 18 May 2022 14:04:28 -0400 Subject: [PATCH 20/76] Update config.php --- scripts/config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/config.php b/scripts/config.php index cabaa7e..7fbd0ed 100644 --- a/scripts/config.php +++ b/scripts/config.php @@ -150,7 +150,7 @@ https://discordapp.com/api/webhooks/{WebhookID}/{WebhookToken}

Bird Photos from Flickr

-
+

Set your Flickr API key to enable the display of bird images next to detections. Get your free key here.

Localization

From 5bd1835b6f6dc0c870d1b794c4d7183c668be16b Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Wed, 18 May 2022 14:14:59 -0400 Subject: [PATCH 21/76] better mobile formatting --- scripts/overview.php | 2 +- scripts/todays_detections.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/overview.php b/scripts/overview.php index 80c95e2..7d596fd 100644 --- a/scripts/overview.php +++ b/scripts/overview.php @@ -52,7 +52,7 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" && isse if($key !== false) { $image = $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=".$comname."&license=7%2C9%2C10&sort=relevance&per_page=5&orientation=landscape,square&format=json&nojsoncallback=1"), true)["photos"]["photo"][0]; + $flickrjson = json_decode(file_get_contents("https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key=".$config["FLICKR_API_KEY"]."&text=\"".$comname."\"&license=7%2C9%2C10&sort=relevance&per_page=5&orientation=square,portrait&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'; diff --git a/scripts/todays_detections.php b/scripts/todays_detections.php index 6daea3a..0eaea0d 100644 --- a/scripts/todays_detections.php +++ b/scripts/todays_detections.php @@ -101,7 +101,7 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) { if($key !== false) { $image = $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=".$comname."&license=7%2C9%2C10&sort=relevance&per_page=5&orientation=landscape,square&format=json&nojsoncallback=1"), true)["photos"]["photo"][0]; + $flickrjson = json_decode(file_get_contents("https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key=".$config["FLICKR_API_KEY"]."&text=\"".$comname."\"&license=7%2C9%2C10&sort=relevance&per_page=5&orientation=square,portrait&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'; From 53bc242fffcb369b20d0dada190b2f267c5596d6 Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Wed, 18 May 2022 14:16:20 -0400 Subject: [PATCH 22/76] searching fix --- scripts/overview.php | 2 +- scripts/todays_detections.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/overview.php b/scripts/overview.php index 7d596fd..580217b 100644 --- a/scripts/overview.php +++ b/scripts/overview.php @@ -52,7 +52,7 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" && isse if($key !== false) { $image = $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=\"".$comname."\"&license=7%2C9%2C10&sort=relevance&per_page=5&orientation=square,portrait&format=json&nojsoncallback=1"), true)["photos"]["photo"][0]; + $flickrjson = json_decode(file_get_contents("https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key=".$config["FLICKR_API_KEY"]."&text=".$comname."&license=7%2C9%2C10&sort=relevance&per_page=5&orientation=square,portrait&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'; diff --git a/scripts/todays_detections.php b/scripts/todays_detections.php index 0eaea0d..c2fcd8a 100644 --- a/scripts/todays_detections.php +++ b/scripts/todays_detections.php @@ -101,7 +101,7 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) { if($key !== false) { $image = $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=\"".$comname."\"&license=7%2C9%2C10&sort=relevance&per_page=5&orientation=square,portrait&format=json&nojsoncallback=1"), true)["photos"]["photo"][0]; + $flickrjson = json_decode(file_get_contents("https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key=".$config["FLICKR_API_KEY"]."&text=".$comname."&license=7%2C9%2C10&sort=relevance&per_page=5&orientation=square,portrait&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'; From cdbc0960ce85c7f0f4a4d1e74a40d6d8b03cb51e Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Wed, 18 May 2022 14:20:05 -0400 Subject: [PATCH 23/76] Update style.css --- homepage/style.css | 1 + 1 file changed, 1 insertion(+) diff --git a/homepage/style.css b/homepage/style.css index 0eed7bc..b43b2c3 100644 --- a/homepage/style.css +++ b/homepage/style.css @@ -611,6 +611,7 @@ dialog::backdrop { right:110%; top:0px; border-radius: 5px; + width:unset; } .centered_image_container * { font-size:19px !important; From b12c2846dab7b038e448cd458f96680c75f5287a Mon Sep 17 00:00:00 2001 From: mcguirepr89 Date: Wed, 18 May 2022 17:41:55 -0400 Subject: [PATCH 24/76] open flicker in new tab --- scripts/config.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/config.php b/scripts/config.php index 7fbd0ed..4fecbba 100644 --- a/scripts/config.php +++ b/scripts/config.php @@ -151,7 +151,7 @@ https://discordapp.com/api/webhooks/{WebhookID}/{WebhookToken}

Bird Photos from Flickr


-

Set your Flickr API key to enable the display of bird images next to detections. Get your free key here.

+

Set your Flickr API key to enable the display of bird images next to detections. Get your free key here.

Localization


-
Confidence:

+
Confidence:

From c3fe4828f1042bfd864c4011b7ca4ffa3f4425de Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Thu, 19 May 2022 08:16:20 -0400 Subject: [PATCH 26/76] Let's actually use CC images! --- scripts/overview.php | 2 +- scripts/todays_detections.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/overview.php b/scripts/overview.php index e025239..f8479da 100644 --- a/scripts/overview.php +++ b/scripts/overview.php @@ -52,7 +52,7 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" && isse if($key !== false) { $image = $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=".$comname."&license=7%2C9%2C10&sort=relevance&per_page=5&orientation=square,portrait&format=json&nojsoncallback=1"), true)["photos"]["photo"][0]; + $flickrjson = json_decode(file_get_contents("https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key=".$config["FLICKR_API_KEY"]."&text=".$comname."&license=2%2C3%2C4%2C5%2C6%2C9&sort=relevance&per_page=5&orientation=square,portrait&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'; diff --git a/scripts/todays_detections.php b/scripts/todays_detections.php index c2fcd8a..18ee509 100644 --- a/scripts/todays_detections.php +++ b/scripts/todays_detections.php @@ -101,7 +101,7 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) { if($key !== false) { $image = $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=".$comname."&license=7%2C9%2C10&sort=relevance&per_page=5&orientation=square,portrait&format=json&nojsoncallback=1"), true)["photos"]["photo"][0]; + $flickrjson = json_decode(file_get_contents("https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key=".$config["FLICKR_API_KEY"]."&text=".$comname."&license=2%2C3%2C4%2C5%2C6%2C9&sort=relevance&per_page=5&orientation=square,portrait&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'; From 787c5d65a980092a583aa9ca334bb254ac80e9be Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Thu, 19 May 2022 08:30:48 -0400 Subject: [PATCH 27/76] better search results also adding percentage conf to other files --- scripts/overview.php | 2 +- scripts/play.php | 4 ++-- scripts/stats.php | 4 ++-- scripts/todays_detections.php | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/scripts/overview.php b/scripts/overview.php index f8479da..49c0ccb 100644 --- a/scripts/overview.php +++ b/scripts/overview.php @@ -52,7 +52,7 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" && isse if($key !== false) { $image = $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=".$comname."&license=2%2C3%2C4%2C5%2C6%2C9&sort=relevance&per_page=5&orientation=square,portrait&format=json&nojsoncallback=1"), true)["photos"]["photo"][0]; + $flickrjson = json_decode(file_get_contents("https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key=".$config["FLICKR_API_KEY"]."&text=".str_replace("_", "%20", $comname)."&license=2%2C3%2C4%2C5%2C6%2C9&sort=relevance&per_page=5&orientation=square,portrait&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 = 'http://farm' .$flickrjson["farm"]. '.static.flickr.com/' .$flickrjson["server"]. '/' .$flickrjson["id"]. '_' .$flickrjson["secret"]. '.jpg'; diff --git a/scripts/play.php b/scripts/play.php index 370f53f..aca9574 100644 --- a/scripts/play.php +++ b/scripts/play.php @@ -260,7 +260,7 @@ if(isset($_GET['species'])){ ?> $sciname = preg_replace('/ /', '_', $results['Sci_Name']); $sci_name = $results['Sci_Name']; $time = $results['Time']; - $confidence = $results['Confidence']; + $confidence = round((float)round($results['Confidence'],2) * 100 ) . '%'; $filename_formatted = $date."/".$comname."/".$results['File_Name']; // file was deleted by disk check, no need to show the detection in recordings @@ -316,7 +316,7 @@ if(isset($_GET['filename'])){ $sciname = preg_replace('/ /', '_', $results['Sci_Name']); $sci_name = $results['Sci_Name']; $time = $results['Time']; - $confidence = $results['Confidence']; + $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 diff --git a/scripts/stats.php b/scripts/stats.php index 65d532b..cfa2c47 100644 --- a/scripts/stats.php +++ b/scripts/stats.php @@ -150,7 +150,7 @@ function setModalText(iter, title, text, authorlink) { $iter=0; while($results=$result3->fetchArray(SQLITE3_ASSOC)){ $count = $results['COUNT(*)']; - $maxconf = round($results['MAX(Confidence)'],2); + $maxconf = round((float)round($results['MAX(Confidence)'],2) * 100 ) . '%'; $date = $results['Date']; $time = $results['Time']; $name = $results['Com_Name']; @@ -206,7 +206,7 @@ array_push($excludelines, $results['Date']."/".$comname."/".$results['File_Name' Date: Thu, 19 May 2022 09:38:25 -0400 Subject: [PATCH 28/76] typo --- scripts/stats.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/stats.php b/scripts/stats.php index cfa2c47..fce469b 100644 --- a/scripts/stats.php +++ b/scripts/stats.php @@ -206,7 +206,7 @@ array_push($excludelines, $results['Date']."/".$comname."/".$results['File_Name' - \ No newline at end of file + From da4a8cc4ced0ae39e996ee0ecb2bd331e6c327bc Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Thu, 19 May 2022 14:03:14 -0400 Subject: [PATCH 29/76] Live spectrogram @mcguirepr89 I found this cool demo on codepen: https://codepen.io/jakealbaugh/pen/jvQweW And I adapted it to use the BirdNET-Pi audio livestream. Check it out!! --- scripts/spectrogram.php | 97 +++++++++++++++++++++++++++++++++++------ 1 file changed, 83 insertions(+), 14 deletions(-) diff --git a/scripts/spectrogram.php b/scripts/spectrogram.php index 8140cfc..48d384c 100644 --- a/scripts/spectrogram.php +++ b/scripts/spectrogram.php @@ -1,16 +1,85 @@ -"; -?> + + + +

Loading...

+ + From 389abfdd017ec33044cbaace6d07118dc7f13986 Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Thu, 19 May 2022 15:32:15 -0400 Subject: [PATCH 30/76] Update spectrogram.php --- scripts/spectrogram.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/spectrogram.php b/scripts/spectrogram.php index 48d384c..48eb20f 100644 --- a/scripts/spectrogram.php +++ b/scripts/spectrogram.php @@ -20,7 +20,7 @@ function initialize() { const ACTX = new AudioContext(); const ANALYSER = ACTX.createAnalyser(); - ANALYSER.fftSize = 4096; + ANALYSER.fftSize = 2048; process(); @@ -44,7 +44,7 @@ function initialize() { CTX.putImageData(imgData, 0, 0); ANALYSER.getByteFrequencyData(DATA); for (let i = 0; i < LEN; i++) { - let rat = DATA[i] / 255; + let rat = DATA[i] / 128; let hue = Math.round((rat * 120) + 280 % 360); let sat = '100%'; let lit = 10 + (70 * rat) + '%'; From 9a906dcbc87308cdb6889a6be4403510e374346b Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Thu, 19 May 2022 17:16:03 -0400 Subject: [PATCH 31/76] Auth on delete protection change --- scripts/play.php | 76 ++++++++++++++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 29 deletions(-) diff --git a/scripts/play.php b/scripts/play.php index aca9574..9789c3d 100644 --- a/scripts/play.php +++ b/scripts/play.php @@ -20,30 +20,46 @@ $home = shell_exec("awk -F: '/1000/{print $6}' /etc/passwd"); $home = trim($home); if(isset($_GET['excludefile'])) { - 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']; + 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; + $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; } - 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; } } @@ -121,14 +137,16 @@ if(isset($_GET['bydate'])){ function toggleLock(filename, type, elem) { const xhttp = new XMLHttpRequest(); xhttp.onload = function() { - 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(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") { From 5cbe301fd853c6ae5493ec154a812b5095cc8a7f Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Thu, 19 May 2022 18:29:14 -0400 Subject: [PATCH 32/76] Larger bird images upon click --- scripts/overview.php | 6 +++--- scripts/todays_detections.php | 8 ++++---- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/overview.php b/scripts/overview.php index 49c0ccb..388476a 100644 --- a/scripts/overview.php +++ b/scripts/overview.php @@ -86,7 +86,7 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" && isse @@ -130,7 +130,7 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) { - + @@ -180,7 +180,7 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) { } function setModalText(iter, title, text, authorlink, photolink) { - document.getElementById('modalHeading').innerHTML = "Photo: \""+title+"\" Attribution"; + document.getElementById('modalHeading').innerHTML = "Photo: \""+decodeURIComponent(title).replace("+"," ")+"\" Attribution"; document.getElementById('modalText').innerHTML = "

Image link: "+text+"
Author link: "+authorlink+"
"; showDialog(); } @@ -211,7 +211,7 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) {

Today's Detections —

-
+

Loading...

From d94a734c1b666dd8ff7b5ee88a7ae6cf93031325 Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Fri, 20 May 2022 08:38:42 -0400 Subject: [PATCH 34/76] Fixing bugs I created when I was fixing bugs --- scripts/overview.php | 2 +- scripts/todays_detections.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/overview.php b/scripts/overview.php index f05ceea..a5a3bdc 100644 --- a/scripts/overview.php +++ b/scripts/overview.php @@ -199,7 +199,7 @@ body::-webkit-scrollbar { } function setModalText(iter, title, text, authorlink, photolink) { - document.getElementById('modalHeading').innerHTML = "Photo: \""+decodeURIComponent(title).replace("+"," ")+"\" Attribution"; + document.getElementById('modalHeading').innerHTML = "Photo: \""+decodeURIComponent(title.replace("+"," "))+"\" Attribution"; document.getElementById('modalText').innerHTML = "

Image link: "+text+"
Author link: "+authorlink+"
"; showDialog(); } diff --git a/scripts/todays_detections.php b/scripts/todays_detections.php index 9c2a920..bacd06f 100644 --- a/scripts/todays_detections.php +++ b/scripts/todays_detections.php @@ -180,7 +180,7 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) { } function setModalText(iter, title, text, authorlink, photolink) { - document.getElementById('modalHeading').innerHTML = "Photo: \""+decodeURIComponent(title).replace("+"," ")+"\" Attribution"; + document.getElementById('modalHeading').innerHTML = "Photo: \""+decodeURIComponent(title.replace("+"," "))+"\" Attribution"; document.getElementById('modalText').innerHTML = "

Image link: "+text+"
Author link: "+authorlink+"
"; showDialog(); } From e7e823beceecc4982bb162a1546bc760e74ee4b9 Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Fri, 20 May 2022 09:42:56 -0400 Subject: [PATCH 35/76] Much better Best Recordings > disk_check_exclude.txt logic --- scripts/stats.php | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/scripts/stats.php b/scripts/stats.php index fce469b..3987187 100644 --- a/scripts/stats.php +++ b/scripts/stats.php @@ -59,15 +59,6 @@ $home = trim($home); 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"); } -function editfile( $sourcefile, $start='##start', $end='##end', $data=array() ){ - $lines=array_filter( file( $sourcefile , FILE_SKIP_EMPTY_LINES | FILE_IGNORE_NEW_LINES ) ); - $output=array_merge( - array_splice( $lines, 0, array_search( strtolower( $start ), array_map('strtolower', $lines ) ) + 1 ), - $data, - array_splice( $lines, array_search( strtolower( $end ), array_map('strtolower', $lines ) ) ) - ); - file_put_contents( $sourcefile, implode( PHP_EOL, $output ) ); -} ?> @@ -210,8 +201,10 @@ array_push($excludelines, $results['Date']."/".$comname."/".$results['File_Name' Best Recording:

Occurrences:
- Max Confidence:
+ Max Confidence:
Best Recording:

Occurrences:
- Max Confidence:
+ Max Confidence:
Best Recording:
- +
@@ -198,9 +198,9 @@ body::-webkit-scrollbar { document.getElementById('attribution-dialog').close(); } - function setModalText(iter, title, text, authorlink) { + function setModalText(iter, title, text, authorlink, photolink) { document.getElementById('modalHeading').innerHTML = "Photo: \""+title+"\" Attribution"; - document.getElementById('modalText').innerHTML = "Image link: "+text+"
Author link: "+authorlink+""; + document.getElementById('modalText').innerHTML = "

Image link: "+text+"
Author link: "+authorlink+"
"; showDialog(); } diff --git a/scripts/todays_detections.php b/scripts/todays_detections.php index caa3a62..7903f0c 100644 --- a/scripts/todays_detections.php +++ b/scripts/todays_detections.php @@ -116,7 +116,7 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) {
- +
@@ -179,9 +179,9 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) { 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: "+text+"
Author link: "+authorlink+""; + function setModalText(iter, title, text, authorlink, photolink) { + document.getElementById('modalHeading').innerHTML = "Photo: \""+title+"\" Attribution"; + document.getElementById('modalText').innerHTML = "

Image link: "+text+"
Author link: "+authorlink+"
"; showDialog(); } From 78b009abffb31be79dbf3e7a83a8d1ddc61057d4 Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Fri, 20 May 2022 08:34:01 -0400 Subject: [PATCH 33/76] Fixing bugs --- scripts/overview.php | 4 ++-- scripts/todays_detections.php | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/scripts/overview.php b/scripts/overview.php index 388476a..f05ceea 100644 --- a/scripts/overview.php +++ b/scripts/overview.php @@ -86,7 +86,7 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" && isse
- + @@ -199,7 +199,7 @@ body::-webkit-scrollbar { } function setModalText(iter, title, text, authorlink, photolink) { - document.getElementById('modalHeading').innerHTML = "Photo: \""+title+"\" Attribution"; + document.getElementById('modalHeading').innerHTML = "Photo: \""+decodeURIComponent(title).replace("+"," ")+"\" Attribution"; document.getElementById('modalText').innerHTML = "

Image link: "+text+"
Author link: "+authorlink+"
"; showDialog(); } diff --git a/scripts/todays_detections.php b/scripts/todays_detections.php index 7903f0c..9c2a920 100644 --- a/scripts/todays_detections.php +++ b/scripts/todays_detections.php @@ -116,13 +116,13 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" ) {
- +


- Confidence:

+ Confidence:




Confidence:
Confidence:
From bd7fee901246ee35d869a1f77813457b25a0bb9f Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Fri, 20 May 2022 09:51:26 -0400 Subject: [PATCH 36/76] Update stats.php --- scripts/stats.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/scripts/stats.php b/scripts/stats.php index 3987187..329aa7d 100644 --- a/scripts/stats.php +++ b/scripts/stats.php @@ -56,8 +56,9 @@ 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); -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(!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"); } ?> From 12434c195d7935ae3ede409fd57c7989034ab2bd Mon Sep 17 00:00:00 2001 From: mcguirepr89 Date: Fri, 20 May 2022 12:31:05 -0400 Subject: [PATCH 37/76] amplifying the spectrogram -- @ehpersonal38 what do you think? --- scripts/spectrogram.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/spectrogram.php b/scripts/spectrogram.php index 48eb20f..abfc81a 100644 --- a/scripts/spectrogram.php +++ b/scripts/spectrogram.php @@ -30,7 +30,7 @@ function initialize() { SOURCE.connect(ACTX.destination) const DATA = new Uint8Array(ANALYSER.frequencyBinCount); const LEN = DATA.length; - const h = H / LEN; + const h = (H / LEN + .8); const x = W - 1; CTX.fillStyle = 'hsl(280, 100%, 10%)'; CTX.fillRect(0, 0, W, H); From 182821e037b6fe65833ceb203480029c3672d15a Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Fri, 20 May 2022 13:08:40 -0400 Subject: [PATCH 38/76] Use "Live Audio" stream in top right if running Prevents duplicate audio sources --- scripts/spectrogram.php | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/scripts/spectrogram.php b/scripts/spectrogram.php index abfc81a..7ae4b1e 100644 --- a/scripts/spectrogram.php +++ b/scripts/spectrogram.php @@ -4,7 +4,17 @@ // UPDATE: there is a problem in chrome with starting audio context // before a user gesture. This fixes it. var started = null; +var player = null; window.onload = function(){ + var audioelement = window.parent.document.getElementsByTagName("audio")[0]; + if (typeof(audioelement) != 'undefined') { + + document.getElementById('player').remove(); + + player = audioelement; + } else { + player = document.getElementById('player'); + } if (started) return; started = true; initialize(); @@ -25,7 +35,7 @@ function initialize() { process(); function process() { - const SOURCE = ACTX.createMediaElementSource(document.getElementById('player')); + const SOURCE = ACTX.createMediaElementSource(player); SOURCE.connect(ANALYSER); SOURCE.connect(ACTX.destination) const DATA = new Uint8Array(ANALYSER.frequencyBinCount); @@ -79,6 +89,7 @@ h1 { } +

Loading...

From 29e88400f8c27097cfc6c453fae8ea86d3b808ae Mon Sep 17 00:00:00 2001 From: mcguirepr89 Date: Fri, 20 May 2022 13:08:58 -0400 Subject: [PATCH 39/76] this seems like a really good balance of gain and zoom --- scripts/spectrogram.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/spectrogram.php b/scripts/spectrogram.php index abfc81a..14e96c0 100644 --- a/scripts/spectrogram.php +++ b/scripts/spectrogram.php @@ -30,7 +30,7 @@ function initialize() { SOURCE.connect(ACTX.destination) const DATA = new Uint8Array(ANALYSER.frequencyBinCount); const LEN = DATA.length; - const h = (H / LEN + .8); + const h = (H / LEN + .9); const x = W - 1; CTX.fillStyle = 'hsl(280, 100%, 10%)'; CTX.fillRect(0, 0, W, H); @@ -44,7 +44,7 @@ function initialize() { CTX.putImageData(imgData, 0, 0); ANALYSER.getByteFrequencyData(DATA); for (let i = 0; i < LEN; i++) { - let rat = DATA[i] / 128; + let rat = DATA[i] / 196 ; let hue = Math.round((rat * 120) + 280 % 360); let sat = '100%'; let lit = 10 + (70 * rat) + '%'; From 63a74499b671371048c87eeb8049621b91bc0d62 Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Fri, 20 May 2022 14:25:33 -0400 Subject: [PATCH 40/76] Adding detections to the spectrogram --- scripts/overview.php | 1 + scripts/spectrogram.php | 38 +++++++++++++++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/scripts/overview.php b/scripts/overview.php index a5a3bdc..7ca08ef 100644 --- a/scripts/overview.php +++ b/scripts/overview.php @@ -45,6 +45,7 @@ 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 diff --git a/scripts/spectrogram.php b/scripts/spectrogram.php index f04d7ff..2df3421 100644 --- a/scripts/spectrogram.php +++ b/scripts/spectrogram.php @@ -1,10 +1,11 @@ -
@@ -91,18 +91,18 @@ if(isset($_GET['view'])){ if($submittedpwd == $caddypwd && $submitteduser == 'birdnet'){ $url = $_SERVER['SERVER_NAME']."/scripts/adminer.php"; echo "
-
- - - - - - - - - -
-
"; +
+ + + + + + + + + +
+
"; } else { header('WWW-Authenticate: Basic realm="My Realm"'); header('HTTP/1.0 401 Unauthorized'); @@ -196,36 +196,86 @@ 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)){ + 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', + 'sudo systemctl stop pushed_notifications.service', + 'sudo systemctl restart pushed_notifications.service', + 'sudo systemctl disable --now pushed_notifications.service', + 'sudo systemctl enable --now pushed_notifications.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", "FAILURE", $results); - $results = str_replace("failed", "failed",$results); - $results = str_replace("active (running)", "active (running)",$results); - if(strlen($results) == 0) { + 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", "FAILURE", $results); + $results = str_replace("failed", "failed",$results); + $results = str_replace("active (running)", "active (running)",$results); + if(strlen($results) == 0) { $results = "This command has no output."; - } - echo "
Output of command:`".$initcommand."`
$results
"; + } + echo "
Output of command:`".$initcommand."`
$results
"; } else { header('WWW-Authenticate: Basic realm="My Realm"'); header('HTTP/1.0 401 Unauthorized'); From dd2091a2b8fbc858618235a27b59815580a09641 Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Sat, 21 May 2022 15:20:14 -0400 Subject: [PATCH 52/76] Update play.php Silencing harmless notice that appears if the user doesn't have a disk_check_exclude.txt created yet. --- scripts/play.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/scripts/play.php b/scripts/play.php index 9789c3d..7fdc90b 100644 --- a/scripts/play.php +++ b/scripts/play.php @@ -1,7 +1,5 @@ Date: Sat, 21 May 2022 15:45:17 -0400 Subject: [PATCH 53/76] removed hi line - put label closer to audio signal --- scripts/spectrogram.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/scripts/spectrogram.php b/scripts/spectrogram.php index b2b241d..c710bd7 100644 --- a/scripts/spectrogram.php +++ b/scripts/spectrogram.php @@ -24,7 +24,7 @@ window.onload = function(){ function applyText(text) { CTX.fillStyle = 'white'; CTX.font = '25px Roboto Flex'; - CTX.fillText(text, document.body.querySelector('canvas').scrollWidth - (document.body.querySelector('canvas').scrollWidth * 0.50), document.body.querySelector('canvas').scrollHeight * 0.35); + CTX.fillText(text, document.body.querySelector('canvas').scrollWidth - (document.body.querySelector('canvas').scrollWidth * 0.20), document.body.querySelector('canvas').scrollHeight * 0.35); CTX.fillStyle = 'hsl(280, 100%, 10%)'; } @@ -122,7 +122,3 @@ h1 {

Loading...

- -
-hi - From 2c46f98a5bff6d10492b7c3eaf29d4d910de9bc7 Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Sat, 21 May 2022 15:52:20 -0400 Subject: [PATCH 54/76] Update daily_plot.py Squashed! --- scripts/daily_plot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/daily_plot.py b/scripts/daily_plot.py index 2d80dc3..a20e8d2 100755 --- a/scripts/daily_plot.py +++ b/scripts/daily_plot.py @@ -32,7 +32,7 @@ df['Hour of Day'] = [r.hour for r in df.Time] df_plt=df #Default to use the whole Dbase # Add every font at the specified location -font_dir = ['$HOME/BirdNET-Pi/homepage/static'] +font_dir = [userDir+'/BirdNET-Pi/homepage/static'] for font in font_manager.findSystemFonts(font_dir): font_manager.fontManager.addfont(font) From 72ca3fe5950e94812181f3c8d6de744724798681 Mon Sep 17 00:00:00 2001 From: mcguirepr89 Date: Sat, 21 May 2022 16:11:58 -0400 Subject: [PATCH 55/76] new cleanup.cron --- templates/cleanup.cron | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/templates/cleanup.cron b/templates/cleanup.cron index 4fb2fec..03a84f5 100644 --- a/templates/cleanup.cron +++ b/templates/cleanup.cron @@ -1,6 +1,6 @@ #birdnet -*/5 * * * * $USER /usr/local/bin/disk_check.sh &> /dev/null +*/5 * * * * $USER /usr/local/bin/disk_check.sh >/dev/null 2>&1 #birdnet -*/3 * * * * $USER /usr/local/bin/cleanup.sh &> /dev/null +*/3 * * * * $USER /usr/local/bin/cleanup.sh >/dev/null 2>&1 #birdnet -@reboot $USER /usr/local/bin/cleanup.sh &> /dev/null +@reboot $USER /usr/local/bin/cleanup.sh >/dev/null 2>&1 From 477143a9c4268e1e5e6f7baf418e528e1ce80e4b Mon Sep 17 00:00:00 2001 From: mcguirepr89 Date: Sat, 21 May 2022 18:34:00 -0400 Subject: [PATCH 56/76] I thought I did this? --- scripts/stats.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/stats.php b/scripts/stats.php index aab6bc3..974cda7 100644 --- a/scripts/stats.php +++ b/scripts/stats.php @@ -180,7 +180,7 @@ while($results=$result3->fetchArray(SQLITE3_ASSOC)){ $iter++; $modaltext = "https://flickr.com/photos/".$val["owner"]."/".$val["id"]; $authorlink = "https://flickr.com/people/".$val["owner"]; - $imageurl = 'http://farm' .$val["farm"]. '.static.flickr.com/' .$val["server"]. '/' .$val["id"]. '_' .$val["secret"]. '.jpg'; + $imageurl = 'https://farm' .$val["farm"]. '.static.flickr.com/' .$val["server"]. '/' .$val["id"]. '_' .$val["secret"]. '.jpg'; echo "".$iter.""; } } From 86fcdafbe2c7dfe7bd044a2bbd9b9a2d74e1562c Mon Sep 17 00:00:00 2001 From: mcguirepr89 Date: Sat, 21 May 2022 18:36:10 -0400 Subject: [PATCH 57/76] make the image the link --- scripts/stats.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/stats.php b/scripts/stats.php index 974cda7..81dc0b0 100644 --- a/scripts/stats.php +++ b/scripts/stats.php @@ -181,7 +181,7 @@ while($results=$result3->fetchArray(SQLITE3_ASSOC)){ $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 "".$iter.""; + echo ""; } } } From 9fd68a913cd12886141dee272858b3863b0c50d2 Mon Sep 17 00:00:00 2001 From: mcguirepr89 Date: Sat, 21 May 2022 19:04:56 -0400 Subject: [PATCH 58/76] removed style not used --- scripts/stats.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/stats.php b/scripts/stats.php index 81dc0b0..9e6b095 100644 --- a/scripts/stats.php +++ b/scripts/stats.php @@ -181,7 +181,7 @@ while($results=$result3->fetchArray(SQLITE3_ASSOC)){ $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 ""; + echo ""; } } } From fa82f4c50ddf6daca6f0f328c854ac49e37f4c1f Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Sun, 22 May 2022 08:54:04 -0400 Subject: [PATCH 59/76] iOS Legacy Mode + Responsive Text Scaling @mcguirepr89 Try this out on your iOS device(s) and let me know how/if it works! --- scripts/spectrogram.php | 46 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 5 deletions(-) diff --git a/scripts/spectrogram.php b/scripts/spectrogram.php index c710bd7..8b61cc0 100644 --- a/scripts/spectrogram.php +++ b/scripts/spectrogram.php @@ -7,6 +7,29 @@ var started = null; var player = null; const ctx = null; window.onload = function(){ + // if user agent includes iPhone or Mac, AND is not chrome, use legacy mode + if( (window.navigator.userAgent.includes("iPhone") || window.navigator.userAgent.includes("Mac")) && !window.navigator.userAgent.includes("CriOS")) { + document.getElementById("spectrogramimage").style.display=""; + document.body.querySelector('canvas').remove(); + document.getElementById('player').remove(); + document.body.querySelector('h1').remove(); + + + // every $refresh seconds, this loop will run and refresh the spectrogram image + window.setInterval(function(){ + document.getElementById("spectrogramimage").src = "/spectrogram.png?nocache="+Date.now(); + }, *1000); + } else { + document.getElementById("spectrogramimage").remove(); + var audioelement = window.parent.document.getElementsByTagName("audio")[0]; if (typeof(audioelement) != 'undefined') { @@ -16,15 +39,27 @@ window.onload = function(){ } else { player = document.getElementById('player'); } + player.play(); if (started) return; - started = true; - initialize(); + 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); +} + function applyText(text) { CTX.fillStyle = 'white'; CTX.font = '25px Roboto Flex'; - CTX.fillText(text, document.body.querySelector('canvas').scrollWidth - (document.body.querySelector('canvas').scrollWidth * 0.20), document.body.querySelector('canvas').scrollHeight * 0.35); + fitTextOnCanvas(text,"Roboto Flex",document.body.querySelector('canvas').scrollHeight * 0.35) CTX.fillStyle = 'hsl(280, 100%, 10%)'; } @@ -46,7 +81,7 @@ function loadDetectionIfNewExists() { window.setInterval(function(){ loadDetectionIfNewExists(); -}, 5000); +}, 2500); function initialize() { document.body.querySelector('h1').remove(); @@ -118,7 +153,8 @@ h1 { } + - +

Loading...

From 913c0141c8e9faf739d1029ddeaab28c1ce644b1 Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Sun, 22 May 2022 10:20:01 -0400 Subject: [PATCH 60/76] Update spectrogram.php --- scripts/spectrogram.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/spectrogram.php b/scripts/spectrogram.php index 8b61cc0..a109f94 100644 --- a/scripts/spectrogram.php +++ b/scripts/spectrogram.php @@ -7,8 +7,8 @@ var started = null; var player = null; const ctx = null; window.onload = function(){ - // if user agent includes iPhone or Mac, AND is not chrome, use legacy mode - if( (window.navigator.userAgent.includes("iPhone") || window.navigator.userAgent.includes("Mac")) && !window.navigator.userAgent.includes("CriOS")) { + // 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(); From 27462d31594d3939d3aafde256bdb35fdb068fc2 Mon Sep 17 00:00:00 2001 From: mcguirepr89 Date: Sun, 22 May 2022 10:37:51 -0400 Subject: [PATCH 61/76] you had this right the first time --- scripts/spectrogram.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/spectrogram.php b/scripts/spectrogram.php index a109f94..f95ee72 100644 --- a/scripts/spectrogram.php +++ b/scripts/spectrogram.php @@ -118,7 +118,7 @@ function initialize() { CTX.putImageData(imgData, 0, 0); ANALYSER.getByteFrequencyData(DATA); for (let i = 0; i < LEN; i++) { - let rat = DATA[i] / 196 ; + let rat = DATA[i] / 128 ; let hue = Math.round((rat * 120) + 280 % 360); let sat = '100%'; let lit = 10 + (70 * rat) + '%'; From 3a3c3e58c332ee160d048ae324fdfde4ab189111 Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Sun, 22 May 2022 13:22:01 -0400 Subject: [PATCH 62/76] shrunk & unbroke --- homepage/style.css | 2 +- homepage/views.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homepage/style.css b/homepage/style.css index b43b2c3..dcfceb0 100644 --- a/homepage/style.css +++ b/homepage/style.css @@ -181,7 +181,7 @@ button:hover { } .stats table { - width: 75%; + width: 60%; } .overview th { diff --git a/homepage/views.php b/homepage/views.php index 0ebd926..323fc84 100644 --- a/homepage/views.php +++ b/homepage/views.php @@ -70,7 +70,7 @@ if(isset($_GET['view'])){ if($_GET['view'] == "View Log"){echo "";} if($_GET['view'] == "Overview"){include('overview.php');} if($_GET['view'] == "Today's Detections"){include('todays_detections.php');} - if($_GET['view'] == "Species Stats"){echo "

";include('stats.php');} + if($_GET['view'] == "Species Stats"){include('stats.php');} if($_GET['view'] == "Streamlit"){echo "";} if($_GET['view'] == "Daily Charts"){include('history.php');} if($_GET['view'] == "Tools"){ From 0462e1ec2b137b8bad1b818efeebc5a00b8d611a Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Sun, 22 May 2022 17:21:42 -0400 Subject: [PATCH 63/76] Things have been made better - All buttons and bird images now have nice transitions on hover - Bird images have an added drop shadow for the aesthetics. :sunglasses: - When hovering over sort icons, a tooltip describing the button is now displayed - Best Recordings has been cleaned up and made a little clearer --- homepage/style.css | 17 ++++++++++++++++- scripts/play.php | 8 ++++---- scripts/stats.php | 11 ++++++++--- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/homepage/style.css b/homepage/style.css index dcfceb0..9e92938 100644 --- a/homepage/style.css +++ b/homepage/style.css @@ -70,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 { @@ -546,7 +551,7 @@ button:hover { font-size:x-large; background:#dbffeb; padding:5px; - + box-shadow: 0px 0px 5px 2px rgba(0, 0, 0, 0.10); } button.legacyview { color:gray; @@ -605,6 +610,7 @@ dialog::backdrop { margin-bottom:3px; } .centered_image_container img.img1 { + box-shadow:0px 2px 3px 0px rgb(0 0 0 / 29%); cursor:pointer; height:95%; position:absolute; @@ -613,9 +619,18 @@ dialog::backdrop { border-radius: 5px; width:unset; } +.centered_image_container img.img1:hover{ + opacity:0.8; +} .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; } \ No newline at end of file diff --git a/scripts/play.php b/scripts/play.php index 7fdc90b..cf7e30f 100644 --- a/scripts/play.php +++ b/scripts/play.php @@ -168,10 +168,10 @@ if(!isset($_GET['species']) && !isset($_GET['filename'])){
@@ -228,10 +228,10 @@ if(isset($_GET['species'])){ ?>
diff --git a/scripts/stats.php b/scripts/stats.php index 9e6b095..3ad11f0 100644 --- a/scripts/stats.php +++ b/scripts/stats.php @@ -81,10 +81,10 @@ if(!file_exists($home."/BirdNET-Pi/scripts/disk_check_exclude.txt") || strpos(fi
@@ -187,7 +187,12 @@ while($results=$result3->fetchArray(SQLITE3_ASSOC)){ } } ?> -


+ +

+
Best Recordings for Other Species:

+ +

+ Date: Mon, 23 May 2022 13:22:26 -0400 Subject: [PATCH 64/76] hehe --- homepage/views.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homepage/views.php b/homepage/views.php index 323fc84..4dbd247 100644 --- a/homepage/views.php +++ b/homepage/views.php @@ -97,7 +97,7 @@ if(isset($_GET['view'])){ - + From 7cf38359d46a7761cc29bd7a89e92606220733b4 Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Mon, 23 May 2022 14:09:10 -0400 Subject: [PATCH 65/76] Logo & shadows --- homepage/images/bnp.png | Bin 0 -> 17314 bytes homepage/style.css | 37 ++++++++++++++++++++++++++++++++++--- 2 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 homepage/images/bnp.png diff --git a/homepage/images/bnp.png b/homepage/images/bnp.png new file mode 100644 index 0000000000000000000000000000000000000000..cd67dce95053703869b9b9963f774a622f5acc61 GIT binary patch literal 17314 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 Bhh+c& literal 0 HcmV?d00001 diff --git a/homepage/style.css b/homepage/style.css index 9e92938..3319185 100644 --- a/homepage/style.css +++ b/homepage/style.css @@ -143,10 +143,15 @@ button:hover { margin-left: auto; margin-right: auto; margin-bottom: 15px; - box-shadow: 0px 0px 17px 1px rgba(0, 0, 0, 0.10); !important; + box-shadow: 0px 0px 28px 1px rgba(0, 0, 0, 0.10); !important; border-radius: 4px; } +.topimage { + width:175px; + display:initial !important; +} + .topnav form { margin: 0; padding: 0; @@ -252,11 +257,14 @@ button:hover { .views .centered button { 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 { @@ -562,15 +570,31 @@ button.legacyview { font-size:small; background:#dbffeb; padding:5px; - + transition:box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1); + box-shadow:0px 3px 1px -2px rgb(0 0 0 / 20%), 0px 2px 2px 0px rgb(0 0 0 / 14%), 0px 1px 5px 0px rgb(0 0 0 / 12%); } +button.legacyview:hover { + box-shadow:0px 2px 4px -1px rgb(0 0 0 / 20%), 0px 4px 5px 0px rgb(0 0 0 / 14%), 0px 1px 10px 0px rgb(0 0 0 / 12%); +} + button.loadmore { margin-top:10px; font-size:x-large; background:#dbffeb; padding:10px; + transition:box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1); + box-shadow:0px 3px 1px -2px rgb(0 0 0 / 20%), 0px 2px 2px 0px rgb(0 0 0 / 14%), 0px 1px 5px 0px rgb(0 0 0 / 12%); } +button.loadmore:hover { + box-shadow:0px 2px 4px -1px rgb(0 0 0 / 20%), 0px 4px 5px 0px rgb(0 0 0 / 14%), 0px 1px 10px 0px rgb(0 0 0 / 12%); +} +#searchterm { + transition:box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1); +} +#searchterm:hover { + box-shadow:0px 2px 4px -1px rgb(0 0 0 / 20%), 0px 4px 5px 0px rgb(0 0 0 / 14%), 0px 1px 10px 0px rgb(0 0 0 / 12%); +} tr { background-color:#9fe29b; @@ -586,6 +610,11 @@ tr { .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); @@ -610,7 +639,8 @@ dialog::backdrop { margin-bottom:3px; } .centered_image_container img.img1 { - box-shadow:0px 2px 3px 0px rgb(0 0 0 / 29%); + 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; @@ -621,6 +651,7 @@ dialog::backdrop { } .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; From 87f34b494b8a1a031a1d88ed36a8ebf680812a6e Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Mon, 23 May 2022 16:46:20 -0400 Subject: [PATCH 66/76] Using $_SESSION for storing and retrieving Flickr URLs Significantly decreases API calls --- scripts/overview.php | 15 ++++++++++----- scripts/todays_detections.php | 16 +++++++++++----- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/scripts/overview.php b/scripts/overview.php index ca308fd..39be33b 100644 --- a/scripts/overview.php +++ b/scripts/overview.php @@ -1,4 +1,7 @@ execute(); - $images = []; + 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)) { @@ -49,16 +54,16 @@ if(isset($_GET['ajax_detections']) && $_GET['ajax_detections'] == "true" && isse 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($images, 0)); + $key = array_search($comname, array_column($_SESSION['images'], 0)); if($key !== false) { - $image = $images[$key]; + $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($images, array($comname,$imageurl,$flickrjson["title"], $modaltext, $authorlink)); - $image = $images[count($images)-1]; + array_push($_SESSION['images'], array($comname,$imageurl,$flickrjson["title"], $modaltext, $authorlink)); + $image = $_SESSION['images'][count($_SESSION['images'])-1]; } } diff --git a/scripts/todays_detections.php b/scripts/todays_detections.php index bacd06f..0eaaf3f 100644 --- a/scripts/todays_detections.php +++ b/scripts/todays_detections.php @@ -1,4 +1,7 @@
From bf46a174fc02222fe82ca0d86641c0be9c4c731d Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Mon, 23 May 2022 18:37:37 -0400 Subject: [PATCH 67/76] Update todays_detections.php --- scripts/todays_detections.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/todays_detections.php b/scripts/todays_detections.php index 0eaaf3f..35216a7 100644 --- a/scripts/todays_detections.php +++ b/scripts/todays_detections.php @@ -247,7 +247,7 @@ document.getElementById("searchterm").onkeydown = (function(e) { }); function switchViews(element) { - document.getElementById("detections_table").innerHTML = ""; + document.getElementById("detections_table").innerHTML = "

Loading detections...

"; if(element.innerHTML == "Legacy view") { element.innerHTML = "Normal view"; loadDetections(undefined); From cdbadbb45c73cb15ffe1f07266b4c1c4eac724ba Mon Sep 17 00:00:00 2001 From: mcguirepr89 Date: Mon, 23 May 2022 18:41:16 -0400 Subject: [PATCH 68/76] starting this to get some help --- birdnet.conf-defaults | 3 ++- homepage/views.php | 4 ---- scripts/config.php | 12 +++++++----- scripts/install_config.sh | 1 + scripts/install_services.sh | 17 ----------------- scripts/restart_services.sh | 3 +-- scripts/server.py | 26 ++++++++++++++++++++++++++ scripts/service_controls.php | 7 ------- 8 files changed, 37 insertions(+), 36 deletions(-) diff --git a/birdnet.conf-defaults b/birdnet.conf-defaults index e75cda1..e53af20 100644 --- a/birdnet.conf-defaults +++ b/birdnet.conf-defaults @@ -60,7 +60,8 @@ 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 -----------------------# diff --git a/homepage/views.php b/homepage/views.php index 4dbd247..33f4621 100644 --- a/homepage/views.php +++ b/homepage/views.php @@ -250,10 +250,6 @@ if(isset($_GET['view'])){ 'sudo systemctl restart spectrogram_viewer.service', 'sudo systemctl disable --now spectrogram_viewer.service', 'sudo systemctl enable --now spectrogram_viewer.service', - 'sudo systemctl stop pushed_notifications.service', - 'sudo systemctl restart pushed_notifications.service', - 'sudo systemctl disable --now pushed_notifications.service', - 'sudo systemctl enable --now pushed_notifications.service', 'stop_core_services.sh', 'restart_services.sh', 'sudo reboot', diff --git a/scripts/config.php b/scripts/config.php index 78f0055..8b13084 100644 --- a/scripts/config.php +++ b/scripts/config.php @@ -16,10 +16,10 @@ if(isset($_GET['apprise_notify_each_detection'])) { } 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 @@ -46,6 +46,7 @@ $contents = preg_replace("/BIRDWEATHER_ID=.*/", "BIRDWEATHER_ID=$birdweather_id" $contents = preg_replace("/APPRISE_NOTIFICATION_TITLE=.*/", "APPRISE_NOTIFICATION_TITLE=\"$apprise_notification_title\"", $contents); $contents = preg_replace("/APPRISE_NOTIFICATION_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); @@ -56,6 +57,7 @@ $contents2 = preg_replace("/BIRDWEATHER_ID=.*/", "BIRDWEATHER_ID=$birdweather_id $contents2 = preg_replace("/APPRISE_NOTIFICATION_TITLE=.*/", "APPRISE_NOTIFICATION_TITLE=\"$apprise_notification_title\"", $contents2); $contents2 = preg_replace("/APPRISE_NOTIFICATION_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); @@ -144,8 +146,8 @@ https://discordapp.com/api/webhooks/{WebhookID}/{WebhookToken}

- > -
+ > +
>

Bird Photos from Flickr

diff --git a/scripts/install_config.sh b/scripts/install_config.sh index e74ac56..daab688 100755 --- a/scripts/install_config.sh +++ b/scripts/install_config.sh @@ -74,6 +74,7 @@ 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=0 +APPRISE_NOTIFY_NEW_SPECIES=0 #---------------------- Flickr Images API Configuration -----------------------# diff --git a/scripts/install_services.sh b/scripts/install_services.sh index 093047b..1d038b9 100755 --- a/scripts/install_services.sh +++ b/scripts/install_services.sh @@ -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 diff --git a/scripts/restart_services.sh b/scripts/restart_services.sh index 98993af..ad4e9f3 100755 --- a/scripts/restart_services.sh +++ b/scripts/restart_services.sh @@ -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 30 +sleep 45 done sudo systemctl restart birdnet_analysis.service diff --git a/scripts/server.py b/scripts/server.py index 35833e1..627b1a0 100755 --- a/scripts/server.py +++ b/scripts/server.py @@ -243,6 +243,32 @@ 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') + 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=' ') diff --git a/scripts/service_controls.php b/scripts/service_controls.php index 8abde5e..e81952b 100644 --- a/scripts/service_controls.php +++ b/scripts/service_controls.php @@ -73,13 +73,6 @@ -
-

Pushed Notifications

- - - - -
From 9987d332f2f45b267701634ca7e98f34e04686da Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Mon, 23 May 2022 18:45:32 -0400 Subject: [PATCH 69/76] Fix searching in legacy mode --- scripts/todays_detections.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/scripts/todays_detections.php b/scripts/todays_detections.php index 35216a7..a5866cd 100644 --- a/scripts/todays_detections.php +++ b/scripts/todays_detections.php @@ -70,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"; @@ -259,7 +259,11 @@ function switchViews(element) { function searchDetections(searchvalue) { document.getElementById("detections_table").innerHTML = "

Loading...

"; 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(); From 10e5770c82ed8a7e8251cd6b618a2519ba174ddc Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Tue, 24 May 2022 09:22:04 -0400 Subject: [PATCH 70/76] Prevent style caching on new update I assume this'll be 0.14? --- homepage/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homepage/index.php b/homepage/index.php index 03f8c34..eab5f2a 100644 --- a/homepage/index.php +++ b/homepage/index.php @@ -5,7 +5,7 @@ body::-webkit-scrollbar { display:none } - + "; } else { header('WWW-Authenticate: Basic realm="My Realm"'); @@ -46,12 +46,12 @@ if(isset($_GET['stream'])){ } } } else { - echo " + echo "
-

BirdNET-Pi

+

"; } if(isset($_GET['filename'])) { From 92e990a44f81865502aadc24a03e6c86062c6e71 Mon Sep 17 00:00:00 2001 From: mcguirepr89 Date: Tue, 24 May 2022 10:21:28 -0400 Subject: [PATCH 74/76] adding new variable to update_snippets --- scripts/update_birdnet_snippets.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/scripts/update_birdnet_snippets.sh b/scripts/update_birdnet_snippets.sh index 0082ca2..9f27cc2 100755 --- a/scripts/update_birdnet_snippets.sh +++ b/scripts/update_birdnet_snippets.sh @@ -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 From 7cb6da59104a9ed99a7de130157877ffc0bcfcc4 Mon Sep 17 00:00:00 2001 From: mcguirepr89 Date: Tue, 24 May 2022 10:35:45 -0400 Subject: [PATCH 75/76] removes pushed_notifications.service on update --- scripts/update_birdnet_snippets.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/scripts/update_birdnet_snippets.sh b/scripts/update_birdnet_snippets.sh index 9f27cc2..912574d 100755 --- a/scripts/update_birdnet_snippets.sh +++ b/scripts/update_birdnet_snippets.sh @@ -56,3 +56,8 @@ fi 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 From d540b5dbdd3d0994323783950b23a51051e16a0f Mon Sep 17 00:00:00 2001 From: ehpersonal38 <103586016+ehpersonal38@users.noreply.github.com> Date: Tue, 24 May 2022 11:27:54 -0400 Subject: [PATCH 76/76] Final banner! --- homepage/images/bnp.png | Bin 30595 -> 23501 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/homepage/images/bnp.png b/homepage/images/bnp.png index 72dfddadc09bf2224c28314f5112128118fbc25c..db5334b98a38cba522a2a44d6564a9aa9962ac3e 100644 GIT binary patch literal 23501 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 bozsfeczWbs-D>(>CimG>-M`Bo+r9ih0yy)z