Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UI : show new and rare species on top in overview.php #213

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions scripts/advanced.php
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,15 @@
$contents = preg_replace("/RAW_SPECTROGRAM=.*/", "RAW_SPECTROGRAM=0", $contents);
}

if(isset($_GET["rare_species_threshold"])) {
$rare_species_threshold = $_GET["rare_species_threshold"];
if(strcmp($rare_species_threshold, $config['RARE_SPECIES_THRESHOLD']) !== 0) {
$contents = preg_replace("/RARE_SPECIES_THRESHOLD=.*/", "RARE_SPECIES_THRESHOLD=$rare_species_threshold", $contents);
}
} else {
$contents = preg_replace("/RARE_SPECIES_THRESHOLD=.*/", "RARE_SPECIES_THRESHOLD=30", $contents);
}

if(isset($_GET["custom_image"])) {
$custom_image = $_GET["custom_image"];
if(strcmp($custom_image,$config['CUSTOM_IMAGE']) !== 0) {
Expand Down Expand Up @@ -434,6 +443,10 @@ function collectrtspUrls() {
<label for="raw_spectrogram">Minimalist Spectrograms: </label>
<input type="checkbox" name="raw_spectrogram" <?php if($newconfig['RAW_SPECTROGRAM'] == 1) { echo "checked"; };?> ><br>
<p>This allows you to remove the axes and labels of the spectrograms that are generated by Sox for each detection for a cleaner appearance.</p>

<label for="rare_species_threshold">Rare Species Threshold (days): </label>
<input type="number" name="rare_species_threshold" min="1" value="<?php echo isset($newconfig['RARE_SPECIES_THRESHOLD']) ? $newconfig['RARE_SPECIES_THRESHOLD'] : 30; ?>"><br>
<p>This setting defines after how many days since last detection a species is considered rare. Default is 30 days.</p>
</td></tr></table><br>

<table class="settingstable"><tr><td>
Expand Down
3 changes: 3 additions & 0 deletions scripts/install_config.sh
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,9 @@ RAW_SPECTROGRAM=0
CUSTOM_IMAGE=
CUSTOM_IMAGE_TITLE=""

## RARE_SPECIES_THRESHOLD defines after how many days a species is considered as rare and highlighted on overview page
RARE_SPECIES_THRESHOLD=30

## These are just for debugging
LAST_RUN=
THIS_RUN=
Expand Down
143 changes: 140 additions & 3 deletions scripts/overview.php
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,143 @@ function setModalText(iter, title, text, authorlink, photolink, licenseurl) {
<div class="right-column">
<div class="center-column">
</div>
<?php
$statement = $db->prepare("
SELECT d_today.Com_Name, d_today.Sci_Name, d_today.Date, d_today.Time, d_today.Confidence, d_today.File_Name,
MAX(d_today.Confidence) as MaxConfidence,
(SELECT MAX(Date) FROM detections d_prev WHERE d_prev.Com_Name = d_today.Com_Name AND d_prev.Date < DATE('now', 'localtime')) as LastSeenDate,
(SELECT COUNT(*) FROM detections d_occ WHERE d_occ.Com_Name = d_today.Com_Name AND d_occ.Date = DATE('now', 'localtime')) as OccurrenceCount
FROM detections d_today
WHERE d_today.Date = DATE('now', 'localtime')
GROUP BY d_today.Com_Name
");
ensure_db_ok($statement);
$result = $statement->execute();

$new_species = [];
$rare_species = [];
$rare_species_threshold = isset($config['RARE_SPECIES_THRESHOLD']) ? $config['RARE_SPECIES_THRESHOLD'] : 30;
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
$last_seen_date = $row['LastSeenDate'];
if ($last_seen_date === NULL) {
$new_species[] = $row;
} else {
$date1 = new DateTime($last_seen_date);
$date2 = new DateTime('now');
$interval = $date1->diff($date2);
$days_ago = $interval->days;
if ($days_ago > $rare_species_threshold) {
$row['DaysAgo'] = $days_ago;
$rare_species[] = $row;
}
}
}

if (!isset($_SESSION['images'])) {
$_SESSION['images'] = [];
}
$flickr = null;

function display_species($species_list, $title, $show_last_seen=false) {
global $config, $_SESSION, $flickr;
$species_count = count($species_list);
if ($species_count > 0): ?>
<div class="<?php echo strtolower(str_replace(' ', '_', $title)); ?>">
<h2 style="text-align:center;"><?php echo $species_count; ?> <?php echo strtolower($title); ?> detected today!</h2>
<?php if ($species_count > 5): ?>
<table><tr><td style="text-align:center;"><form action="" method="GET"><input type="hidden" name="view" value="Recordings"><button type="submit" name="date" value="<?php echo date('Y-m-d');?>">Open Today's recordings page</button></form></td></tr></table>
<?php else: ?>
<table>
<?php
$iterations = 0;
foreach($species_list as $todaytable):
$iterations++;
$comname = preg_replace('/ /', '_', $todaytable['Com_Name']);
$comname = preg_replace('/\'/', '', $comname);
$comnamegraph = str_replace("'", "\'", $todaytable['Com_Name']);
$filename = "/By_Date/".$todaytable['Date']."/".$comname."/".$todaytable['File_Name'];
$filename_formatted = $todaytable['Date']."/".$comname."/".$todaytable['File_Name'];
$sciname = preg_replace('/ /', '_', $todaytable['Sci_Name']);
$engname = get_com_en_name($todaytable['Sci_Name']);
$engname_url = str_replace("'", '', str_replace(' ', '_', $engname));
$info_url = get_info_url($todaytable['Sci_Name']);
$url = $info_url['URL'];
$url_title = $info_url['TITLE'];

$image_url = ""; // Default empty image URL

if (!empty($config["FLICKR_API_KEY"])) {
if ($flickr === null) {
$flickr = new Flickr();
}
if (isset($_SESSION["FLICKR_FILTER_EMAIL"]) && $_SESSION["FLICKR_FILTER_EMAIL"] !== $flickr->get_uid_from_db()['uid']) {
unset($_SESSION['images']);
$_SESSION["FLICKR_FILTER_EMAIL"] = $flickr->get_uid_from_db()['uid'];
}

// Check if the Flickr image has been cached in the session
$key = array_search($comname, array_column($_SESSION['images'], 0));
if ($key !== false) {
$image = $_SESSION['images'][$key];
} else {
// Retrieve the image from Flickr API and cache it
$flickr_cache = $flickr->get_image($todaytable['Sci_Name']);
array_push($_SESSION["images"], array($comname, $flickr_cache["image_url"], $flickr_cache["title"], $flickr_cache["photos_url"], $flickr_cache["author_url"], $flickr_cache["license_url"]));
$image = $_SESSION['images'][count($_SESSION['images']) - 1];
}
$image_url = $image[1] ?? ""; // Get the image URL if available
}

$last_seen_text = "";
if ($show_last_seen && isset($todaytable['DaysAgo'])) {
$days_ago = $todaytable['DaysAgo'];
if ($days_ago > 30) {
$months_ago = floor($days_ago / 30);
$last_seen_text = "<br><i><span class='text left'>Last seen: </span>{$months_ago}mo ago</i>";
} else {
$last_seen_text = "<br><i><span class='text left'>Last seen: </span>{$days_ago}d ago</i>";
}
}

$occurrence_text = "";
if (isset($todaytable['OccurrenceCount']) && $todaytable['OccurrenceCount'] > 1) {
$occurrence_text = " ({$todaytable['OccurrenceCount']}x)";
}
?>
<tr class="relative" id="<?php echo $iterations; ?>">
<td><?php if (!empty($image_url)): ?>
<img onclick='setModalText(<?php echo $iterations; ?>,"<?php echo urlencode($image[2]); ?>", "<?php echo $image[3]; ?>", "<?php echo $image[4]; ?>", "<?php echo $image[1]; ?>", "<?php echo $image[5]; ?>")' src="<?php echo $image_url; ?>" style="max-width: none; height: 50px; width: 50px; border-radius: 5px; cursor: pointer;" class="img1" title="Image from Flickr" />
<?php endif; ?></td>
<td id="recent_detection_middle_td">
<div><form action="" method="GET">
<input type="hidden" name="view" value="Species Stats">
<button class="a2" type="submit" name="species" value="<?php echo $todaytable['Com_Name']; ?>"><?php echo $todaytable['Com_Name']; ?></button>
<br><i><?php echo $todaytable['Sci_Name']; ?><br>
<a href="<?php echo $url; ?>" target="_blank"><img style="height: 1em;cursor:pointer;float:unset;display:inline" title="<?php echo $url_title; ?>" src="images/info.png" width="25"></a>
<a href="https://wikipedia.org/wiki/<?php echo $sciname; ?>" target="_blank"><img style="height: 1em;cursor:pointer;float:unset;display:inline" title="Wikipedia" src="images/wiki.png" width="25"></a>
<?php if ($show_last_seen): ?>
<img style="height: 1em;cursor:pointer;float:unset;display:inline" title="View species stats" onclick="generateMiniGraph(this, '<?php echo $comnamegraph; ?>', 160)" width="25" src="images/chart.svg">
<?php endif; ?>
<a target="_blank" href="index.php?filename=<?php echo $todaytable['File_Name']; ?>"><img style="height: 1em;cursor:pointer;float:unset;display:inline" class="copyimage-mobile" title="Open in new tab" width="16" src="images/copy.png"></a>
</i>
</form></div>
</td>
<td style="white-space: nowrap;"><?php
echo '<span class="text left">Max confidence: </span>' . round($todaytable['Confidence'] * 100 ) . '%' . $occurrence_text;
echo "<br><span class='text left'>First detection: </span>{$todaytable['Time']}";
echo $last_seen_text;
?></td>
</tr>
<?php endforeach; ?>
</table>
<?php endif; ?>
</div>
<?php endif;
}

display_species($new_species, 'New Species');
display_species($rare_species, 'Rare Species', true);
?>
<div class="chart">
<?php
$refresh = $config['RECORDING_LENGTH'];
Expand Down Expand Up @@ -477,11 +614,11 @@ function startAutoRefresh() {
}
</style>
<script>
function generateMiniGraph(elem, comname) {
function generateMiniGraph(elem, comname, days = 30) {

// Make an AJAX call to fetch the number of detections for the bird species
var xhr = new XMLHttpRequest();
xhr.open('GET', '/todays_detections.php?comname=' + comname);
xhr.open('GET', '/todays_detections.php?comname=' + comname + '&days=' + days);
xhr.onload = function() {
if (xhr.status === 200) {
var detections = JSON.parse(xhr.responseText);
Expand Down Expand Up @@ -534,7 +671,7 @@ function generateMiniGraph(elem, comname) {
},
title: {
display: true,
text: 'Detections Over 30d'
text: 'Detections Over ' + days + 'd'
},
legend: {
display: false
Expand Down
4 changes: 3 additions & 1 deletion scripts/todays_detections.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,11 @@
if(isset($_GET['comname'])) {
$birdName = htmlspecialchars_decode($_GET['comname'], ENT_QUOTES);

// Set default days to 30 if not provided
$days = isset($_GET['days']) ? intval($_GET['days']) : 30;

// Prepare a SQL statement to retrieve the detection data for the specified bird
$stmt = $db->prepare('SELECT Date, COUNT(*) AS Detections FROM detections WHERE Com_Name = :com_name AND Date BETWEEN DATE("now", "-30 days") AND DATE("now") GROUP BY Date');
$stmt = $db->prepare('SELECT Date, COUNT(*) AS Detections FROM detections WHERE Com_Name = :com_name AND Date BETWEEN DATE("now", "-' . $days . ' days") AND DATE("now") GROUP BY Date');

// Bind the bird name parameter to the SQL statement
$stmt->bindValue(':com_name', $birdName);
Expand Down
5 changes: 5 additions & 0 deletions scripts/update_birdnet_snippets.sh
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ if ! grep -E '^MAX_FILES_SPECIES=' /etc/birdnet/birdnet.conf &>/dev/null;then
echo "MAX_FILES_SPECIES=\"0\"" >> /etc/birdnet/birdnet.conf
fi

if ! grep -E '^RARE_SPECIES_THRESHOLD=' /etc/birdnet/birdnet.conf &>/dev/null;then
echo '## RARE_SPECIES_THRESHOLD defines after how many days a species is considered as rare and highlighted on overview page' >> /etc/birdnet/birdnet.conf
echo "RARE_SPECIES_THRESHOLD=\"30\"" >> /etc/birdnet/birdnet.conf
fi

[ -d $RECS_DIR/StreamData ] || sudo_with_user mkdir -p $RECS_DIR/StreamData
[ -L ${EXTRACTED}/spectrogram.png ] || sudo_with_user ln -sf ${RECS_DIR}/StreamData/spectrogram.png ${EXTRACTED}/spectrogram.png

Expand Down