Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
2c9f783
Add Species Management button and view handling
alexbelgium Aug 26, 2025
cd37822
Add species_tools.php for species management
alexbelgium Aug 26, 2025
50b13ae
Enhance species management with confirmed list
alexbelgium Aug 26, 2025
051df1c
Open db in write only if needed
alexbelgium Aug 26, 2025
0ebf18f
Add search, max confidence
alexbelgium Aug 26, 2025
f9ebf36
Clarify what is deleted
alexbelgium Aug 26, 2025
c77323e
Lazy load local files and threshold
alexbelgium Aug 27, 2025
44ac630
Add improved mini charts
alexbelgium Aug 28, 2025
60c3a48
Add options for 720 and 1080 days in selector
alexbelgium Aug 28, 2025
404fd26
Rename 'Identifications' header to 'Count'
alexbelgium Aug 28, 2025
4a5cf56
Add link to info pages
alexbelgium Aug 29, 2025
7bcc514
Remove db modif
alexbelgium Sep 13, 2025
4c9ffdf
Fix apostrophes
alexbelgium Sep 14, 2025
02d74e0
Change queries to use Sci_Name instead of Com_Name
alexbelgium Oct 11, 2025
d75924d
Add generateMiniGraph function for dynamic charts
alexbelgium Oct 11, 2025
4d412fe
Use common generateMiniGraph
alexbelgium Oct 11, 2025
9308bdb
External generateMiniGraph
alexbelgium Oct 11, 2025
76724e0
External generateMiniGraph function
alexbelgium Oct 11, 2025
737efd4
Compare with sci_names and not com_names in lists
alexbelgium Oct 11, 2025
e1ff6ff
Merge branch 'Nachtzuster:main' into patch-11
alexbelgium Oct 12, 2025
d3e0e3c
Still use sci name_com name in text files
alexbelgium Oct 12, 2025
0e5f49a
Link confirmed species list in clear_all_data.sh
alexbelgium Oct 12, 2025
da887b7
Add confirmed species list to backup script
alexbelgium Oct 12, 2025
5b54867
Add symlink for confirmed_species_list.txt
alexbelgium Oct 12, 2025
54f17b1
Add check.svg
alexbelgium Oct 12, 2025
33a71c9
Load threshold with sci names
alexbelgium Oct 12, 2025
c99c108
FILTER_SANITIZE_STRING is deprecated in PHP 8.1+
alexbelgium Oct 12, 2025
23f9b75
Use sci names for diskcount ajax
alexbelgium Oct 12, 2025
d7baca2
Revert diskcount to comname, as files are stored by comname
alexbelgium Oct 12, 2025
71d6789
Delete using sudo rm aligned code with play.php
alexbelgium Oct 12, 2025
ca9d589
Show deletion text using common name
alexbelgium Oct 12, 2025
809cf84
Fix typo
alexbelgium Oct 12, 2025
813df94
Simplify file deletion process in species_tools.php
alexbelgium Oct 28, 2025
e53e01c
Remove useless under_base
alexbelgium Oct 29, 2025
8093e44
Remove htmlspecialchars
alexbelgium Oct 29, 2025
f433fd3
Remove under_base check before directory deletion
alexbelgium Dec 16, 2025
23b2d8a
Remove under_base function from species_tools.php
alexbelgium Dec 16, 2025
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
4 changes: 4 additions & 0 deletions homepage/images/check.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
116 changes: 116 additions & 0 deletions homepage/static/generateMiniGraph.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
function generateMiniGraph(elem, comname, days = 30) {
var xhr = new XMLHttpRequest();
xhr.open('GET', '/todays_detections.php?comname=' + encodeURIComponent(comname) + '&days=' + days);
xhr.onload = function() {
if (xhr.status === 200) {
var detections = JSON.parse(xhr.responseText);
if (typeof(window.chartWindow) !== 'undefined') {
document.body.removeChild(window.chartWindow);
window.chartWindow = undefined;
}
var chartWindow = document.createElement('div');
chartWindow.className = 'chartdiv';
document.body.appendChild(chartWindow);

var canvas = document.createElement('canvas');
canvas.width = chartWindow.offsetWidth;
canvas.height = chartWindow.offsetHeight - 40;
chartWindow.appendChild(canvas);

var ctx = canvas.getContext('2d');
var chart = new Chart(ctx, {
type: 'line',
data: {
labels: detections.map(item => item.date),
datasets: [{
label: 'Detections',
data: detections.map(item => item.count),
backgroundColor: '#9fe29b',
borderColor: '#77c487',
borderWidth: 1,
lineTension: 0.3,
pointRadius: 1,
pointHitRadius: 10,
trendlineLinear: {
style: 'rgba(55, 99, 64, 0.5)',
lineStyle: 'solid',
width: 1.5
}
}]
},
options: {
layout: { padding: { right: 10 } },
title: { display: true, text: 'Detections Over ' + days + 'd' },
legend: { display: false },
scales: {
xAxes: [{
display: true,
gridLines: { display: true },
ticks: {
autoSkip: true,
maxTicksLimit: 6,
callback: value => value.substring(5)
}
}],
yAxes: [{
gridLines: { display: false },
ticks: { beginAtZero: true, precision: 0, maxTicksLimit: 5 }
}]
}
}
});

var buttonRect = elem.getBoundingClientRect();
var chartRect = chartWindow.getBoundingClientRect();
if (window.innerWidth < 700) {
chartWindow.style.left = 'calc(75% - ' + (chartRect.width / 2) + 'px)';
} else {
chartWindow.style.left = (buttonRect.right + 10) + 'px';
}

var buttonCenter = buttonRect.top + (buttonRect.height / 2);
var chartHeight = chartWindow.offsetHeight;
var chartTop = buttonCenter - (chartHeight / 2);
chartWindow.style.top = chartTop + 'px';

var closeButton = document.createElement('button');
closeButton.id = 'chartcb';
closeButton.innerText = 'X';
closeButton.style.position = 'absolute';
closeButton.style.top = '5px';
closeButton.style.right = '5px';
closeButton.addEventListener('click', () => {
document.body.removeChild(chartWindow);
window.chartWindow = undefined;
});
chartWindow.appendChild(closeButton);

var selector = document.createElement('select');
[30, 180, 360, 720, 1080].forEach(opt => {
var option = document.createElement('option');
option.value = opt;
option.text = opt + 'd';
if (opt === days) option.selected = true;
selector.appendChild(option);
});
selector.addEventListener('change', function() {
generateMiniGraph(elem, comname, parseInt(this.value));
});
selector.style.position = 'absolute';
selector.style.bottom = '5px';
selector.style.left = '5px';
chartWindow.appendChild(selector);

window.chartWindow = chartWindow;
}
};
xhr.send();
}

