Skip to content

Commit

Permalink
Added video thumbnail support
Browse files Browse the repository at this point in the history
  • Loading branch information
MrSleeps committed Feb 11, 2024
1 parent 82d1f42 commit 303a9b9
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 6 deletions.
15 changes: 12 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,36 @@
# Frigate Timelapser

This is a node app that helps generate timelapse videos from a Frigate feed.
This is a node app that helps generate timelapse videos from a Frigate feed. It takes a snapshot every few seconds and when called will create a timelapse of the last 15 seconds.

# Why did I write this?

Because at the time Frigate didn't have a timelapse function and I find the one that it currently has clunky and unreliable. I wanted something that I could easily call from Home Assistant and it generate a video when, for example, my front door opens.

It's very much a work in progress and has next to no error checking. It does however work, I've been using it for a about a year, sending videos to my telegram via Home Assistant.


## How to get it running..

You can run it locally via node (and maybe PM2) or via Docker:

You can either build it yourself or grab it from DockerHub.

If you are building it yourself:

```bash
git clone https://github.com/MrSleeps/FrigateTimelapser.git
cd FrigateTimelapser
./build
```
Once it's built (hopefully without errors), copy the docker-compose file below and make the relevant changes
Once it's built (hopefully without errors), or you are grabbing it direct from DockerHub, you need to copy the docker-compose file below and make the relevant changes


```bash
version: '3.6'

services:
flame:
image: mrsleeps/frigate-timelapser
image: mrsleeps/frigate-timelapse
container_name: frigate-timelapser
volumes:
- ${PWD}/files:/app/files
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "Frigate Timelapser",
"version": "1.0.1",
"version": "1.0.2",
"description": "Generate Timelapse videos from Frigate",
"author": "MrSleeps",
"main": "server.js",
Expand Down
42 changes: 42 additions & 0 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,18 +67,33 @@ app.get('/', (req, res) => {
app.get('/c/:camera', (req, res) => {
var camera = req.params.camera;
var imagePath = imageDirPath+camera;
var videoPath = videoDirPath+camera;
const dirents = fs.readdirSync(imagePath, { withFileTypes: true });
const unSortedImages = dirents
.filter(dirent => dirent.isFile())
.map(dirent => dirent.name);
var images = unSortedImages.slice(Math.max(unSortedImages.length - 10, 0)).reverse();

const direntsv = fs.readdirSync(videoPath, { withFileTypes: true });
const unSortedVideos = direntsv
.filter(direntsv => direntsv.isFile())
.map(dirent => dirent.name);
var filteredVideos = unSortedVideos.filter(function(value) {
var ext = path.extname(value);
return ['.png'].indexOf(ext) == -1;
});
var videos = filteredVideos.slice(Math.max(filteredVideos.length - 10, 0)).reverse();
res.render('pages/cameras', {
frigateurl: config.frigateBaseURL,
cameras: config.cameras,
images: images,
videos: videos,
camera: camera,
pagesubtitle: "View camera snapshots"
});
console.log(images)
console.log("Videos at:"+videoPath)
console.log(filteredVideos)
});

app.get('/timelapse/generate', (req, res) => {
Expand All @@ -100,6 +115,19 @@ app.get('/v/watch/:camera/:filename', (req, res) => {
});
});

app.get('/v/thumb/:camera/:filename/:pointless', (req, res) => {
var file = req.params.filename;
var camera = req.params.camera;
var fileWithPath = videoDirPath+camera+'/'+file
console.log(fileWithPath)
if (!fs.existsSync(fileWithPath)) {
res.sendFile(__dirname + '/public/images/not-found.jpg')
} else {
res.sendFile(videoDirPath+camera+'/tn_'+file+'.png');
}

});

app.get('/v/t/:camera/:filename', (req, res) => {
var camera = req.params.camera;
var file = req.params.filename;
Expand Down Expand Up @@ -190,6 +218,20 @@ app.get('/:camera/timelapse/:hass/:json', (req, res) => {
json: true,
timeout: 10 * 60 * 1000 //10 minutes
}
// create thumbnail
// videoFilename
var proc = ffmpeg(videoFilename)
.on('filenames', function(filenames) {
console.log('screenshots are ' + filenames.join(', '));
})
.on('end', function() {
console.log('screenshots were saved');
})
.on('error', function(err) {
console.log('an error happened: ' + err.message);
})
// take 1 screenshots at predefined timemarks and size
.takeScreenshots({ count: 1, timemarks: [ '00:00:07.000' ], size: '300x169', filename: 'tn_'+videoDate+'.mp4.png' }, dirPathVideoCamera);
if(fromHomeAssistant == 1 && config.postToHomeAssistant == 1) {
jsonString = '{"video": ' + config.timeLapseURL + '/' + req.params['camera'] + '/' + videoDate + '.mp4"}'
needle.post(config.homeAssistantURL+'/api/webhook/'+config.homeAssistantToken, jsonString, requestOptions)
Expand Down
18 changes: 16 additions & 2 deletions views/pages/cameras.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,23 @@
</div>
</div>
<% }); %>


</div>
<hr>
<h1>Latest Videos</h1>
<div class="row row-cols-1 row-cols-sm-2 row-cols-md-4 g-3">
<% videos.forEach(function(video){ %>
<div class="col">
<div class="card shadow-sm">
<a href="/v/t/<%= camera %>/<%= video %>" data-toggle="lightbox" data-gallery="latest-videos">
<img class="img-thumbnail" src="/v/thumb/<%= camera %>/<%= video %>/png" />
</a>
<div class="card-body">
<p class="card-text"><%= video %></p>
</div>
</div>
</div>
<% }); %>
</div>
</main>


Expand Down

0 comments on commit 303a9b9

Please sign in to comment.