Skip to content

Instantly share code, notes, and snippets.

@mattogodoy
Created April 16, 2024 15:38
Show Gist options
  • Select an option

  • Save mattogodoy/1618f07e0966d846bfa64bf847535293 to your computer and use it in GitHub Desktop.

Select an option

Save mattogodoy/1618f07e0966d846bfa64bf847535293 to your computer and use it in GitHub Desktop.
A Greasemonkey/Violentmonkey script to bulk-delete events in Frigate
// ==UserScript==
// @name Frigate - Bulk delete events
// @namespace Violentmonkey Scripts
// @match http://192.168.1.120:8100/events*
// @grant none
// @version 1.0
// @author Matto Godoy
// @description Deletes multiple events one by one in Frigate NVR
// ==/UserScript==
const sleep = time => new Promise(res => setTimeout(res, time, "done sleeping"));
window.onload = function(){
// Wait for the page to load (it takes a good while)
console.log("Waiting...");
sleep(3000).then(msg => {
console.log("Let's go!");
addLinks();
});
};
// 1. Find the "PAST EVENTS" title so we can add the link under it
function findTitleLocation(){
var titleElement;
for (const h1 of document.querySelectorAll("h1")) {
if (h1.textContent.includes("Past Events")) {
titleElement = h1;
break;
}
}
return titleElement;
}
// 2. Add the Delete link
function addLinks(){
var titleEl = findTitleLocation();
// Add "Add checks" link
var html = '<a href="javascript:void(0);" style="color: green;">Add checks</a>';
var el = document.createElement('div');
el.innerHTML = html;
el.addEventListener('click', addCheckboxes);
titleEl.append(el);
// Add "Select all" link
var html = '<a href="javascript:void(0);" style="color: yellow;">Select all</a>';
var el = document.createElement('div');
el.innerHTML = html;
el.addEventListener('click', checkAllBoxes);
titleEl.append(el);
// Add "Delete" link
var html = '<a href="javascript:void(0);" style="color: red;">Delete all selected clips</a>';
var el = document.createElement('div');
el.innerHTML = html;
el.addEventListener('click', cleanClips);
titleEl.append(el);
}
// 3. Add checkboxes to all events in the list
function addCheckboxes(){
const events = document.getElementsByClassName('flex bg-slate-100 dark:bg-slate-800 rounded cursor-pointer min-w-[330px]');
for(i=0; i<events.length; i++){
var eventEl = events[i].childNodes[1].childNodes[2];
if(eventEl.childElementCount > 2)
continue; // Already has a checkbox
var html = '<input type="checkbox" id="deleteEvent_' + i + '" class="delete-event" onclick="event.stopPropagation();" />';
var checkboxEl = document.createElement('div');
checkboxEl.innerHTML = html;
eventEl.prepend(checkboxEl);
}
}
// Marks all boxes as checked
function checkAllBoxes(){
var checkboxes = document.getElementsByClassName('delete-event');
for (var i=0; i<checkboxes.length; i++) {
checkboxes[i].checked = true;
}
}
// 4. Get all checked boxes so we can delete those events
function getCheckedBoxes() {
var checkboxes = document.getElementsByClassName('delete-event');
var checkboxesChecked = [];
for (var i=0; i<checkboxes.length; i++) {
if (checkboxes[i].checked) {
checkboxesChecked.push(checkboxes[i]);
}
}
return checkboxesChecked.length > 0 ? checkboxesChecked : null;
}
// 5. Delete the clips that have their checkboxes checked
function cleanClips() {
const delayTime = 2000; // milliseconds
var checkboxes = getCheckedBoxes();
if(checkboxes == null)
return false;
for (var i=0; i<checkboxes.length; i++) {
(function(i) {
setTimeout(function() {
console.log("Deleting", i + 1, "of", checkboxes.length, "clips...");
var deleteButton = checkboxes[i].parentElement.parentElement.childNodes[1];
deleteButton.dispatchEvent(new Event('click'));
}, delayTime * i);
})(i);
}
}
@mattogodoy
Copy link
Author

mattogodoy commented Apr 16, 2024

This script allows you to delete many Frigate events in a simple way. Folks at Frigate are working on the new version of the UI (0.14), but in the meantime there's no other way to delete events than one by one.

