Skip to content

Instantly share code, notes, and snippets.

@danshev
Last active July 2, 2019 23:17
Show Gist options
  • Save danshev/5393bb1741e845ec17d30b6655dac547 to your computer and use it in GitHub Desktop.
Save danshev/5393bb1741e845ec17d30b6655dac547 to your computer and use it in GitHub Desktop.
TeslaCam-Create-Playlist (for AWS Lambda)
/*
Function: TeslaCam-Create-Playlist
Runtime: Node.js 10.x
Environment: AWS Lambda
Description:
This function is meant to be triggered by a periodic CloudWatch Event.
Upon execution, it will scan an S3 bucket (containing TeslaCam files),
build an M3U playlist of processed / merged TeslaCam videos, determine
how many *new* videos were added, and push a message to AWS SNS (for alerting).
Environment Variables:
- S3_BUCKET = the.name.of.your.bucket
- SNS_ARN = your:arn:for:aws:sns:etc-etc
Assumptions:
1. Your S3 bucket is only used for TeslaCam work
2. You're using the other two Lambdas:
- TeslaCam-Identify-Sets-and-Kickoff
- TeslaCam-Merge-Videos
3. This Lambda function has a permissions Role enabling it to:
a. Read from and Write to S3
b. Publish to SNS
c. (Recommended) Write to CloudWatch Logs
*/
let AWS = require('aws-sdk');
let s3 = new AWS.S3();
let readline = require('readline');
exports.handler = async (event) => {
var myProxyResponseObj = {
statusCode: 500,
body: JSON.stringify('It worked!'),
};
let playlistParams = { Bucket: process.env.S3_BUCKET, Key: 'playlist.m3u' };
// Check if a playlist exists and populate previousVideos array
var previousVideos = [];
try {
await s3.headObject(playlistParams).promise();
// Download the current playlist
let s3ReadStream = s3.getObject(playlistParams).createReadStream();
let rl = readline.createInterface({ input: s3ReadStream, terminal: false });
let myPromise = new Promise((resolve, reject) => {
rl.on('line', (line) => {
if (line.indexOf("https") >= 0) {
previousVideos.push(line.match(/[^\/]+\/[^\/]+$/g)[0]);
}
});
rl.on('error', () => { console.log('error'); });
rl.on('close', () => { resolve(); });
})
try { await myPromise; }
catch(err) {
myProxyResponseObj.body = JSON.stringify({ "message": err.message });
return myProxyResponseObj;
}
}
catch (err) {
console.log('There was no previous playlist file (no big deal)');
}
// Retrieve the keys of previously-processed videos
var data;
try { data = await s3.listObjectsV2({ Bucket: process.env.S3_BUCKET, Prefix: 'fullscreen' }).promise(); }
catch (err) {
myProxyResponseObj.statusCode = err.statusCode;
myProxyResponseObj.body = JSON.stringify({ "message": err.message });
return myProxyResponseObj;
}
// Build playlist file
var currentVideos = [];
var playlist = "#EXTM3U\n";
for (const obj of data.Contents) {
currentVideos.push(obj.Key);
playlist = playlist.concat("#EXTINF:60, "+ obj.Key.split("/")[1] +"\n");
playlist = playlist.concat("https://s3.amazonaws.com/"+ process.env.S3_BUCKET +"/"+ obj.Key +"\n");
}
var params = {
ACL: "public-read",
Bucket: process.env.S3_BUCKET,
Key: 'playlist.m3u',
ContentType: 'text/plain',
Body: playlist.trim()
};
// Upload the file to S3
try { await s3.putObject(params).promise(); }
catch(err) {
myProxyResponseObj.body = JSON.stringify({ "message": err.message });
return myProxyResponseObj;
}
// ==> Determine if there were any new videos in the updated playlist
let newVideos = currentVideos.filter(
function(e) { return this.indexOf(e) < 0; }, previousVideos
);
// If there were new videos, publish to SNS
if (newVideos.length > 0) {
let correctWording = newVideos.length == 1 ? " video is " : " videos are ";
let sns = new AWS.SNS();
params = {
Message: newVideos.length +" new"+ correctWording +"available! \n\nhttps://s3.amazonaws.com/shevenell.teslacam/playlist.m3u",
Subject: "New Videos",
TopicArn: process.env.SNS_ARN
};
try { await sns.publish(params).promise(); }
catch(err) {
console.log(err);
}
}
myProxyResponseObj.statusCode = 200;
return myProxyResponseObj;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment