Update Cloud Uploaders
parent
f956271e5e
commit
c548692754
|
@ -441,6 +441,7 @@
|
|||
"Endpoint Address": "Endpoint Address",
|
||||
"Custom Endpoint": "Custom Endpoint",
|
||||
"Bucket": "Bucket",
|
||||
"Bucket ID": "Bucket ID",
|
||||
"Region": "Region",
|
||||
"Use Global Amazon S3 Video Storage": "Use Global Amazon S3 Video Storage",
|
||||
"Use Global Wasabi Hot Cloud Storage Video Storage": "Use Global Wasabi Hot Cloud Storage Video Storage",
|
||||
|
|
|
@ -6,4 +6,11 @@ module.exports = async function(s,config){
|
|||
await addColumn('Monitors',[
|
||||
{name: 'tags', length: 500, type: 'string'},
|
||||
])
|
||||
await addColumn('Cloud Videos',[
|
||||
{name: 'type', type: 'string', length: 15, defaultTo: 's3'},
|
||||
{name: 'ext', type: 'string', length: 10, defaultTo: 'mp4'},
|
||||
])
|
||||
await addColumn('Cloud Timelapse Frames',[
|
||||
{name: 'type', type: 'string', length: 15, defaultTo: 's3'},
|
||||
])
|
||||
}
|
||||
|
|
|
@ -95,12 +95,12 @@ module.exports = function(s,config,lang,app,io){
|
|||
})
|
||||
}
|
||||
}
|
||||
s.deleteTimelapseFrameFromCloud = function(e){
|
||||
s.deleteTimelapseFrameFromCloud = function(e,cloudType){
|
||||
// e = video object
|
||||
s.checkDetails(e)
|
||||
var frameSelector = {
|
||||
ke: e.ke,
|
||||
mid: e.id,
|
||||
type: cloudType,
|
||||
time: new Date(e.time),
|
||||
}
|
||||
s.knexQuery({
|
||||
|
@ -118,7 +118,7 @@ module.exports = function(s,config,lang,app,io){
|
|||
where: frameSelector,
|
||||
limit: 1
|
||||
},function(){
|
||||
s.onDeleteTimelapseFrameFromCloudExtensionsRunner(e,r)
|
||||
s.onDeleteTimelapseFrameFromCloudExtensionsRunner(e,details.type || r.type || 's3',r)
|
||||
})
|
||||
}else{
|
||||
// console.log('Delete Failed',e)
|
||||
|
|
|
@ -1,6 +1,30 @@
|
|||
var fs = require('fs');
|
||||
// https://us-east-1.console.aws.amazon.com/iamv2/home#/users
|
||||
|
||||
const fs = require('fs');
|
||||
const { S3Client, PutObjectCommand, DeleteObjectCommand, GetObjectCommand } = require("@aws-sdk/client-s3");
|
||||
|
||||
module.exports = function(s,config,lang){
|
||||
//Amazon S3
|
||||
const genericRequest = async (groupKey,requestOptions) => {
|
||||
const response = {ok: true}
|
||||
try {
|
||||
await s.group[groupKey].aws_s3.send(requestOptions);
|
||||
} catch (err) {
|
||||
console.error('AMZ genericRequest',groupKey,requestOptions)
|
||||
response.ok = false
|
||||
response.err = err
|
||||
}
|
||||
return response;
|
||||
};
|
||||
const deleteObject = async (groupKey,options) => {
|
||||
return await genericRequest(groupKey,new DeleteObjectCommand(options))
|
||||
};
|
||||
const uploadObject = async (groupKey,options) => {
|
||||
return await genericRequest(groupKey,new PutObjectCommand(options))
|
||||
};
|
||||
const getObject = async (groupKey,options) => {
|
||||
// returns createReadStream
|
||||
return await s.group[groupKey].aws_s3.send(new GetObjectCommand(options))
|
||||
};
|
||||
function beforeAccountSave(d){
|
||||
//d = save event
|
||||
d.formDetails.aws_use_global=d.d.aws_use_global
|
||||
|
@ -29,7 +53,7 @@ module.exports = function(s,config,lang){
|
|||
userDetails = Object.assign(userDetails,config.cloudUploaders.AmazonS3)
|
||||
}
|
||||
//Amazon S3
|
||||
if(!s.group[e.ke].aws &&
|
||||
if(
|
||||
!s.group[e.ke].aws_s3 &&
|
||||
userDetails.aws_s3 !== '0' &&
|
||||
userDetails.aws_accessKeyId !== ''&&
|
||||
|
@ -45,17 +69,16 @@ module.exports = function(s,config,lang){
|
|||
if(userDetails.aws_s3_dir !== ''){
|
||||
userDetails.aws_s3_dir = s.checkCorrectPathEnding(userDetails.aws_s3_dir)
|
||||
}
|
||||
s.group[e.ke].aws = new require("aws-sdk")
|
||||
s.group[e.ke].aws.config = new s.group[e.ke].aws.Config({
|
||||
accessKeyId: userDetails.aws_accessKeyId,
|
||||
secretAccessKey: userDetails.aws_secretAccessKey,
|
||||
s.group[e.ke].aws_s3 = new S3Client({
|
||||
credentials: {
|
||||
accessKeyId: userDetails.aws_accessKeyId,
|
||||
secretAccessKey: userDetails.aws_secretAccessKey,
|
||||
},
|
||||
region: userDetails.aws_region
|
||||
})
|
||||
s.group[e.ke].aws_s3 = new s.group[e.ke].aws.S3();
|
||||
});
|
||||
}
|
||||
}
|
||||
function unloadGroupApp(user){
|
||||
s.group[user.ke].aws = null
|
||||
s.group[user.ke].aws_s3 = null
|
||||
}
|
||||
function deleteVideo(e,video,callback){
|
||||
|
@ -68,55 +91,55 @@ module.exports = function(s,config,lang){
|
|||
if(!videoDetails.location){
|
||||
videoDetails.location = video.href.split('.amazonaws.com')[1]
|
||||
}
|
||||
if(videoDetails.type !== 's3'){
|
||||
if(video.type !== 's3'){
|
||||
callback()
|
||||
return
|
||||
}
|
||||
try{
|
||||
s.group[video.ke].aws_s3.deleteObject({
|
||||
Bucket: s.group[video.ke].init.aws_s3_bucket,
|
||||
Key: videoDetails.location,
|
||||
}, function(err, data) {
|
||||
if (err) console.log(err);
|
||||
callback()
|
||||
});
|
||||
}catch(err){
|
||||
console.log('Amazon S3 DELETE Error',err)
|
||||
deleteObject(video.ke,{
|
||||
Bucket: s.group[video.ke].init.aws_s3_bucket,
|
||||
Key: videoDetails.location,
|
||||
}).then((response) => {
|
||||
if (response.err){
|
||||
console.error('Amazon S3 DELETE Error')
|
||||
console.error(err);
|
||||
}
|
||||
callback()
|
||||
}
|
||||
});
|
||||
}
|
||||
function uploadVideo(e,k){
|
||||
function uploadVideo(e,k,insertQuery){
|
||||
//e = video object
|
||||
//k = temporary values
|
||||
if(!k)k={};
|
||||
//cloud saver - amazon s3
|
||||
if(s.group[e.ke].aws_s3 && s.group[e.ke].init.use_aws_s3 !== '0' && s.group[e.ke].init.aws_s3_save === '1'){
|
||||
var ext = k.filename.split('.')
|
||||
ext = ext[ext.length - 1]
|
||||
var fileStream = fs.createReadStream(k.dir+k.filename);
|
||||
const groupKey = insertQuery.ke
|
||||
if(s.group[groupKey].aws_s3 && s.group[groupKey].init.use_aws_s3 !== '0' && s.group[groupKey].init.aws_s3_save === '1'){
|
||||
const filename = `${s.formattedTime(insertQuery.time)}.${insertQuery.ext}`
|
||||
var fileStream = fs.createReadStream(k.dir+filename);
|
||||
fileStream.on('error', function (err) {
|
||||
console.error(err)
|
||||
})
|
||||
var saveLocation = s.group[e.ke].init.aws_s3_dir+e.ke+'/'+e.mid+'/'+k.filename
|
||||
s.group[e.ke].aws_s3.upload({
|
||||
Bucket: s.group[e.ke].init.aws_s3_bucket,
|
||||
var saveLocation = s.group[groupKey].init.aws_s3_dir+groupKey+'/'+e.mid+'/'+filename
|
||||
uploadObject(groupKey,{
|
||||
Bucket: s.group[groupKey].init.aws_s3_bucket,
|
||||
Key: saveLocation,
|
||||
Body: fileStream,
|
||||
ContentType: 'video/'+ext
|
||||
},function(err,data){
|
||||
if(err){
|
||||
s.userLog(e,{type:lang['Amazon S3 Upload Error'],msg:err})
|
||||
ContentType: 'video/'+e.ext
|
||||
}).then((response) => {
|
||||
if(response.err){
|
||||
s.userLog(e,{type:lang['Amazon S3 Upload Error'],msg:response.err})
|
||||
}
|
||||
if(s.group[e.ke].init.aws_s3_log === '1' && data && data.Location){
|
||||
if(s.group[groupKey].init.aws_s3_log === '1' && response.ok){
|
||||
s.knexQuery({
|
||||
action: "insert",
|
||||
table: "Cloud Videos",
|
||||
insert: {
|
||||
mid: e.mid,
|
||||
ke: e.ke,
|
||||
time: k.startTime,
|
||||
ke: groupKey,
|
||||
ext: insertQuery.ext,
|
||||
time: insertQuery.time,
|
||||
status: 1,
|
||||
type : 's3',
|
||||
details: s.s({
|
||||
type : 's3',
|
||||
location : saveLocation
|
||||
}),
|
||||
size: k.filesize,
|
||||
|
@ -124,13 +147,13 @@ module.exports = function(s,config,lang){
|
|||
href: ''
|
||||
}
|
||||
})
|
||||
s.setCloudDiskUsedForGroup(e.ke,{
|
||||
s.setCloudDiskUsedForGroup(groupKey,{
|
||||
amount: k.filesizeMB,
|
||||
storageType: 's3'
|
||||
})
|
||||
s.purgeCloudDiskForGroup(e,'s3')
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
function onInsertTimelapseFrame(monitorObject,queryInfo,filePath){
|
||||
|
@ -141,17 +164,16 @@ module.exports = function(s,config,lang){
|
|||
console.error(err)
|
||||
})
|
||||
var saveLocation = s.group[e.ke].init.aws_s3_dir + e.ke + '/' + e.mid + '_timelapse/' + queryInfo.filename
|
||||
s.group[e.ke].aws_s3.upload({
|
||||
uploadObject(e.ke,{
|
||||
Bucket: s.group[e.ke].init.aws_s3_bucket,
|
||||
Key: saveLocation,
|
||||
Body: fileStream,
|
||||
ACL:'public-read',
|
||||
ContentType:'image/jpeg'
|
||||
},function(err,data){
|
||||
if(err){
|
||||
s.userLog(e,{type:lang['Wasabi Hot Cloud Storage Upload Error'],msg:err})
|
||||
}).then((response) => {
|
||||
if(response.err){
|
||||
s.userLog(e,{type:lang['Wasabi Hot Cloud Storage Upload Error'],msg:response.err})
|
||||
}
|
||||
if(s.group[e.ke].init.aws_s3_log === '1' && data && data.Location){
|
||||
if(s.group[e.ke].init.aws_s3_log === '1' && response.ok){
|
||||
s.knexQuery({
|
||||
action: "insert",
|
||||
table: "Cloud Timelapse Frames",
|
||||
|
@ -160,12 +182,12 @@ module.exports = function(s,config,lang){
|
|||
ke: queryInfo.ke,
|
||||
time: queryInfo.time,
|
||||
filename: queryInfo.filename,
|
||||
type : 's3',
|
||||
details: s.s({
|
||||
type : 's3',
|
||||
location : saveLocation
|
||||
}),
|
||||
size: queryInfo.size,
|
||||
href: data.Location
|
||||
href: ''
|
||||
}
|
||||
})
|
||||
s.setCloudDiskUsedForGroup(e.ke,{
|
||||
|
@ -184,30 +206,32 @@ module.exports = function(s,config,lang){
|
|||
}catch(err){
|
||||
var frameDetails = frame.details
|
||||
}
|
||||
if(frameDetails.type !== 's3'){
|
||||
if(video.type !== 's3'){
|
||||
callback()
|
||||
return
|
||||
}
|
||||
if(!frameDetails.location){
|
||||
frameDetails.location = frame.href.split(locationUrl)[1]
|
||||
}
|
||||
s.group[e.ke].aws_s3.deleteObject({
|
||||
deleteObject(e.ke,{
|
||||
Bucket: s.group[e.ke].init.aws_s3_bucket,
|
||||
Key: frameDetails.location,
|
||||
}, function(err, data) {
|
||||
if (err) console.log(err);
|
||||
}).then((response) => {
|
||||
if (response.err){
|
||||
console.error('Amazon S3 DELETE Error')
|
||||
console.error(err);
|
||||
}
|
||||
callback()
|
||||
});
|
||||
}
|
||||
function onGetVideoData(video){
|
||||
async function onGetVideoData(video){
|
||||
const videoDetails = s.parseJSON(video.details)
|
||||
return new Promise((resolve, reject) => {
|
||||
const saveLocation = videoDetails.location
|
||||
var fileStream = s.group[video.ke].aws_s3.getObject({
|
||||
Bucket: s.group[video.ke].init.aws_s3_bucket,
|
||||
Key: saveLocation,
|
||||
}).createReadStream();
|
||||
resolve(fileStream)
|
||||
})
|
||||
const saveLocation = videoDetails.location
|
||||
var fileStream = await getObject(video.ke,{
|
||||
Bucket: s.group[video.ke].init.aws_s3_bucket,
|
||||
Key: saveLocation,
|
||||
});
|
||||
return fileStream.Body
|
||||
}
|
||||
//amazon s3
|
||||
s.addCloudUploader({
|
||||
|
@ -219,8 +243,8 @@ module.exports = function(s,config,lang){
|
|||
cloudDiskUseStartupExtensions: cloudDiskUseStartup,
|
||||
beforeAccountSave: beforeAccountSave,
|
||||
onAccountSave: cloudDiskUseStartup,
|
||||
onInsertTimelapseFrame: onInsertTimelapseFrame,
|
||||
onDeleteTimelapseFrameFromCloud: onDeleteTimelapseFrameFromCloud,
|
||||
onInsertTimelapseFrame: (() => {}) || onInsertTimelapseFrame,
|
||||
onDeleteTimelapseFrameFromCloud: (() => {}) || onDeleteTimelapseFrameFromCloud,
|
||||
onGetVideoData
|
||||
})
|
||||
//return fields that will appear in settings
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
const fs = require('fs');
|
||||
const { Readable } = require('stream');
|
||||
const B2 = require('backblaze-b2')
|
||||
module.exports = function(s,config,lang){
|
||||
//Backblaze B2
|
||||
var beforeAccountSaveForBackblazeB2 = function(d){
|
||||
|
@ -37,7 +38,6 @@ module.exports = function(s,config,lang){
|
|||
userDetails.bb_b2_bucket !== '' &&
|
||||
userDetails.bb_b2_save === '1'
|
||||
){
|
||||
var B2 = require('backblaze-b2')
|
||||
if(!userDetails.bb_b2_dir || userDetails.bb_b2_dir === '/'){
|
||||
userDetails.bb_b2_dir = ''
|
||||
}
|
||||
|
@ -48,37 +48,21 @@ module.exports = function(s,config,lang){
|
|||
// console.log(err)
|
||||
s.userLog({mid:'$USER',ke:e.ke},{type:lang['Backblaze Error'],msg:err.stack || err.data || err})
|
||||
}
|
||||
var createB2Connection = function(){
|
||||
var b2 = new B2({
|
||||
async function createB2Connection(){
|
||||
const b2 = new B2({
|
||||
accountId: userDetails.bb_b2_accountId,
|
||||
applicationKey: userDetails.bb_b2_applicationKey
|
||||
})
|
||||
b2.authorize().then(function(resp){
|
||||
s.group[e.ke].bb_b2_downloadUrl = resp.downloadUrl
|
||||
b2.listBuckets().then(function(resp){
|
||||
var buckets = resp.buckets
|
||||
var bucketN = -2
|
||||
if(!buckets){
|
||||
s.userLog({mid:'$USER',ke:e.ke},{type: lang['Backblaze Error'],msg: lang['Not Authorized']})
|
||||
return
|
||||
}
|
||||
buckets.forEach(function(item,n){
|
||||
if(item.bucketName === userDetails.bb_b2_bucket){
|
||||
bucketN = n
|
||||
}
|
||||
})
|
||||
if(bucketN > -1){
|
||||
s.group[e.ke].bb_b2_bucketId = buckets[bucketN].bucketId
|
||||
}else{
|
||||
b2.createBucket(
|
||||
userDetails.bb_b2_bucket,
|
||||
'allPublic'
|
||||
).then(function(resp){
|
||||
s.group[e.ke].bb_b2_bucketId = resp.bucketId
|
||||
}).catch(backblazeErr)
|
||||
}
|
||||
}).catch(backblazeErr)
|
||||
}).catch(backblazeErr)
|
||||
});
|
||||
const bucketName = userDetails.bb_b2_bucket
|
||||
try{
|
||||
const authResponse = await b2.authorize();
|
||||
const getBucketResponse = await b2.getBucket({bucketName: bucketName})
|
||||
const bucketId = getBucketResponse.data.buckets[0].bucketId
|
||||
s.group[e.ke].bb_b2_bucketId = bucketId
|
||||
}catch(err){
|
||||
console.error('b2.authorize',err)
|
||||
backblazeErr(err)
|
||||
}
|
||||
s.group[e.ke].bb_b2 = b2
|
||||
}
|
||||
createB2Connection()
|
||||
|
@ -99,13 +83,19 @@ module.exports = function(s,config,lang){
|
|||
}catch(err){
|
||||
var videoDetails = video.details
|
||||
}
|
||||
if(video.type !== 'b2'){
|
||||
callback()
|
||||
return
|
||||
}
|
||||
s.group[e.ke].bb_b2.deleteFileVersion({
|
||||
fileId: videoDetails.fileId,
|
||||
fileName: videoDetails.fileName
|
||||
}).then(function(resp){
|
||||
// console.log('deleteFileVersion',resp)
|
||||
callback()
|
||||
}).catch(function(err){
|
||||
console.log('deleteFileVersion',err)
|
||||
callback()
|
||||
})
|
||||
}
|
||||
var uploadVideoToBackblazeB2 = function(e,k){
|
||||
|
@ -113,28 +103,31 @@ module.exports = function(s,config,lang){
|
|||
//k = temporary values
|
||||
if(!k)k={};
|
||||
//cloud saver - Backblaze B2
|
||||
if(s.group[e.ke].bb_b2 && s.group[e.ke].init.use_bb_b2 !== '0' && s.group[e.ke].init.bb_b2_save === '1'){
|
||||
var backblazeErr = function(err){
|
||||
// console.log(err)
|
||||
s.userLog({mid:'$USER',ke:e.ke},{type:lang['Backblaze Error'],msg:err.data})
|
||||
const theGroup = s.group[e.ke]
|
||||
if(theGroup.bb_b2 && theGroup.init.use_bb_b2 !== '0' && theGroup.init.bb_b2_save === '1'){
|
||||
function backblazeErr(err){
|
||||
s.userLog({mid:'$USER',ke:e.ke},{type:lang['Backblaze Error'],msg:err})
|
||||
s.debugLog(err)
|
||||
}
|
||||
fs.readFile(k.dir+k.filename,function(err,data){
|
||||
var backblazeSavePath = s.group[e.ke].init.bb_b2_dir+e.ke+'/'+e.mid+'/'+k.filename
|
||||
var backblazeSavePath = theGroup.init.bb_b2_dir+e.ke+'/'+e.mid+'/'+k.filename
|
||||
var getUploadUrl = function(bucketId,callback){
|
||||
s.group[e.ke].bb_b2.getUploadUrl(bucketId).then(function(resp){
|
||||
theGroup.bb_b2.getUploadUrl(bucketId).then(function(resp){
|
||||
callback(resp)
|
||||
}).catch(backblazeErr)
|
||||
}
|
||||
getUploadUrl(s.group[e.ke].bb_b2_bucketId,function(req){
|
||||
s.group[e.ke].bb_b2.uploadFile({
|
||||
uploadUrl: req.uploadUrl,
|
||||
uploadAuthToken: req.authorizationToken,
|
||||
getUploadUrl(theGroup.bb_b2_bucketId,function(req){
|
||||
const uploadUrl = req.data.uploadUrl
|
||||
const authorizationToken = req.data.authorizationToken
|
||||
theGroup.bb_b2.uploadFile({
|
||||
uploadUrl: uploadUrl,
|
||||
uploadAuthToken: authorizationToken,
|
||||
filename: backblazeSavePath,
|
||||
data: data,
|
||||
onUploadProgress: null
|
||||
}).then(function(resp){
|
||||
if(s.group[e.ke].init.bb_b2_log === '1' && resp.fileId){
|
||||
var backblazeDownloadUrl = s.group[e.ke].bb_b2_downloadUrl + '/file/' + s.group[e.ke].init.bb_b2_bucket + '/' + backblazeSavePath
|
||||
const uploadResponse = resp.data
|
||||
if(theGroup.init.bb_b2_log === '1' && uploadResponse.fileId){
|
||||
s.knexQuery({
|
||||
action: "insert",
|
||||
table: "Cloud Videos",
|
||||
|
@ -143,11 +136,11 @@ module.exports = function(s,config,lang){
|
|||
ke: e.ke,
|
||||
time: k.startTime,
|
||||
status: 1,
|
||||
type : 'b2',
|
||||
details: s.s({
|
||||
type : 'b2',
|
||||
bucketId : resp.bucketId,
|
||||
fileId : resp.fileId,
|
||||
fileName : resp.fileName
|
||||
bucketId : uploadResponse.bucketId,
|
||||
fileId : uploadResponse.fileId,
|
||||
fileName : uploadResponse.fileName
|
||||
}),
|
||||
size: k.filesize,
|
||||
end: k.endTime,
|
||||
|
@ -183,6 +176,7 @@ module.exports = function(s,config,lang){
|
|||
const fileStream = Readable.from(response.data);
|
||||
resolve(fileStream)
|
||||
}).catch((err) => {
|
||||
s.debugLog(err)
|
||||
reject(err)
|
||||
});
|
||||
})
|
||||
|
@ -225,7 +219,7 @@ module.exports = function(s,config,lang){
|
|||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"field": lang.Bucket,
|
||||
"field": lang['Bucket ID'],
|
||||
"name": "detail=bb_b2_bucket",
|
||||
"placeholder": "Example : slippery-seal",
|
||||
"form-group-class": "autosave_bb_b2_input autosave_bb_b2_1",
|
||||
|
|
|
@ -115,10 +115,12 @@ module.exports = (s,config,lang,app,io) => {
|
|||
s.group[user.ke].googleDrive = null
|
||||
s.group[user.ke].googleDriveOAuth2Client = null
|
||||
}
|
||||
var deleteVideoFromGoogleDrive = function(groupKey,video,callback){
|
||||
var deleteVideoFromGoogleDrive = function(e,video,callback){
|
||||
// e = user
|
||||
const groupKey = e.ke
|
||||
var videoDetails = s.parseJSON(video.details)
|
||||
if(videoDetails.type !== 'googd'){
|
||||
if(video.type !== 'googd'){
|
||||
callback()
|
||||
return
|
||||
}
|
||||
s.group[groupKey].googleDrive.files.delete({
|
||||
|
@ -168,8 +170,8 @@ module.exports = (s,config,lang,app,io) => {
|
|||
ke: e.ke,
|
||||
time: k.startTime,
|
||||
status: 1,
|
||||
type: 'googd',
|
||||
details: s.s({
|
||||
type: 'googd',
|
||||
id: data.id
|
||||
}),
|
||||
size: k.filesize,
|
||||
|
@ -221,8 +223,8 @@ module.exports = (s,config,lang,app,io) => {
|
|||
mid: queryInfo.mid,
|
||||
ke: queryInfo.ke,
|
||||
time: queryInfo.time,
|
||||
type : 'googd',
|
||||
details: s.s({
|
||||
type : 'googd',
|
||||
id : data.id,
|
||||
}),
|
||||
size: queryInfo.size,
|
||||
|
@ -241,7 +243,7 @@ module.exports = (s,config,lang,app,io) => {
|
|||
var onDeleteTimelapseFrameFromCloud = function(e,frame,callback){
|
||||
// e = user
|
||||
var frameDetails = s.parseJSON(frame.details)
|
||||
if(frameDetails.type !== 'googd'){
|
||||
if(frame.type !== 'googd'){
|
||||
return
|
||||
}
|
||||
s.group[e.ke].googleDrive.files.delete({
|
||||
|
@ -255,9 +257,6 @@ module.exports = (s,config,lang,app,io) => {
|
|||
// e = user
|
||||
var videoDetails = s.parseJSON(video.details)
|
||||
const fileId = videoDetails.id
|
||||
if(videoDetails.type !== 'googd'){
|
||||
return
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
s.group[video.ke].googleDrive.files
|
||||
.get({fileId, alt: 'media'}, {responseType: 'stream'})
|
||||
|
@ -296,8 +295,8 @@ module.exports = (s,config,lang,app,io) => {
|
|||
cloudDiskUseStartupExtensions: cloudDiskUseStartupForGoogleDrive,
|
||||
beforeAccountSave: beforeAccountSaveForGoogleDrive,
|
||||
onAccountSave: cloudDiskUseStartupForGoogleDrive,
|
||||
onInsertTimelapseFrame: onInsertTimelapseFrame,
|
||||
onDeleteTimelapseFrameFromCloud: onDeleteTimelapseFrameFromCloud,
|
||||
onInsertTimelapseFrame: (() => {}) || onInsertTimelapseFrame,
|
||||
onDeleteTimelapseFrameFromCloud: (() => {}) || onDeleteTimelapseFrameFromCloud,
|
||||
onGetVideoData: onGetVideoData
|
||||
})
|
||||
return {
|
||||
|
|
|
@ -1,15 +1,37 @@
|
|||
var fs = require('fs');
|
||||
// https://us-east-1.console.aws.amazon.com/iamv2/home#/users
|
||||
|
||||
const fs = require('fs');
|
||||
const { S3Client, PutObjectCommand, DeleteObjectCommand, GetObjectCommand } = require("@aws-sdk/client-s3");
|
||||
|
||||
module.exports = function(s,config,lang){
|
||||
//Wasabi Hot Cloud Storage
|
||||
var beforeAccountSaveForWasabiHotCloudStorage = function(d){
|
||||
const genericRequest = async (groupKey,requestOptions) => {
|
||||
const response = {ok: true}
|
||||
try {
|
||||
await s.group[groupKey].whcs.send(requestOptions);
|
||||
} catch (err) {
|
||||
console.error('AMZ genericRequest',groupKey,requestOptions)
|
||||
response.ok = false
|
||||
response.err = err
|
||||
}
|
||||
return response;
|
||||
};
|
||||
const deleteObject = async (groupKey,options) => {
|
||||
return await genericRequest(groupKey,new DeleteObjectCommand(options))
|
||||
};
|
||||
const uploadObject = async (groupKey,options) => {
|
||||
return await genericRequest(groupKey,new PutObjectCommand(options))
|
||||
};
|
||||
const getObject = async (groupKey,options) => {
|
||||
// returns createReadStream
|
||||
return await s.group[groupKey].whcs.send(new GetObjectCommand(options))
|
||||
};
|
||||
function beforeAccountSave(d){
|
||||
//d = save event
|
||||
d.formDetails.whcs_use_global=d.d.whcs_use_global
|
||||
d.formDetails.use_whcs=d.d.use_whcs
|
||||
}
|
||||
var cloudDiskUseStartupForWasabiHotCloudStorage = function(group,userDetails){
|
||||
group.cloudDiskUse = group.cloudDiskUse || {}
|
||||
group.cloudDiskUse['whcs'] = group.cloudDiskUse['whcs'] || {}
|
||||
group.cloudDiskUse['whcs'].name = 'Wasabi Hot Cloud Storage'
|
||||
function cloudDiskUseStartup(group,userDetails){
|
||||
group.cloudDiskUse['whcs'].name = 'S3-Based Network Storage'
|
||||
group.cloudDiskUse['whcs'].sizeLimitCheck = (userDetails.use_whcs_size_limit === '1')
|
||||
if(!userDetails.whcs_size_limit || userDetails.whcs_size_limit === ''){
|
||||
group.cloudDiskUse['whcs'].sizeLimit = 10000
|
||||
|
@ -17,9 +39,9 @@ module.exports = function(s,config,lang){
|
|||
group.cloudDiskUse['whcs'].sizeLimit = parseFloat(userDetails.whcs_size_limit)
|
||||
}
|
||||
}
|
||||
var loadWasabiHotCloudStorageForUser = function(e){
|
||||
function loadGroupApp(e){
|
||||
// e = user
|
||||
var userDetails = s.parseJSON(e.details)
|
||||
var userDetails = JSON.parse(e.details)
|
||||
if(userDetails.whcs_use_global === '1' && config.cloudUploaders && config.cloudUploaders.WasabiHotCloudStorage){
|
||||
// {
|
||||
// whcs_accessKeyId: "",
|
||||
|
@ -30,8 +52,9 @@ module.exports = function(s,config,lang){
|
|||
// }
|
||||
userDetails = Object.assign(userDetails,config.cloudUploaders.WasabiHotCloudStorage)
|
||||
}
|
||||
//Wasabi Hot Cloud Storage
|
||||
if(!s.group[e.ke].whcs &&
|
||||
//S3-Based Network Storage
|
||||
if(
|
||||
!s.group[e.ke].whcs &&
|
||||
userDetails.whcs !== '0' &&
|
||||
userDetails.whcs_accessKeyId !== ''&&
|
||||
userDetails.whcs_secretAccessKey &&
|
||||
|
@ -41,119 +64,98 @@ module.exports = function(s,config,lang){
|
|||
if(!userDetails.whcs_dir || userDetails.whcs_dir === '/'){
|
||||
userDetails.whcs_dir = ''
|
||||
}
|
||||
if(userDetails.whcs_dir !== ''){
|
||||
if(userDetails.whcs_dir){
|
||||
userDetails.whcs_dir = s.checkCorrectPathEnding(userDetails.whcs_dir)
|
||||
}
|
||||
if(userDetails.use_whcs_endpoint_select && userDetails.use_whcs_endpoint_select !== ''){
|
||||
userDetails.whcs_endpoint = userDetails.use_whcs_endpoint_select
|
||||
}
|
||||
if(!userDetails.whcs_endpoint || userDetails.whcs_endpoint === ''){
|
||||
if(!userDetails.whcs_endpoint ){
|
||||
userDetails.whcs_endpoint = 's3.wasabisys.com'
|
||||
}
|
||||
var whcs_region = null
|
||||
if(userDetails.whcs_region && userDetails.whcs_region !== ''){
|
||||
whcs_region = userDetails.whcs_region
|
||||
}
|
||||
var endpointSplit = userDetails.whcs_endpoint.split('.')
|
||||
if(endpointSplit.length > 2){
|
||||
endpointSplit.shift()
|
||||
}
|
||||
var locationUrl = endpointSplit.join('.')
|
||||
var AWS = new require("aws-sdk")
|
||||
s.group[e.ke].whcs = AWS
|
||||
var wasabiEndpoint = new AWS.Endpoint(userDetails.whcs_endpoint)
|
||||
s.group[e.ke].whcs.config = new s.group[e.ke].whcs.Config({
|
||||
endpoint: wasabiEndpoint,
|
||||
accessKeyId: userDetails.whcs_accessKeyId,
|
||||
secretAccessKey: userDetails.whcs_secretAccessKey,
|
||||
region: whcs_region
|
||||
})
|
||||
s.group[e.ke].whcs = new s.group[e.ke].whcs.S3();
|
||||
s.group[e.ke].whcs = new S3Client({
|
||||
endpoint: userDetails.whcs_endpoint,
|
||||
credentials: {
|
||||
accessKeyId: userDetails.whcs_accessKeyId,
|
||||
secretAccessKey: userDetails.whcs_secretAccessKey,
|
||||
},
|
||||
region: userDetails.whcs_region || null
|
||||
});
|
||||
}
|
||||
}
|
||||
var unloadWasabiHotCloudStorageForUser = function(user){
|
||||
function unloadGroupApp(user){
|
||||
s.group[user.ke].whcs = null
|
||||
}
|
||||
var deleteVideoFromWasabiHotCloudStorage = function(e,video,callback){
|
||||
function deleteVideo(e,video,callback){
|
||||
// e = user
|
||||
try{
|
||||
var videoDetails = JSON.parse(video.details)
|
||||
}catch(err){
|
||||
var videoDetails = video.details
|
||||
}
|
||||
if(!videoDetails.location){
|
||||
videoDetails.location = video.href.split(locationUrl)[1]
|
||||
}
|
||||
if(videoDetails.type !== 'whcs'){
|
||||
if(video.type !== 'whcs'){
|
||||
callback()
|
||||
return
|
||||
}
|
||||
s.group[e.ke].whcs.deleteObject({
|
||||
Bucket: s.group[e.ke].init.whcs_bucket,
|
||||
deleteObject(video.ke,{
|
||||
Bucket: s.group[video.ke].init.whcs_bucket,
|
||||
Key: videoDetails.location,
|
||||
}, function(err, data) {
|
||||
if (err) console.log(err);
|
||||
}).then((response) => {
|
||||
if (response.err){
|
||||
console.error('S3-Based Network Storage DELETE Error')
|
||||
console.error(err);
|
||||
}
|
||||
callback()
|
||||
});
|
||||
}
|
||||
var uploadVideoToWasabiHotCloudStorage = function(e,k){
|
||||
function uploadVideo(e,k,insertQuery){
|
||||
//e = video object
|
||||
//k = temporary values
|
||||
if(!k)k={};
|
||||
//cloud saver - Wasabi Hot Cloud Storage
|
||||
if(s.group[e.ke].whcs && s.group[e.ke].init.use_whcs !== '0' && s.group[e.ke].init.whcs_save === '1'){
|
||||
var ext = k.filename.split('.')
|
||||
ext = ext[ext.length - 1]
|
||||
var fileStream = fs.createReadStream(k.dir+k.filename);
|
||||
//cloud saver - S3-Based Network Storage
|
||||
const groupKey = insertQuery.ke
|
||||
if(s.group[groupKey].whcs && s.group[groupKey].init.use_whcs !== '0' && s.group[groupKey].init.whcs_save === '1'){
|
||||
const filename = `${s.formattedTime(insertQuery.time)}.${insertQuery.ext}`
|
||||
var fileStream = fs.createReadStream(k.dir+filename);
|
||||
fileStream.on('error', function (err) {
|
||||
console.error(err)
|
||||
})
|
||||
var bucketName = s.group[e.ke].init.whcs_bucket
|
||||
var saveLocation = s.group[e.ke].init.whcs_dir+e.ke+'/'+e.mid+'/'+k.filename
|
||||
// gcp does not support multipart. Set queueSize to 1 and a big enough partSize
|
||||
var options = s.group[e.ke].whcs.endpoint.href.includes("https://storage.googleapis.com") ? {
|
||||
queueSize: 1,
|
||||
partSize: 300 * 1024 * 1024
|
||||
} : {}
|
||||
s.group[e.ke].whcs.upload({
|
||||
Bucket: bucketName,
|
||||
var saveLocation = s.group[groupKey].init.whcs_dir+groupKey+'/'+e.mid+'/'+filename
|
||||
uploadObject(groupKey,{
|
||||
Bucket: s.group[groupKey].init.whcs_bucket,
|
||||
Key: saveLocation,
|
||||
Body: fileStream,
|
||||
ContentType: 'video/'+ext
|
||||
},options,function(err,data){
|
||||
if(err){
|
||||
console.error(err)
|
||||
s.userLog(e,{type:lang['Wasabi Hot Cloud Storage Upload Error'],msg:err})
|
||||
ContentType: 'video/'+e.ext
|
||||
}).then((response) => {
|
||||
if(response.err){
|
||||
s.userLog(e,{type:lang['S3-Based Network Storage Upload Error'],msg:response.err})
|
||||
}
|
||||
if(s.group[e.ke].init.whcs_log === '1' && data && data.Location){
|
||||
var cloudLink = data.Location
|
||||
cloudLink = fixCloudianUrl(e,cloudLink)
|
||||
if(s.group[groupKey].init.whcs_log === '1' && response.ok){
|
||||
s.knexQuery({
|
||||
action: "insert",
|
||||
table: "Cloud Videos",
|
||||
insert: {
|
||||
mid: e.mid,
|
||||
ke: e.ke,
|
||||
time: k.startTime,
|
||||
ke: groupKey,
|
||||
ext: insertQuery.ext,
|
||||
time: insertQuery.time,
|
||||
status: 1,
|
||||
type : 'whcs',
|
||||
details: s.s({
|
||||
type : 'whcs',
|
||||
location : saveLocation
|
||||
}),
|
||||
size: k.filesize,
|
||||
end: k.endTime,
|
||||
href: cloudLink
|
||||
href: ''
|
||||
}
|
||||
})
|
||||
s.setCloudDiskUsedForGroup(e.ke,{
|
||||
amount : k.filesizeMB,
|
||||
storageType : 'whcs'
|
||||
s.setCloudDiskUsedForGroup(groupKey,{
|
||||
amount: k.filesizeMB,
|
||||
storageType: 'whcs'
|
||||
})
|
||||
s.purgeCloudDiskForGroup(e,'whcs')
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
var onInsertTimelapseFrame = function(monitorObject,queryInfo,filePath){
|
||||
function onInsertTimelapseFrame(monitorObject,queryInfo,filePath){
|
||||
var e = monitorObject
|
||||
if(s.group[e.ke].whcs && s.group[e.ke].init.use_whcs !== '0' && s.group[e.ke].init.whcs_save === '1'){
|
||||
var fileStream = fs.createReadStream(filePath)
|
||||
|
@ -161,17 +163,16 @@ module.exports = function(s,config,lang){
|
|||
console.error(err)
|
||||
})
|
||||
var saveLocation = s.group[e.ke].init.whcs_dir + e.ke + '/' + e.mid + '_timelapse/' + queryInfo.filename
|
||||
s.group[e.ke].whcs.upload({
|
||||
uploadObject(e.ke,{
|
||||
Bucket: s.group[e.ke].init.whcs_bucket,
|
||||
Key: saveLocation,
|
||||
Body: fileStream,
|
||||
ACL:'public-read',
|
||||
ContentType:'image/jpeg'
|
||||
},function(err,data){
|
||||
if(err){
|
||||
s.userLog(e,{type:lang['Wasabi Hot Cloud Storage Upload Error'],msg:err})
|
||||
}).then((response) => {
|
||||
if(response.err){
|
||||
s.userLog(e,{type:lang['Wasabi Hot Cloud Storage Upload Error'],msg:response.err})
|
||||
}
|
||||
if(s.group[e.ke].init.whcs_log === '1' && data && data.Location){
|
||||
if(s.group[e.ke].init.whcs_log === '1' && response.ok){
|
||||
s.knexQuery({
|
||||
action: "insert",
|
||||
table: "Cloud Timelapse Frames",
|
||||
|
@ -179,13 +180,13 @@ module.exports = function(s,config,lang){
|
|||
mid: queryInfo.mid,
|
||||
ke: queryInfo.ke,
|
||||
time: queryInfo.time,
|
||||
filename: queryInfo.filename,
|
||||
filename: queryInfo.filename,
|
||||
type : 'whcs',
|
||||
details: s.s({
|
||||
type : 'whcs',
|
||||
location : saveLocation
|
||||
}),
|
||||
size: queryInfo.size,
|
||||
href: data.Location
|
||||
href: ''
|
||||
}
|
||||
})
|
||||
s.setCloudDiskUsedForGroup(e.ke,{
|
||||
|
@ -197,68 +198,55 @@ module.exports = function(s,config,lang){
|
|||
})
|
||||
}
|
||||
}
|
||||
var onDeleteTimelapseFrameFromCloud = function(e,frame,callback){
|
||||
function onDeleteTimelapseFrameFromCloud(e,frame,callback){
|
||||
// e = user
|
||||
try{
|
||||
var frameDetails = JSON.parse(frame.details)
|
||||
}catch(err){
|
||||
var frameDetails = frame.details
|
||||
}
|
||||
if(frameDetails.type !== 'whcs'){
|
||||
if(video.type !== 'whcs'){
|
||||
callback()
|
||||
return
|
||||
}
|
||||
if(!frameDetails.location){
|
||||
frameDetails.location = frame.href.split(locationUrl)[1]
|
||||
}
|
||||
s.group[e.ke].whcs.deleteObject({
|
||||
deleteObject(e.ke,{
|
||||
Bucket: s.group[e.ke].init.whcs_bucket,
|
||||
Key: frameDetails.location,
|
||||
}, function(err, data) {
|
||||
if (err) console.log(err);
|
||||
}).then((response) => {
|
||||
if (response.err){
|
||||
console.error('S3-Based Network Storage DELETE Error')
|
||||
console.error(err);
|
||||
}
|
||||
callback()
|
||||
});
|
||||
}
|
||||
var fixCloudianUrl = function(e,cloudLink){
|
||||
if(cloudLink.indexOf('http') === -1){
|
||||
var bucketName = s.group[e.ke].init.whcs_bucket
|
||||
var endPointSplit = s.group[e.ke].init.whcs_endpoint.split('://')
|
||||
endPoint = endPointSplit[1] || endPointSplit[0]
|
||||
var protocol = `https`
|
||||
if(endPointSplit[1])protocol = endPointSplit[0]
|
||||
var cloudLinkPrefix = `${protocol}://${bucketName}.${endPoint}`
|
||||
var truncatedLink = cloudLink.substring(0, bucketName.length + 3)
|
||||
if(truncatedLink.indexOf(`${bucketName}/`) > -1){
|
||||
cloudLink = cloudLink.replace(`${bucketName}/`,'')
|
||||
}
|
||||
cloudLink = s.checkCorrectPathEnding(cloudLinkPrefix) + cloudLink
|
||||
}
|
||||
return cloudLink
|
||||
}
|
||||
function onGetVideoData(video){
|
||||
async function onGetVideoData(video){
|
||||
const videoDetails = s.parseJSON(video.details)
|
||||
return new Promise((resolve, reject) => {
|
||||
const saveLocation = videoDetails.location
|
||||
var fileStream = s.group[video.ke].whcs.getObject({
|
||||
Bucket: s.group[video.ke].init.whcs_bucket,
|
||||
Key: saveLocation,
|
||||
}).createReadStream();
|
||||
resolve(fileStream)
|
||||
})
|
||||
const saveLocation = videoDetails.location
|
||||
var fileStream = await getObject(video.ke,{
|
||||
Bucket: s.group[video.ke].init.whcs_bucket,
|
||||
Key: saveLocation,
|
||||
});
|
||||
return fileStream.Body
|
||||
}
|
||||
//wasabi
|
||||
//S3-Based Network Storage
|
||||
s.addCloudUploader({
|
||||
name: 'whcs',
|
||||
loadGroupAppExtender: loadWasabiHotCloudStorageForUser,
|
||||
unloadGroupAppExtender: unloadWasabiHotCloudStorageForUser,
|
||||
insertCompletedVideoExtender: uploadVideoToWasabiHotCloudStorage,
|
||||
deleteVideoFromCloudExtensions: deleteVideoFromWasabiHotCloudStorage,
|
||||
cloudDiskUseStartupExtensions: cloudDiskUseStartupForWasabiHotCloudStorage,
|
||||
beforeAccountSave: beforeAccountSaveForWasabiHotCloudStorage,
|
||||
onAccountSave: cloudDiskUseStartupForWasabiHotCloudStorage,
|
||||
onInsertTimelapseFrame: onInsertTimelapseFrame,
|
||||
onDeleteTimelapseFrameFromCloud: onDeleteTimelapseFrameFromCloud,
|
||||
loadGroupAppExtender: loadGroupApp,
|
||||
unloadGroupAppExtender: unloadGroupApp,
|
||||
insertCompletedVideoExtender: uploadVideo,
|
||||
deleteVideoFromCloudExtensions: deleteVideo,
|
||||
cloudDiskUseStartupExtensions: cloudDiskUseStartup,
|
||||
beforeAccountSave: beforeAccountSave,
|
||||
onAccountSave: cloudDiskUseStartup,
|
||||
onInsertTimelapseFrame: (() => {}) || onInsertTimelapseFrame,
|
||||
onDeleteTimelapseFrameFromCloud: (() => {}) || onDeleteTimelapseFrameFromCloud,
|
||||
onGetVideoData
|
||||
})
|
||||
//return fields that will appear in settings
|
||||
return {
|
||||
"evaluation": "details.use_whcs !== '0'",
|
||||
"name": lang["S3-Based Network Storage"],
|
||||
|
@ -285,35 +273,11 @@ module.exports = function(s,config,lang){
|
|||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"name": "detail=use_whcs_endpoint_select",
|
||||
"selector":"h_whcs_endpoint",
|
||||
"field": lang.Endpoint,
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"fieldType": "select",
|
||||
"possible": [
|
||||
{
|
||||
"name": "Custom Endpoint",
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"name": lang['Wasabi Hot Cloud Storage'],
|
||||
"value": "s3.wasabisys.com"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"field": lang['Endpoint Address'],
|
||||
"name": "detail=whcs_endpoint",
|
||||
"placeholder": "s3.wasabisys.com",
|
||||
"form-group-class": "autosave_whcs_input autosave_whcs_1",
|
||||
"form-group-class-pre-layer":"h_whcs_endpoint_input h_whcs_endpoint_",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
"field": lang['Endpoint Address'],
|
||||
"name": "detail=whcs_endpoint",
|
||||
"placeholder": "s3.wasabisys.com",
|
||||
"form-group-class": "autosave_whcs_input autosave_whcs_1",
|
||||
"form-group-class-pre-layer":"h_whcs_endpoint_input h_whcs_endpoint_"
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
|
@ -357,7 +321,7 @@ module.exports = function(s,config,lang){
|
|||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": [
|
||||
"possible": [
|
||||
{
|
||||
"name": lang['No Region'],
|
||||
"value": ""
|
||||
|
@ -434,7 +398,7 @@ module.exports = function(s,config,lang){
|
|||
"name": "South America 1",
|
||||
"value": "sa-east-1"
|
||||
}
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
|
|
|
@ -57,6 +57,10 @@ module.exports = function(s,config,lang){
|
|||
}catch(err){
|
||||
var videoDetails = video.details
|
||||
}
|
||||
if(video.type !== 'webdav'){
|
||||
callback()
|
||||
return
|
||||
}
|
||||
if(!videoDetails.location){
|
||||
var prefix = s.addUserPassToUrl(s.checkCorrectPathEnding(s.group[groupKey].init.webdav_url),s.group[groupKey].init.webdav_user,s.group[groupKey].init.webdav_pass)
|
||||
videoDetails.location = video.href.replace(prefix,'')
|
||||
|
@ -88,8 +92,8 @@ module.exports = function(s,config,lang){
|
|||
ke: e.ke,
|
||||
time: k.startTime,
|
||||
status: 1,
|
||||
type : 'webdav',
|
||||
details: s.s({
|
||||
type : 'webdav',
|
||||
location : webdavUploadDir + k.filename
|
||||
}),
|
||||
size: k.filesize,
|
||||
|
@ -172,8 +176,8 @@ module.exports = function(s,config,lang){
|
|||
ke: queryInfo.ke,
|
||||
time: queryInfo.time,
|
||||
filename: queryInfo.filename,
|
||||
type : 'webdav',
|
||||
details: s.s({
|
||||
type : 'webdav',
|
||||
location : saveLocation
|
||||
}),
|
||||
size: queryInfo.size,
|
||||
|
@ -195,7 +199,8 @@ module.exports = function(s,config,lang){
|
|||
}catch(err){
|
||||
var frameDetails = frame.details
|
||||
}
|
||||
if(frameDetails.type !== 'webdav'){
|
||||
if(frame.type !== 'webdav'){
|
||||
callback()
|
||||
return
|
||||
}
|
||||
if(!frameDetails.location){
|
||||
|
@ -223,8 +228,8 @@ module.exports = function(s,config,lang){
|
|||
cloudDiskUseStartupExtensions: cloudDiskUseStartupForWebDav,
|
||||
beforeAccountSave: beforeAccountSaveForWebDav,
|
||||
onAccountSave: cloudDiskUseStartupForWebDav,
|
||||
onInsertTimelapseFrame,
|
||||
onDeleteTimelapseFrameFromCloud,
|
||||
onInsertTimelapseFrame: () => {},
|
||||
onDeleteTimelapseFrameFromCloud: () => {},
|
||||
onGetVideoData
|
||||
})
|
||||
return {
|
||||
|
|
|
@ -331,22 +331,18 @@ module.exports = function(s,config,lang){
|
|||
}
|
||||
if(s.deleteVideoFromCloudExtensions[storageType]){
|
||||
s.deleteVideoFromCloudExtensions[storageType](e,video,function(){
|
||||
s.tx({
|
||||
s.tx(Object.assign({
|
||||
f: 'video_delete_cloud',
|
||||
mid: e.mid,
|
||||
ke: e.ke,
|
||||
time: e.time,
|
||||
end: e.end
|
||||
},'GRP_'+e.ke);
|
||||
},video),'GRP_'+e.ke);
|
||||
})
|
||||
}
|
||||
}
|
||||
s.deleteVideoFromCloud = function(e){
|
||||
s.deleteVideoFromCloud = function(e,cloudType){
|
||||
// e = video object
|
||||
s.checkDetails(e)
|
||||
const whereQuery = {
|
||||
ke: e.ke,
|
||||
mid: e.mid,
|
||||
type: cloudType,
|
||||
time: new Date(e.time),
|
||||
}
|
||||
s.knexQuery({
|
||||
|
@ -363,7 +359,7 @@ module.exports = function(s,config,lang){
|
|||
table: "Cloud Videos",
|
||||
where: whereQuery
|
||||
},(err) => {
|
||||
s.deleteVideoFromCloudExtensionsRunner(e,details.type || 's3',r)
|
||||
s.deleteVideoFromCloudExtensionsRunner(e,details.type || r.type || 's3',r)
|
||||
})
|
||||
}else{
|
||||
// console.log('Delete Failed',e)
|
||||
|
|
|
@ -1379,6 +1379,7 @@ module.exports = function(s,config,lang,app,io){
|
|||
where: [
|
||||
['ke','=',groupKey],
|
||||
['mid','=',req.params.id],
|
||||
['type','=', s.getPostData(req,'type') || 's3'],
|
||||
['time','=',time]
|
||||
],
|
||||
limit: 1
|
||||
|
@ -1386,7 +1387,7 @@ module.exports = function(s,config,lang,app,io){
|
|||
if(r&&r[0]){
|
||||
r = r[0]
|
||||
const videoDetails = JSON.parse(r.details)
|
||||
const storageType = videoDetails.type
|
||||
const storageType = r.type || videoDetails.type
|
||||
const onGetVideoData = s.cloudDiskUseOnGetVideoDataExtensions[storageType]
|
||||
if(onGetVideoData){
|
||||
onGetVideoData(r).then((dataPipe) => {
|
||||
|
@ -1803,15 +1804,17 @@ module.exports = function(s,config,lang,app,io){
|
|||
videoSet = 'Cloud Videos'
|
||||
break;
|
||||
}
|
||||
const whereQuery = [
|
||||
['ke','=',groupKey],
|
||||
['mid','=',req.params.id],
|
||||
['time','=',time]
|
||||
]
|
||||
if(videoParam === 'cloudVideos')whereQuery.push(['type','=',s.getPostData(req,'type') || 's3']);
|
||||
s.knexQuery({
|
||||
action: "select",
|
||||
columns: "*",
|
||||
table: videoSet,
|
||||
where: [
|
||||
['ke','=',groupKey],
|
||||
['mid','=',req.params.id],
|
||||
['time','=',time]
|
||||
],
|
||||
where: whereQuery,
|
||||
limit: 1
|
||||
},async (err,r) => {
|
||||
if(r && r[0]){
|
||||
|
@ -1884,7 +1887,7 @@ module.exports = function(s,config,lang,app,io){
|
|||
response.ok = true;
|
||||
switch(videoParam){
|
||||
case'cloudVideos':
|
||||
s.deleteVideoFromCloud(r,details.type || 's3')
|
||||
s.deleteVideoFromCloud(r,details.type || r.type || 's3')
|
||||
break;
|
||||
default:
|
||||
s.deleteVideo(r)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -14,8 +14,8 @@
|
|||
},
|
||||
"homepage": "https://gitlab.com/Shinobi-Systems/Shinobi#readme",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.226.0",
|
||||
"async": "^3.2.2",
|
||||
"aws-sdk": "^2.1030.0",
|
||||
"backblaze-b2": "^0.9.12",
|
||||
"body-parser": "^1.19.0",
|
||||
"bson": "^4.6.1",
|
||||
|
|
|
@ -26,7 +26,7 @@ $(document).ready(function(e){
|
|||
$.getJSON(apiURL + '?' + queryString.join('&'),function(data){
|
||||
$.each(data.videos,function(n,v){
|
||||
if(v.status !== 0){
|
||||
loadedVideosInMemory[`${v.mid}${v.time}`] = Object.assign({},v)
|
||||
loadedVideosInMemory[`${v.mid}${v.time}${v.type}`] = Object.assign({},v)
|
||||
var loadedMonitor = loadedMonitors[v.mid]
|
||||
if(loadedMonitor){
|
||||
v.title = loadedMonitor.name+' - '+(parseInt(v.size)/1048576).toFixed(2)+'mb';
|
||||
|
@ -53,7 +53,7 @@ $(document).ready(function(e){
|
|||
eventLimit: true,
|
||||
events: calendarData,
|
||||
eventClick: function(v){
|
||||
var video = loadedVideosInMemory[`${v.mid}${v.time}`]
|
||||
var video = loadedVideosInMemory[`${v.mid}${v.time}${v.type}`]
|
||||
var href = video.href
|
||||
createVideoPlayerTab(Object.assign({},video,{href: href}))
|
||||
$(this).css('border-color', 'red');
|
||||
|
|
|
@ -1067,7 +1067,7 @@ $(document).ready(function(e){
|
|||
d.mid = d.id || d.mid
|
||||
var monitorId = d.mid
|
||||
var videoTime = d.time
|
||||
loadedVideosInMemory[`${monitorId}${videoTime}`] = d
|
||||
loadedVideosInMemory[`${monitorId}${videoTime}${d.type}`] = d
|
||||
if(liveGridElements[monitorId] && liveGridElements[monitorId].streamElement)drawVideoCardToMiniList(monitorId,createVideoLinks(d),false)
|
||||
break;
|
||||
case'monitor_watch_off':case'monitor_stopping':
|
||||
|
|
|
@ -250,7 +250,7 @@ $(document).ready(function(){
|
|||
var el = $(this).parents('[data-mid]')
|
||||
var monitorId = el.attr('data-mid')
|
||||
var videoTime = el.attr('data-time')
|
||||
var video = loadedVideosInMemory[`${monitorId}${videoTime}`]
|
||||
var video = loadedVideosInMemory[`${monitorId}${videoTime}${undefined}`]
|
||||
openTab('studio')
|
||||
loadVideoIntoSlicer(video)
|
||||
return false;
|
||||
|
|
|
@ -34,7 +34,7 @@ $(document).ready(function(){
|
|||
})
|
||||
eventMatrixHtml += `</div>`
|
||||
}
|
||||
var baseHtml = `<main class="container page-tab tab-videoPlayer" id="tab-${newTabId}" video-id="${video.mid}${video.time}" data-time="${video.time}" data-mid="${video.mid}" data-ke="${video.ke}">
|
||||
var baseHtml = `<main class="container page-tab tab-videoPlayer" id="tab-${newTabId}" video-id="${video.mid}${video.time}${video.type}" data-time="${video.time}" data-mid="${video.mid}" data-ke="${video.ke}" data-type="${video.type}">
|
||||
<div class="my-3 ${definitions.Theme.isDark ? 'bg-dark text-white' : 'bg-light text-dark'} rounded shadow-sm">
|
||||
<div class="p-3">
|
||||
<h6 class="video-title border-bottom-dotted border-bottom-dark pb-2 mb-0">${tabLabel}</h6>
|
||||
|
|
|
@ -278,7 +278,7 @@ function createVideoRow(row,classOverride){
|
|||
}
|
||||
var videoEndpoint = getApiPrefix(`videos`) + '/' + row.mid + '/' + row.filename
|
||||
return `
|
||||
<div class="video-row ${classOverride ? classOverride : `col-md-12 col-lg-6 mb-3`} search-row" data-mid="${row.mid}" data-time="${row.time}" data-time-formed="${new Date(row.time)}">
|
||||
<div class="video-row ${classOverride ? classOverride : `col-md-12 col-lg-6 mb-3`} search-row" data-mid="${row.mid}" data-time="${row.time}" data-type="${row.type}" data-time-formed="${new Date(row.time)}">
|
||||
<div class="video-time-card shadow-lg px-0 btn-default">
|
||||
<div class="card-header">
|
||||
<div class="${definitions.Theme.isDark ? 'text-white' : ''}">
|
||||
|
@ -441,7 +441,7 @@ function drawVideoRowsToList(targetElement,rows){
|
|||
function loadVideosData(newVideos){
|
||||
$.each(newVideos,function(n,video){
|
||||
delete(video.f)
|
||||
loadedVideosInMemory[`${video.mid}${video.time}`] = video
|
||||
loadedVideosInMemory[`${video.mid}${video.time}${video.type}`] = video
|
||||
})
|
||||
}
|
||||
function loadEventsData(videoEvents){
|
||||
|
@ -486,7 +486,10 @@ function getVideos(options,callback){
|
|||
$.getJSON(`${getApiPrefix(`events`)}${monitorId ? `/${monitorId}` : ''}?${requestQueries.concat([`limit=${limit}`]).join('&')}`,function(eventData){
|
||||
var theEvents = eventData.events || eventData;
|
||||
var newVideos = applyDataListToVideos(videos,theEvents)
|
||||
newVideos = applyTimelapseFramesListToVideos(newVideos,timelapseFrames.frames || timelapseFrames,'timelapseFrames',true)
|
||||
newVideos = applyTimelapseFramesListToVideos(newVideos,timelapseFrames.frames || timelapseFrames,'timelapseFrames',true).map((video) => {
|
||||
video.videoSet = customVideoSet
|
||||
return video
|
||||
})
|
||||
loadEventsData(theEvents)
|
||||
loadVideosData(newVideos)
|
||||
if(callback)callback({videos: newVideos, frames: timelapseFrames});
|
||||
|
@ -634,16 +637,16 @@ async function unarchiveVideos(videos){
|
|||
}
|
||||
}
|
||||
function buildDefaultVideoMenuItems(file,options){
|
||||
var href = file.href
|
||||
var isLocalVideo = !file.videoSet || file.videoSet === 'videos'
|
||||
var href = file.href + `${!isLocalVideo ? `?type=${file.type}` : ''}`
|
||||
options = options ? options : {play: true}
|
||||
return `
|
||||
<li><a class="dropdown-item" href="${href}" download>${lang.Download}</a></li>
|
||||
${options.play ? `<li><a class="dropdown-item open-video" href="${href}">${lang.Play}</a></li>` : ``}
|
||||
${options.play ? `<li><a class="dropdown-item mark-unread" href="${href}">${lang.Play}</a></li>` : ``}
|
||||
<li><hr class="dropdown-divider"></li>
|
||||
${permissionCheck('video_delete',file.mid) ? `<li><a class="dropdown-item open-video-studio" href="${href}">${lang.Slice}</a></li>` : ``}
|
||||
${isLocalVideo && permissionCheck('video_delete',file.mid) ? `<li><a class="dropdown-item open-video-studio" href="${href}">${lang.Slice}</a></li>` : ``}
|
||||
${permissionCheck('video_delete',file.mid) ? `<li><a class="dropdown-item delete-video" href="${href}">${lang.Delete}</a></li>` : ``}
|
||||
${permissionCheck('video_delete',file.mid) ? `<li><a class="dropdown-item compress-video" href="${href}">${lang.Compress}</a></li>` : ``}
|
||||
${isLocalVideo && permissionCheck('video_delete',file.mid) ? `<li><a class="dropdown-item compress-video" href="${href}">${lang.Compress}</a></li>` : ``}
|
||||
`
|
||||
}
|
||||
function setVideoStatus(video,toStatus){
|
||||
|
@ -659,10 +662,10 @@ function setVideoStatus(video,toStatus){
|
|||
onWebSocketEvent(function(d){
|
||||
switch(d.f){
|
||||
case'video_edit':case'video_archive':
|
||||
var video = loadedVideosInMemory[`${d.mid}${d.time}`]
|
||||
var video = loadedVideosInMemory[`${d.mid}${d.time}${d.type}`]
|
||||
if(video){
|
||||
let filename = `${formattedTimeForFilename(convertTZ(d.time),false,`YYYY-MM-DDTHH-mm-ss`)}.${video.ext || 'mp4'}`
|
||||
loadedVideosInMemory[`${d.mid}${d.time}`].status = d.status
|
||||
loadedVideosInMemory[`${d.mid}${d.time}${d.type}`].status = d.status
|
||||
$(`[data-mid="${d.mid}"][data-filename="${filename}"]`).attr('data-status',d.status);
|
||||
}
|
||||
break;
|
||||
|
@ -685,7 +688,7 @@ $(document).ready(function(){
|
|||
var el = $(this).parents('[data-mid]')
|
||||
var monitorId = el.attr('data-mid')
|
||||
var videoTime = el.attr('data-time')
|
||||
var video = loadedVideosInMemory[`${monitorId}${videoTime}`]
|
||||
var video = loadedVideosInMemory[`${monitorId}${videoTime}${undefined}`]
|
||||
createVideoPlayerTab(video)
|
||||
setVideoStatus(video)
|
||||
return false;
|
||||
|
@ -695,7 +698,7 @@ $(document).ready(function(){
|
|||
var monitorId = el.attr('data-mid')
|
||||
var videoTime = el.attr('video-time-seeked-video-position')
|
||||
var timeInward = (parseInt(el.attr('video-slice-seeked')) / 1000) - 2
|
||||
var video = loadedVideosInMemory[`${monitorId}${videoTime}`]
|
||||
var video = loadedVideosInMemory[`${monitorId}${videoTime}${undefined}`]
|
||||
timeInward = timeInward < 0 ? 0 : timeInward
|
||||
createVideoPlayerTab(video,timeInward)
|
||||
})
|
||||
|
@ -704,23 +707,27 @@ $(document).ready(function(){
|
|||
var el = $(this).parents('[data-mid]')
|
||||
var monitorId = el.attr('data-mid')
|
||||
var videoTime = el.attr('data-time')
|
||||
var video = loadedVideosInMemory[`${monitorId}${videoTime}`]
|
||||
var type = el.attr('data-type')
|
||||
var video = loadedVideosInMemory[`${monitorId}${videoTime}${type}`]
|
||||
var videoSet = video.videoSet
|
||||
var ext = video.filename.split('.')
|
||||
ext = ext[ext.length - 1]
|
||||
var videoEndpoint = getApiPrefix(`videos`) + '/' + video.mid + '/' + video.filename
|
||||
var isCloudVideo = videoSet === 'cloudVideos'
|
||||
var videoEndpoint = getApiPrefix(videoSet || 'videos') + '/' + video.mid + '/' + video.filename
|
||||
var endpointType = isCloudVideo ? `?type=${video.type}` : ''
|
||||
$.confirm.create({
|
||||
title: lang["Delete Video"] + ' : ' + video.filename,
|
||||
body: `${lang.DeleteVideoMsg}<br><br><div class="row"><video class="video_video" autoplay loop controls><source src="${videoEndpoint}" type="video/${ext}"></video></div>`,
|
||||
body: `${lang.DeleteVideoMsg}<br><br><div class="row"><video class="video_video" autoplay loop controls><source src="${videoEndpoint}${endpointType}" type="video/${ext}"></video></div>`,
|
||||
clickOptions: {
|
||||
title: '<i class="fa fa-trash-o"></i> ' + lang.Delete,
|
||||
class: 'btn-danger btn-sm'
|
||||
},
|
||||
clickCallback: function(){
|
||||
$.getJSON(videoEndpoint + '/delete',function(data){
|
||||
$.getJSON(videoEndpoint + '/delete' + endpointType,function(data){
|
||||
if(data.ok){
|
||||
console.log('Video Deleted')
|
||||
}else{
|
||||
console.log('Video Not Deleted',data,videoEndpoint)
|
||||
console.log('Video Not Deleted',data,videoEndpoint + endpointType)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -732,7 +739,7 @@ $(document).ready(function(){
|
|||
var el = $(this).parents('[data-mid]')
|
||||
var monitorId = el.attr('data-mid')
|
||||
var videoTime = el.attr('data-time')
|
||||
var video = loadedVideosInMemory[`${monitorId}${videoTime}`]
|
||||
var video = loadedVideosInMemory[`${monitorId}${videoTime}${undefined}`]
|
||||
var ext = video.filename.split('.')
|
||||
ext = ext[ext.length - 1]
|
||||
var videoEndpoint = getApiPrefix(`videos`) + '/' + video.mid + '/' + video.filename
|
||||
|
@ -755,7 +762,7 @@ $(document).ready(function(){
|
|||
var monitorId = el.attr('data-mid')
|
||||
var videoTime = el.attr('data-time')
|
||||
var unarchive = $(this).hasClass('status-archived')
|
||||
var video = loadedVideosInMemory[`${monitorId}${videoTime}`]
|
||||
var video = loadedVideosInMemory[`${monitorId}${videoTime}${undefined}`]
|
||||
var ext = video.filename.split('.')
|
||||
ext = ext[ext.length - 1]
|
||||
var videoEndpoint = getApiPrefix(`videos`) + '/' + video.mid + '/' + video.filename
|
||||
|
@ -781,7 +788,7 @@ $(document).ready(function(){
|
|||
var el = $(this).parents('[data-mid]')
|
||||
var monitorId = el.attr('data-mid')
|
||||
var videoTime = el.attr('data-time')
|
||||
var video = loadedVideosInMemory[`${monitorId}${videoTime}`]
|
||||
var video = loadedVideosInMemory[`${monitorId}${videoTime}${undefined}`]
|
||||
var ext = video.filename.split('.')
|
||||
ext = ext[ext.length - 1]
|
||||
var videoEndpoint = getApiPrefix(`videos`) + '/' + video.mid + '/' + video.filename
|
||||
|
|
|
@ -61,6 +61,7 @@ $(document).ready(function(e){
|
|||
var endDate = dateRange.endDate
|
||||
var monitorId = monitorsList.val()
|
||||
var wantsArchivedVideo = getVideoSetSelected() === 'archive'
|
||||
var wantCloudVideo = wantCloudVideos()
|
||||
var frameIconsHtml = ''
|
||||
if(!usePreloadedData){
|
||||
loadedVideosTable = (await getVideos({
|
||||
|
@ -69,10 +70,10 @@ $(document).ready(function(e){
|
|||
endDate,
|
||||
searchQuery,
|
||||
archived: wantsArchivedVideo,
|
||||
customVideoSet: wantCloudVideos() ? 'cloudVideos' : null,
|
||||
customVideoSet: wantCloudVideo ? 'cloudVideos' : null,
|
||||
})).videos;
|
||||
$.each(loadedVideosTable,function(n,v){
|
||||
loadedVideosInMemory[`${monitorId}${v.time}`]
|
||||
loadedVideosInMemory[`${monitorId}${v.time}${v.type}`]
|
||||
})
|
||||
}
|
||||
// for (let i = 0; i < loadedVideosTable.length; i++) {
|
||||
|
@ -131,7 +132,8 @@ $(document).ready(function(e){
|
|||
}
|
||||
],
|
||||
data: loadedVideosTable.map((file) => {
|
||||
var href = file.href
|
||||
var isLocalVideo = !wantCloudVideo
|
||||
var href = file.href + `${!isLocalVideo ? `?type=${file.type}` : ''}`
|
||||
var loadedMonitor = loadedMonitors[file.mid]
|
||||
return {
|
||||
image: `<div class="video-thumbnail" data-mid="${file.mid}" data-ke="${file.ke}" data-time="${file.time}" data-end="${file.end}" data-filename="${file.filename}">
|
||||
|
@ -154,12 +156,13 @@ $(document).ready(function(e){
|
|||
objects: file.objects,
|
||||
tags: `
|
||||
${file.ext ? `<span class="badge badge-${file.ext ==='webm' ? `primary` : 'danger'}">${file.ext}</span>` : ''}
|
||||
${!isLocalVideo ? `<span class="badge badge-success">${file.type}</span>` : ''}
|
||||
`,
|
||||
size: convertKbToHumanSize(file.size),
|
||||
buttons: `
|
||||
<div class="row-info btn-group" data-mid="${file.mid}" data-ke="${file.ke}" data-time="${file.time}" data-filename="${file.filename}" data-status="${file.status}">
|
||||
<div class="row-info btn-group" data-mid="${file.mid}" data-ke="${file.ke}" data-time="${file.time}" data-filename="${file.filename}" data-status="${file.status}" data-type="${file.type}">
|
||||
<a class="btn btn-sm btn-default btn-monitor-status-color open-video" href="${href}" title="${lang.Play}"><i class="fa fa-play"></i></a>
|
||||
${permissionCheck('video_delete',file.mid) ? `<a class="btn btn-sm btn-${file.archive === 1 ? `success status-archived` : `default`} archive-video" title="${lang.Archive}"><i class="fa fa-${file.archive === 1 ? `lock` : `unlock-alt`}"></i></a>` : ''}
|
||||
${isLocalVideo && permissionCheck('video_delete',file.mid) ? `<a class="btn btn-sm btn-${file.archive === 1 ? `success status-archived` : `default`} archive-video" title="${lang.Archive}"><i class="fa fa-${file.archive === 1 ? `lock` : `unlock-alt`}"></i></a>` : ''}
|
||||
<div class="dropdown d-inline-block">
|
||||
<a class="btn btn-sm btn-primary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false" data-bs-reference="parent">
|
||||
<i class="fa fa-ellipsis-v" aria-hidden="true"></i>
|
||||
|
@ -185,7 +188,8 @@ $(document).ready(function(e){
|
|||
var groupKey = rowInfo.attr('data-ke')
|
||||
var time = rowInfo.attr('data-time')
|
||||
var filename = rowInfo.attr('data-filename')
|
||||
rowsSelected.push(getLoadedRows ? loadedVideosInMemory[`${monitorId}${time}`] : {
|
||||
var type = rowInfo.attr('data-type')
|
||||
rowsSelected.push(getLoadedRows ? loadedVideosInMemory[`${monitorId}${time}${type}`] : {
|
||||
mid: monitorId,
|
||||
ke: groupKey,
|
||||
time: time,
|
||||
|
@ -257,7 +261,8 @@ $(document).ready(function(e){
|
|||
var rowEl = $(this).parents('[data-mid]')
|
||||
var monitorId = rowEl.attr('data-mid')
|
||||
var videoTime = rowEl.attr('data-time')
|
||||
var video = loadedVideosInMemory[`${monitorId}${videoTime}`]
|
||||
var type = rowEl.attr('data-type')
|
||||
var video = loadedVideosInMemory[`${monitorId}${videoTime}${type}`]
|
||||
var href = el.attr('href')
|
||||
setPreviewedVideoHighlight(el,videosTableDrawArea)
|
||||
drawPreviewVideo(href)
|
||||
|
@ -374,11 +379,12 @@ $(document).ready(function(e){
|
|||
onWebSocketEvent((data) => {
|
||||
switch(data.f){
|
||||
case'video_delete':
|
||||
case'video_delete_cloud':
|
||||
if(tabTree.name === 'videosTableView'){
|
||||
var videoIndexToRemove = loadedVideosTable.findIndex(row => data.mid === row.mid && new Date(row.time).getTime() === new Date(data.time).getTime())
|
||||
var videoIndexToRemove = loadedVideosTable.findIndex(row => (!data.type || data.type === row.type) && data.mid === row.mid && new Date(row.time).getTime() === new Date(data.time).getTime())
|
||||
if(videoIndexToRemove !== -1){
|
||||
loadedVideosTable.splice(videoIndexToRemove, 1);
|
||||
delete(loadedVideosInMemory[`${data.mid}${data.time}`])
|
||||
delete(loadedVideosInMemory[`${data.mid}${data.time}${data.type}`])
|
||||
clearTimeout(redrawTimeout)
|
||||
redrawTimeout = setTimeout(function(){
|
||||
drawVideosTableViewElements(true)
|
||||
|
|
Loading…
Reference in New Issue