window.addEventListener('scroll', function() {
var charts = document.querySelectorAll('.chartdiv');
charts.forEach(chart => {
chart.parentNode.removeChild(chart);
window.chartWindow = undefined;
});
});
5 changes: 5 additions & 0 deletions homepage/views.php
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ function update_species_list($filename, $species, $add) {
<button type=\"submit\" name=\"view\" value=\"Included\" form=\"views\">Custom Species List</button>
<button type=\"submit\" name=\"view\" value=\"Excluded\" form=\"views\">Excluded Species List</button>
<button type=\"submit\" name=\"view\" value=\"Whitelisted\" form=\"views\">Whitelist Species List</button>
<button type=\"submit\" name=\"view\" value=\"Species Management\" form=\"views\">Species Management</button>
</form>
</div>";
}
Expand Down Expand Up @@ -203,6 +204,10 @@ function update_species_list($filename, $species, $add) {
$species_list="whitelist";
include('./scripts/species_list.php');
}
if($_GET['view'] == "Species Management"){
ensure_authenticated();
include('scripts/species_tools.php');
}
if($_GET['view'] == "File"){
echo "<iframe src='scripts/filemanager/filemanager.php'></iframe>";
}
Expand Down
1 change: 1 addition & 0 deletions scripts/backup_data.sh
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ optional=("/home/$BIRDNET_USER/BirdNET-Pi/apprise.txt"
"/home/$BIRDNET_USER/BirdNET-Pi/scripts/blacklisted_images.txt"
"/home/$BIRDNET_USER/BirdNET-Pi/scripts/disk_check_exclude.txt"
"/home/$BIRDNET_USER/BirdNET-Pi/exclude_species_list.txt"
"/home/$BIRDNET_USER/BirdNET-Pi/confirmed_species_list.txt"
"/home/$BIRDNET_USER/BirdNET-Pi/include_species_list.txt")

[ $ACTION == "backup" ] && backup_check
Expand Down
1 change: 1 addition & 0 deletions scripts/clear_all_data.sh
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ echo "Re-creating necessary directories"
[ -d ${PROCESSED} ] || sudo -u ${USER} mkdir -p ${PROCESSED}

sudo -u ${USER} ln -fs $(dirname $my_dir)/exclude_species_list.txt $my_dir
sudo -u ${USER} ln -fs $(dirname $my_dir)/confirmed_species_list.txt $my_dir
sudo -u ${USER} ln -fs $(dirname $my_dir)/include_species_list.txt $my_dir
sudo -u ${USER} ln -fs $(dirname $my_dir)/whitelist_species_list.txt $my_dir
sudo -u ${USER} ln -fs $(dirname $my_dir)/homepage/* ${EXTRACTED}
Expand Down
1 change: 1 addition & 0 deletions scripts/install_services.sh
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ create_necessary_dirs() {
[ -L ${EXTRACTED}/spectrogram.png ] || sudo -u ${USER} ln -sf ${RECS_DIR}/StreamData/spectrogram.png ${EXTRACTED}/spectrogram.png

sudo -u ${USER} ln -fs $my_dir/exclude_species_list.txt $my_dir/scripts
sudo -u ${USER} ln -fs $my_dir/confirmed_species_list.txt $my_dir/scripts
sudo -u ${USER} ln -fs $my_dir/include_species_list.txt $my_dir/scripts
sudo -u ${USER} ln -fs $my_dir/whitelist_species_list.txt $my_dir/scripts
sudo -u ${USER} ln -fs $my_dir/homepage/* ${EXTRACTED}
Expand Down
121 changes: 1 addition & 120 deletions scripts/overview.php
Original file line number Diff line number Diff line change
Expand Up @@ -600,127 +600,8 @@ function startAutoRefresh() {
}
</style>
<script src="static/custom-audio-player.js"></script>
<script src="static/generateMiniGraph.js"></script>
<script>
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 + '&days=' + days);
xhr.onload = function() {
if (xhr.status === 200) {
var detections = JSON.parse(xhr.responseText);

// Create a div element for the chart window
if (typeof(window.chartWindow) != 'undefined') {
document.body.removeChild(window.chartWindow);
window.chartWindow = undefined;
}
var chartWindow = document.createElement('div');
chartWindow.className = "chartdiv"
document.body.appendChild(chartWindow);


// Create a canvas element for the chart
var canvas = document.createElement('canvas');
canvas.width = chartWindow.offsetWidth;
canvas.height = chartWindow.offsetHeight;
chartWindow.appendChild(canvas);

// Create a new Chart.js chart
var ctx = canvas.getContext('2d');
var chart = new Chart(ctx, {
type: 'line',
data: {
labels: detections.map(item => item.date),
datasets: [{
label: 'Detections',
data: detections.map(item => item.count),
backgroundColor: '#9fe29b',
borderColor: '#77c487',
borderWidth: 1,
lineTension: 0.3, // Add smoothing to the line
pointRadius: 1, // Make the data points smaller
pointHitRadius: 10, // Increase the area around data points for mouse events

trendlineLinear: {
style: "rgba(55, 99, 64, 0.5)",
lineStyle: "solid",
width: 1.5
}

}]
},
options: {
layout: {
padding: {
right: 10
}
},
title: {
display: true,
text: 'Detections Over ' + days + 'd'
},
legend: {
display: false
},
scales: {
xAxes: [{
display: false,
gridLines: {
display: false // Hide the gridlines on the x-axis
},
ticks: {
autoSkip: true,
maxTicksLimit: 2
}
}],
yAxes: [{
gridLines: {
display: false // Hide the gridlines on the y-axis
},
ticks: {
beginAtZero: true,
precision: 0,
stepSize: 1
}
}]
}
}
});

var buttonRect = elem.getBoundingClientRect();
var chartRect = chartWindow.getBoundingClientRect();
if (window.innerWidth < 700) {
chartWindow.style.left = 'calc(75% - ' + (chartRect.width / 2) + 'px)';
} else {
chartWindow.style.left = (buttonRect.right + 10) + 'px';
}


// Calculate the top position of the chart to center it with the button
var buttonCenter = buttonRect.top + (buttonRect.height / 2);
var chartHeight = chartWindow.offsetHeight;
var chartTop = buttonCenter - (chartHeight / 2);
chartWindow.style.top = chartTop + 'px';

// Add a close button to the chart window
var closeButton = document.createElement('button');
closeButton.id = "chartcb";
closeButton.innerText = 'X';
closeButton.style.position = 'absolute';
closeButton.style.top = '5px';
closeButton.style.right = '5px';
closeButton.addEventListener('click', function() {
document.body.removeChild(chartWindow);
window.chartWindow = undefined;
});
chartWindow.appendChild(closeButton);
window.chartWindow = chartWindow;
}
};
xhr.send();
}

// Listen for the scroll event on the window object
window.addEventListener('scroll', function() {
// Get all chart elements
Expand Down
Loading