Shinobi/libs/video/utils.js

218 lines
9.5 KiB
JavaScript

const fs = require('fs')
const { spawn } = require('child_process')
module.exports = (s,config,lang) => {
// orphanedVideoCheck : new function
const checkIfVideoIsOrphaned = (monitor,videosDirectory,filename) => {
const response = {ok: true}
return new Promise((resolve,reject) => {
fs.stat(videosDirectory + filename,(err,stats) => {
if(!err && stats.size > 10){
s.knexQuery({
action: "select",
columns: "*",
table: "Videos",
where: [
['ke','=',monitor.ke],
['mid','=',monitor.mid],
['time','=',s.nameToTime(filename)],
],
limit: 1
},(err,rows) => {
if(!err && (!rows || !rows[0])){
//row does not exist, create one for video
var video = rows[0]
s.insertCompletedVideo(monitor,{
file : filename
},() => {
response.status = 2
resolve(response)
})
}else{
//row exists, no errors
response.status = 1
resolve(response)
}
})
}else{
response.status = 0
resolve(response)
}
})
})
}
const scanForOrphanedVideos = (monitor,options) => {
// const options = {
// checkMax: 2
// }
options = options ? options : {}
return new Promise((resolve,reject) => {
const response = {ok: false}
if(options.forceCheck === true || config.insertOrphans === true){
if(!options.checkMax){
options.checkMax = config.orphanedVideoCheckMax || 2
}
let finished = false
let orphanedFilesCount = 0;
let videosFound = 0;
const videosDirectory = s.getVideoDirectory(monitor)
const tempDirectory = s.getStreamsDirectory(monitor)
// const findCmd = [videosDirectory].concat(options.flags || ['-maxdepth','1'])
fs.writeFileSync(
tempDirectory + 'orphanCheck.sh',
`find "${videosDirectory}" -maxdepth 1 -type f -exec stat -c "%n" {} + | sort -r | head -n ${options.checkMax}`
);
let listing = spawn('sh',[tempDirectory + 'orphanCheck.sh'])
// const onData = options.onData ? options.onData : () => {}
const onError = options.onError ? options.onError : s.systemLog
const onExit = () => {
try{
listing.kill('SIGTERM')
fs.unlink(tempDirectory + 'orphanCheck.sh',() => {})
}catch(err){
s.debugLog(err)
}
delete(listing)
}
const onFinish = () => {
if(!finished){
finished = true
response.ok = true
response.orphanedFilesCount = orphanedFilesCount
resolve(response)
onExit()
}
}
const processLine = async (filePath) => {
let filename = filePath.split('/')
filename = `${filename[filename.length - 1]}`.trim()
if(filename && filename.indexOf('-') > -1 && filename.indexOf('.') > -1){
const { status } = await checkIfVideoIsOrphaned(monitor,videosDirectory,filename)
if(status === 2){
++orphanedFilesCount
}
++videosFound
if(videosFound === options.checkMax){
onFinish()
}
}
}
listing.stdout.on('data', async (d) => {
const filePathLines = d.toString().split('\n')
var i;
for (i = 0; i < filePathLines.length; i++) {
await processLine(filePathLines[i])
}
})
listing.stderr.on('data', d=>onError(d.toString()))
listing.on('close', (code) => {
// s.debugLog(`findOrphanedVideos ${monitor.ke} : ${monitor.mid} process exited with code ${code}`);
setTimeout(() => {
onFinish()
},1000)
});
}else{
resolve(response)
}
})
}
// orphanedVideoCheck : old function
const orphanedVideoCheck = (monitor,checkMax,callback,forceCheck) => {
var finish = function(orphanedFilesCount){
if(callback)callback(orphanedFilesCount)
}
if(forceCheck === true || config.insertOrphans === true){
if(!checkMax){
checkMax = config.orphanedVideoCheckMax || 2
}
var videosDirectory = s.getVideoDirectory(monitor)// + s.formattedTime(video.time) + '.' + video.ext
fs.readdir(videosDirectory,function(err,files){
if(files && files.length > 0){
var fiveRecentFiles = files.slice(files.length - checkMax,files.length)
var completedFile = 0
var orphanedFilesCount = 0
var fileComplete = function(){
++completedFile
if(fiveRecentFiles.length === completedFile){
finish(orphanedFilesCount)
}
}
fiveRecentFiles.forEach(function(filename){
if(/T[0-9][0-9]-[0-9][0-9]-[0-9][0-9]./.test(filename)){
fs.stat(videosDirectory + filename,(err,stats) => {
if(!err && stats.size > 10){
s.knexQuery({
action: "select",
columns: "*",
table: "Videos",
where: [
['ke','=',monitor.ke],
['mid','=',monitor.mid],
['time','=',s.nameToTime(filename)],
],
limit: 1
},(err,rows) => {
if(!err && (!rows || !rows[0])){
++orphanedFilesCount
var video = rows[0]
s.insertCompletedVideo(monitor,{
file : filename
},() => {
fileComplete()
})
}else{
fileComplete()
}
})
}
})
}
})
}else{
finish()
}
})
}else{
finish()
}
}
function cutVideoLength(options){
return new Promise((resolve,reject) => {
const response = {ok: false}
const inputFilePath = options.filePath
const monitorId = options.mid
const groupKey = options.ke
const cutLength = options.cutLength || 10
const tempDirectory = s.getStreamsDirectory(options)
let fileExt = inputFilePath.split('.')
fileExt = fileExt[fileExt.length -1]
const filename = `${s.gid(10)}.${fileExt}`
const videoOutPath = `${tempDirectory}`
const cuttingProcess = spawn(config.ffmpegDir,['-loglevel','warning','-i', inputFilePath, '-c','copy','-t',`${cutLength}`,videoOutPath])
cuttingProcess.stderr.on('data',(data) => {
const err = data.toString()
s.debugLog('cutVideoLength',options,err)
})
cuttingProcess.on('close',(data) => {
fs.stat(videoOutPath,(err) => {
if(!err){
response.filename = filename
response.filePath = videoOutPath
setTimeout(() => {
s.file('delete',videoOutPath)
},1000 * 60 * 3)
}else{
s.debugLog('cutVideoLength:readFile',options,err)
}
resolve(response)
})
})
})
}
return {
orphanedVideoCheck: orphanedVideoCheck,
scanForOrphanedVideos: scanForOrphanedVideos,
cutVideoLength: cutVideoLength,
}
}