-
Notifications
You must be signed in to change notification settings - Fork 21
/
Copy pathserver.js
547 lines (478 loc) Β· 19.1 KB
/
server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
// server.js
// modules =================================================
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var methodOverride = require('method-override');
var multer = require('multer');
var ffmpeg = require("fluent-ffmpeg");
var mongo = require('mongodb');
var mongoose = require('mongoose');
var fs = require('fs');
//Set up and start our Node.js server
// set our port
var port = process.env.PORT || 3000;
// set the static files location /public/img will be /img for users
app.use(express.static(__dirname + '/public'));
//app.use('/Video Uploads',express.static(__dirname + '/Video Uploads'));
// routes ==================================================
require('./app/routes')(app); // configure our routes
// start app ===============================================
// startup our app at http://localhost:3000
app.listen(port);
// shoutout to the user
console.log('Magic happens on port ' + port);
//Let's connect to MongoDB now
mongoose.connect('mongodb://localhost/flowbase', function(err) {
if(err) {
console.log('Connection error for MongoDB', err);
} else {
console.log('Connection successful to MongoDB');
}
});
//Create schemas
//Create a project schema
var ProjectsSchema = new mongoose.Schema({
"name": {"type":"String","unique":true},
"date_played":{"type":"Date"},
"local_team":"String",
"opposition_team":"String",
"season":"String",
"competition":"String",
"local_team_score":"Number",
"opposition_team_score":"Number",
"collection_name":"String",
"video":"String",
"date_created": { "type": "Date", "default": Date.now }
});
//Creates a collections schema to keep track of collections of events
var CollectionsSchema = new mongoose.Schema({
"name":{"type":"String","unique":true},
"date_created": {"type":"Date","default":Date.now}
});
//Creates a collections schema to keep track of collections of events
var ProjectCollectionsSchema = new mongoose.Schema({
"name":{"type":"String","unique":true},
"date_created": {"type":"Date","default":Date.now}
});
//Create an events definition schema which will be used to create events definition collection for the current project
var EventsSchema = new mongoose.Schema({
"collection_name":"String",
"event_name":"String",
"lead_time":"Number",
"lag_time":"Number"
});
//Create a schema for videos uploaded in (by default in /public/Video Uploads/)
var VideosUploadedSchema = new mongoose.Schema({
"video_name":"String",
"file_location":"String",
"format":"String",
"file_size":"Number" //In megabytes
});
//Create schema for videos converted in /public/Videos Converted
var VideosConvertedSchema = new mongoose.Schema({
"video_name":"String",
"path": "String",
"format":"String",
"width":"Number",
"height":"Number",
"frame_rate":"Number",
"aspect_ratio":"String",
"codec":"String"
});
//Create tags schema
var TagsSchema = new mongoose.Schema({
"tag_name":{"type":"String", "unique":true},
"event_name":"String",
"collection_name":"String",
"project_name":"String",
"video_name":"String",
"video_path":"String",
"start_time":"Number",
"end_time":"Number",
"date_created": {"type":"Date","default":Date.now}
});
//Create collections using schemas that we just defined
var ProjectsCollection = mongoose.model('projects', ProjectsSchema);
var CollectionsCollection = mongoose.model('collections',CollectionsSchema);
var ProjectCollectionsCollection = mongoose.model('project_collections', ProjectCollectionsSchema);
var EventsCollection = mongoose.model('events',EventsSchema);
var VideosUploadedCollection = mongoose.model('videos_uploaded', VideosUploadedSchema);
var VideosConvertedCollection = mongoose.model('videos',VideosConvertedSchema);
var TagsCollection = mongoose.model('tags',TagsSchema);
// middleware ==============================================
//Database middleware
//Projects Manager Middleware
//CRUD for projects
//READ: Get projects from projects table in database
app.use('/getprojects',function (req,res) {
ProjectsCollection.find(function (err, projects) {
if (err) res.send("Error fetching projects from database.");
else {
res.send(projects);
}
});
});
app.use('/getcurrentproject',bodyParser.json(), function (req,res) {
ProjectsCollection.find({"name":req.body.project_name}, function (err,project) {
if (err) res.send([{"name":"Error fetching project. Error message: "+err}])
else res.send(project);
});
})
//CREATE: Add a new project
app.use('/copycollectiontoproject', bodyParser.json(), function (req,res) {
console.log("Copying collection");
//Let's create a collection with the same name inside project collection table, with date appended
var projectCollectionName = req.body.collection_name + Date.now();
console.log('new pc name', projectCollectionName);
var newProjectCollection = new ProjectCollectionsCollection ({"name": projectCollectionName});
newProjectCollection.save();
//Now create new events in the events collection that will be linked to this new project collection
//First find all events
var eventsToCopy;
EventsCollection.find({"collection_name":req.body.collection_name}, function (err,events) {
eventsToCopy = events;
console.log('eventsToCopy',eventsToCopy);
//Now copy each event and change the collection name to the new projectCollectionName
var newEvent;
var copiedEvents = [];
var idx = 0;
for (idx = 0; idx<eventsToCopy.length; idx++) {
console.log("currentEvent", eventsToCopy[idx]);
//Create new event
newEvent = {"collection_name":projectCollectionName,
"event_name":eventsToCopy[idx].event_name,
"lead_time":eventsToCopy[idx].lead_time,
"lag_time":eventsToCopy[idx].lag_time
};
//Add the event to array
copiedEvents.push(newEvent);
}
//Insert this array of documents (events) into EventsCollection
EventsCollection.create(copiedEvents, function (err,successfullyCopied) {
console.log("Events to copy", eventsToCopy.length, "Successfully copied", successfullyCopied);
res.send({"project_collection":projectCollectionName});
});
});
});
app.use ('/addproject', bodyParser.json(), function (req,res) {
var projectName = req.body.projectName;
var newProject = new ProjectsCollection({
"name": req.body.projectName,
"date_played": req.body.datePlayed,
"local_team":req.body.localTeam,
"opposition_team":req.body.oppositionTeam,
"season":req.body.season,
"competition":req.body.competition,
"local_team_score":req.body.localTeamScore,
"opposition_team_score":req.body.oppositionTeamScore,
"collection_name": req.body.collection,
"video":req.body.video});
newProject.save(function(err){
if(err) res.send({"success":false,"error":err});
else {
res.send({"success":true});
}
});
});
//UPDATE: Update project
app.use('/updateproject', bodyParser.json(), function (req,res) {
ProjectsCollection.update({ "name": req.body.project_name},
{ "date_played": req.body.date_played,
"local_team":req.body.local_team,
"opposition_team":req.body.opposition_team,
"season":req.body.season,
"competition":req.body.competition,
"local_team_score":req.body.local_team_score,
"opposition_team_score":req.body.opposition_team_score,
"video":req.body.video
},
function (err, numberAffected, raw_response) {
if (err) res.send({"success":false, "error":err});
else {
res.send({"success":true})
}
});
})
//DELETE: Delete a project
app.use('/deleteproject', bodyParser.json(), function (req,res) {
var projectName = req.body.projectName;
var projectCollection;
//Get the name of the collection linked to the project, delete the collection and its events, project tags and finally the project.
ProjectsCollection.find({'name':projectName}, function (err, projectObject) {
console.log("Found project", projectObject,"err",err);
if (err) res.send({"success":false,"error":err});
else {
projectCollection = projectObject[0].collection_name;
console.log("project collection", projectCollection);
//Delete the collection
ProjectCollectionsCollection.remove({'name':projectCollection}, function (err) {
console.log("Collection removed!");
if (err) res.send({"success":false, "error":err});
else {
//Delete the events in the collection
EventsCollection.remove({'collection_name':projectCollection}, function (err) {
console.log("Events removed");
if (err) res.send({"success":false, "error":err});
else {
//Delete tags
TagsCollection.remove({"project_name":projectName}, function (err) {
if (err) res.send({"success":false,"error":err});
//Now finally delete the project
console.log("Deleting project");
ProjectsCollection.remove({'name': projectName}, function (err) {
if (err) res.send({"success":false, "error":err});
else res.send({"success":true});
});
});
}
});
}
});
}
});
});
//Collections Manager Middleware
//CR(U)D for collections: No update required as this will be done through events CRUD
//CREATE: Add a new collection
app.use('/addcollection', bodyParser.json(), function (req,res) {
var newCollection = new CollectionsCollection ({"name":req.body.collectionName});
newCollection.save(function (err) {
if (err) res.send({"success":false,"error":err});
else res.send({"success": true});
});
});
//READ: Get exisiting collections
app.use('/getcollections',function (req,res) {
CollectionsCollection.find(function (err, collections) {
if (err) res.send([{"name":"Error fetching collections. Error message: "+err}])
else res.send(collections);
});
});
//DELETE: Remove an existing collection
app.use('/deletecollection',bodyParser.json(),function (req,res) {
//First delte the collection from the Collections collection
CollectionsCollection.remove({'name':req.body.collectionName},function (err) {
if (err) res.send({"success":false,"error":err});
else {
//Now delete the events linked to this collection
EventsCollection.remove({'collection_name':req.body.collectionName}, function (err) {
if (err) res.send({"success":false, "error":err});
else res.send({"success":true});
});
}
});
})
//Events Manager Middleware
//CRUD for events
//Get events for a collection
//CREATE: Add event to collection
app.use('/addevent', bodyParser.json(), function (req,res) {
var newEvent = new EventsCollection({"collection_name":req.body.collection_name,"event_name":req.body.event_name,"lead_time":req.body.lead_time,"lag_time":req.body.lag_time});
newEvent.save(function (err) {
if (err) res.send({"success":false,"error":err});
else {
EventsCollection.find(function(err,events) {
res.send({"success":true,"number_of_events":events.length,"events":events});
});
}
});
});
//READ: Get all events for the selected collection
app.use('/getevents',bodyParser.json(), function (req,res) {
console.log("getting events for",req.body.collectionName);
var collectionName = req.body.collectionName;
EventsCollection.find({"collection_name":collectionName}, function (err,events) {
if (err) res.send([{"name":"Error fetching events for this collection. Error message: "+err}])
else res.send(events);
});
});
//UPDATE: Update an event in the collection
app.use('/updateevent',bodyParser.json(), function (req,res) {
EventsCollection.update({ "collection_name": req.body.collection_selected, "event_name":req.body.event_selected },
{ "event_name": req.body.event_name, "lag_time":req.body.lag_time, "lead_time":req.body.lead_time}, function (err, numberAffected, raw_response) {
if (err) res.send({"success":false, "error":err});
else {
res.send({"success":true})
}
});
});
//DELETE: Delete an event in the collection
app.use('/deleteevent',bodyParser.json(),function (req,res) {
EventsCollection.remove({'collection_name':req.body.collectionName, "event_name":req.body.eventName},function (err) {
if (err) res.send({"success":false,"error":err});
else res.send({"success":true});
});
})
//Video Manager middleware
//Create global variable for file name of video
var newFileName;
//Parse the file name before uploading file
app.use('/fileName', bodyParser.json(),function (request,response,next) {
newFileName = request.body.file_name;
response.send("Done parsing file name.");
});
app.use('/upload',multer({ dest: './public/Video Uploads/',
rename: function (fieldname,filename,request) {
return newFileName;
},
onFileUploadStart: function (file) {
console.log(file.originalname + ' is starting ...');
},
onFileUploadComplete: function (file,request,response) {
console.log(file.originalname + ' uploaded to ' + file.path);
fileName = file.originalname;
uploadPath = file.path;
response.send([fileName,uploadPath]);
}
}));
//Function gets the metadata (using ffprobe) of a video file passed to it, and then returns the metadata object
app.use('/getVideoMetaData',bodyParser.json(), function (request,response,next) {
var fileName = request.body.fileName;
var filePath = request.body.filePath;
ffmpeg.ffprobe(filePath, function(err, metadata) {
response.send(metadata);
});
});
//Function to check if a folder exists, otherwise create it
function ensureExists(path, mask, cb) {
if (typeof mask == 'function') { // allow the `mask` parameter to be optional
cb = mask;
mask = 0777;
}
fs.mkdir(path, mask, function(err) {
if (err) {
if (err.code == 'EEXIST') cb(null); // ignore the error if the folder already exists
else cb(err); // something else went wrong
} else cb(null); // successfully created folder
});
}
//Converts video using ffmpeg
app.use('/convert',bodyParser.json(), function (request,response,next) {
var fileName = request.body.fileName;
var filePath = request.body.filePath;
var newVideoName = fileName.split('.')[0]+Date.now()+'.mp4'; //MR is for Maxflow Ready
var savePath = 'public/Videos Converted/'+newVideoName;
ensureExists('public/Videos Converted/', 0744, function(err) {
if (err) console.log("Count not create folder ",err); // handle folder creation error
else {
console.log("Folder successfully created or already exists - no error");// we're all good
var format = 'mp4';
var convertedVideo = ffmpeg(filePath)
.fps(request.body.framerate)
.size(request.body.resolution)
.autopad()
.format(format)
.on('end', function() { response.send({"success":true, "video_name":newVideoName, "saved_path":savePath});})
.on('error',function(error) {response.send({"success":false, "error":error.message});})
.on('progress', function(progress) { console.log('Processing: ' + progress.percent + '% done');})
.save(savePath);
}
});
});
//CRUD for Video Manager - Middleware
//CREATE: Adds video that has been converted to the videos collection in flowbase MongoDB
app.use('/addconvertedvideo', bodyParser.json(), function (request, response,next) {
var videoName = request.body.video_name;
var videoPath = request.body.saved_path;
ffmpeg.ffprobe(videoPath, function(err, metadata) {
//Now add to VideosConvertedCollection, -1 means undefined or unknown in the database
var width = metadata.streams[0].width;
var height = metadata.streams[0].height;
var aspect = metadata.streams[0].display_aspect_ratio;
var fr = metadata.streams[0].r_frame_rate.split('/');
var frame_rate = Math.round(fr[0]/fr[1]);
var codec = metadata.streams[0].codec_name;
if (metadata.streams[0].width == undefined) width = -1;
if (metadata.streams[0].height== undefined) height= -1;
if (aspect == "0:1" || aspect == undefined) currentAspect = -1;
if (fr[0] == "0" || fr == undefined) frame_rate = -1;
//Create document for collection
var newConvertedVideo = new VideosConvertedCollection({
"video_name":videoName,
"path":videoPath,
"format":'mp4',
"width":width,
"height":height,
"frame_rate": frame_rate,
"aspect_ratio": aspect,
"codec":codec
});
//Save the document to the database
newConvertedVideo.save(function (err) {
if (err) response.send({"success":false,"error":err})
else response.send({"success":true});
});
});
});
//READ: Returns JSON object of all videos in the VideosConvertedCollection collection in MongoDB flowbase
app.use('/getconvertedvideos', function (request,response) {
VideosConvertedCollection.find(function (err, videos) {
if (err) response.send("Error fetching videos from database.");
else {
response.send(videos);
}
});
});
//UPDATE: Not required right now.
//Add an update function to the video manager which will allow the user to change vide name, and also convert video to different resolutions etc.
//DELETE: Remove video from collection and delete the corresponding video file as well.
app.use('/deletevideo', bodyParser.json(), function (request, response) {
//Delete the actual video file
fs.unlink(request.body.path, function (err) {
if (err) console.log(err);
else {
//Now delete the database reference to the video file
VideosConvertedCollection.remove({"path":request.body.path} ,function (err) {
if (err) response.send({"success":false,"error":err});
else response.send({"success":true});
});
}
});
});
//POST response when /getvideopath is sent from front end with name of video, video path is fetched from the converted videos table
app.use('/getvideopath', bodyParser.json(),function (request,response) {
console.log("Express is getting video path for "+request.body.video_name);
VideosConvertedCollection.find({"video_name":request.body.video_name},function (err,video_data) {
console.log("Fetched path..."+video_data[0].path);
if (err) response.send("Error fetching video path from database.");
else response.send({"success":true, "path":video_data[0].path});
});
})
//CRUD for Tags collection
//Add tag
app.use('/addtag',bodyParser.json(), function (request,response) {
//Create document for collection
var newTag = new TagsCollection({
"tag_name":request.body.tag_name,
"event_name":request.body.event_name,
"collection_name":request.body.collection_name,
"project_name":request.body.project_name,
"video_name":request.body.video_name,
"video_path":request.body.video_path,
"start_time":request.body.start_time,
"end_time":request.body.end_time,
});
//Save the document to the database
newTag.save(function (err) {
if (err) response.send({"success":false,"error":err})
else response.send({"success":true});
});
})
//Get all tags for a project and return the object
app.use('/getprojecttags',bodyParser.json(), function (request, response) {
TagsCollection.find({"project_name":request.body.project_name}, function (err,tags) {
console.log("Express has fetched tag object..."+tags);
if (err) response.send({"success":false, "error":"Error fetching tags for this project: "+err});
else response.send({"success":true, "tagsObject":tags});
});
});
//Delete tag
app.use('/deletetag',bodyParser.json(), function (request, response) {
TagsCollection.remove({"tag_name":request.body.tag_name}, function(err) {
if (err) response.send({"success":false, "error":"Error deleting tag."+err});
else response.send({"success":true});
});
});
// Expose app so that server.js can be required by other modules
exports = module.exports = app;