To use this, you'll need Greasemonkey (if you use Firefox), or Violentmonkey (if you use Chrome).

  1. Install one of those
  2. Create a new script
  3. Add the contents of this Gist
  4. Change the line // @match http://192.168.1.120:8100/events* with the correct URL of your Frigate instance and save it
  5. Go to an events page
  6. Wait for 3 seconds and 3 links will appear
  7. Click "ADD CHECKS" to add checkboxes to all events
  8. Manually select the ones you want to delete. If you want to select all, just click "SELECT ALL"
  9. Click "DELETE ALL SELECTED CLIPS". This will delete only the ones you checked one by one. It takes a while since Frigate is quite slow in deleting them.
  10. When all the selected clips are deleted, you can repeat steps 7, 8 and 9 (no need to reload the page)

That's it! I hope you find this useful.

@mattogodoy
Copy link
Author

Here's a demo of how it works:

frigate-bulk-delete.mov

@NOYB4Europe
Copy link

Great idea. Thank you for your work.
I tried to use it with Greasemonkey and tampermonkey in Firefox but it did not work and I don't know how to fix it.
Tampermonkey had some syntax complains which I fixed :
I will reduce the retain to 1 day every now an than.

// ==UserScript==
// @name        Frigate - Bulk delete events
// @namespace   Violentmonkey Scripts
// @match       http://homeassistant.local:8123/events*, http://192.168.1.77:8123/events* 
// @grant       none
// @version     1.02
// @author      Matto Godoy
// @description Deletes multiple events one by one in Frigate NVR
// ==/UserScript==

const sleep = time => new Promise(res => setTimeout(res, time, "done sleeping"));

window.onload = function(){
    // Wait for the page to load (it takes a good while)
    console.log("Waiting...");
    sleep(3000).then(msg => {
        console.log("Let's go!");
        addLinks();
    });
};

// 1. Find the "PAST EVENTS" title so we can add the link under it
function findTitleLocation(){
    var titleElement;
    for (const h1 of document.querySelectorAll("h1")) {
        if (h1.textContent.includes("Past Events")) {
            titleElement = h1;
            break;
        }
    }
    return titleElement;
}

// 2. Add the Delete link

function addLinks(){
    var titleEl = findTitleLocation();
    // Add "Add checks" link
    var html = '<a href="javascript:void(0);" style="color: green;">Add checks</a>';
    var el = document.createElement('div');
    el.innerHTML = html;
    el.addEventListener('click', addCheckboxes);
    titleEl.append(el);
    // Add "Select all" link
    var html1 = '<a href="javascript:void(0);" style="color: yellow;">Select all</a>';
    var el1 = document.createElement('div');
    el1.innerHTML = html1;
    el1.addEventListener('click', checkAllBoxes);
    titleEl.append(el1);
    // Add "Delete" link
    var html2 = '<a href="javascript:void(0);" style="color: red;">Delete all selected clips</a>';
    var el2 = document.createElement('div');
    el2.innerHTML = html2;
    el2.addEventListener('click', cleanClips);
    titleEl.append(el2);
}

// 3. Add checkboxes to all events in the list

function addCheckboxes(){
    const events = document.getElementsByClassName('flex bg-slate-100 dark:bg-slate-800 rounded cursor-pointer min-w-[330px]');
    var i;
    for(i=0; i<events.length; i++){
        var eventEl = events[i].childNodes[1].childNodes[2];
        if(eventEl.childElementCount > 2){
            continue; }// Already has a checkbox
        var html = '<input type="checkbox" id="deleteEvent_' + i + '" class="delete-event" onclick="event.stopPropagation();" />';
        var checkboxEl = document.createElement('div');
        checkboxEl.innerHTML = html;
        eventEl.prepend(checkboxEl);
    }
}

// Marks all boxes as checked
function checkAllBoxes(){
    var checkboxes = document.getElementsByClassName('delete-event');
    for (var i=0; i<checkboxes.length; i++) {
        checkboxes[i].checked = true;
    }
}

// 4. Get all checked boxes so we can delete those events
function getCheckedBoxes() {
    var checkboxes = document.getElementsByClassName('delete-event');
    var checkboxesChecked = [];
    for (var i=0; i<checkboxes.length; i++) {
        if (checkboxes[i].checked) {
            checkboxesChecked.push(checkboxes[i]);
        }
    }
    return checkboxesChecked.length > 0 ? checkboxesChecked : null;
}

// 5. Delete the clips that have their checkboxes checked
function cleanClips() {
    const delayTime = 2000; // milliseconds
    var checkboxes = getCheckedBoxes();
    if(checkboxes == null)
    {return false;}
    for (var i=0; i<checkboxes.length; i++) {
        (function(i) {
            setTimeout(function() {
                console.log("Deleting", i + 1, "of", checkboxes.length, "clips...");
                var deleteButton = checkboxes[i].parentElement.parentElement.childNodes[1];
                deleteButton.dispatchEvent(new Event('click'));
            }, delayTime * i);
        })(i);
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment