1067 lines
37 KiB
Plaintext
Executable File
1067 lines
37 KiB
Plaintext
Executable File
require queue.class
|
|
|
|
proc ::detectads::query_entry_queue_db {ts} {
|
|
set result [{queue check} $ts detectads]
|
|
|
|
return $result
|
|
}
|
|
|
|
proc ::detectads::delete_entry_queue_db {ts} {
|
|
|
|
log "Removing item [$ts get file] from the queue" 1
|
|
return [{queue delete} $ts detectads]
|
|
}
|
|
|
|
proc ::detectads::delete_orphans {} {
|
|
if {![catch {exec /mod/bin/pgrep -x chaseget }]} {return}
|
|
set fl [glob -nocomplain "/mod/tmp/*-inp.ts" "/mod/tmp/*-dec.ts"]
|
|
log "orphan file list $fl" 2
|
|
foreach file $fl {
|
|
if {![system inuse $file]} {
|
|
set bname [file rootname $file]
|
|
file delete -force $bname.hmt
|
|
file delete -force $bname.nts
|
|
file delete -force $bname.thm
|
|
file delete -force $file
|
|
log "Deleted orphan file $file"
|
|
}
|
|
}
|
|
}
|
|
|
|
# Parse command options and apply defaults
|
|
proc ::detectads::checkopts {argv} {
|
|
|
|
set ::optlist ""
|
|
set ::opt "-h"
|
|
set ::debug 0
|
|
set ::time 0
|
|
set parmerror 0
|
|
|
|
set settings [settings]
|
|
|
|
set ::autologlevel [$settings _nval_setting "autolog"]
|
|
if {![info exists ::auto::logfd]} {
|
|
set logfd ::auto::logfd
|
|
}
|
|
|
|
# List of options with default values
|
|
set optarray {
|
|
d 0
|
|
debug 0
|
|
crop 0
|
|
force 0
|
|
bmend 0
|
|
bmsil 0
|
|
delorig 0
|
|
cpulimit 0
|
|
misrdsec 30
|
|
misdetsec 5
|
|
misdetalarm 10
|
|
delsec 180
|
|
retmax 2
|
|
sildb -70
|
|
silminsec 0.2
|
|
brkminct 5
|
|
brkminsec 60
|
|
admaxsec 65
|
|
padsec 0
|
|
dirdecrypt 0
|
|
makethm 0
|
|
thmoffset 0}
|
|
|
|
# Override default from settings DB
|
|
foreach {key defvalue} [array get optarray] {
|
|
set ::opts($key) [$settings _nval_setting "detectads_$key"]
|
|
if {$::opts($key)==0} {set ::opts($key) $defvalue}
|
|
}
|
|
|
|
# Handle text setting for target path
|
|
set ::opts(tgtpath) [$settings _tval_setting "detectads_tgtpath"]
|
|
if {$::opts(tgtpath) == 0} {set ::opts(tgtpath) ""}
|
|
set ::opts(tgtchoice) [$settings _nval_setting "detectads_tgtchoice"]
|
|
|
|
# Handle text setting for oher options
|
|
set otheropts [$settings _tval_setting "detectads_otheropts"]
|
|
if {$otheropts == 0} {set otheropts ""}
|
|
|
|
# Parse argument lists
|
|
foreach argl [list $otheropts $argv] {
|
|
set ::optlist ""
|
|
log "arg list $argl" 2
|
|
for {set ix 0} {$ix < [llength $argl]} {incr ix} {
|
|
set arg [lindex $argl $ix]
|
|
|
|
#check if option in optarray list
|
|
if {[string range $arg 0 0] == "-"} {
|
|
set argx [string tolower [string range $arg 1 end]]
|
|
if {[dict exists $optarray $argx]} {
|
|
incr ix
|
|
set val [lindex $argl $ix]
|
|
set nval $val
|
|
if {$val eq "y"} {set nval 1}
|
|
if {$val eq "n"} {set nval 0}
|
|
if {![string is double -strict $nval]} {
|
|
if {[string length $nval] == 0 ||
|
|
[string range $nval 0 0] == "-"} {
|
|
# Value omitted assume true
|
|
set nval 1
|
|
set val "y"
|
|
incr ix -1
|
|
} else {
|
|
log "Option $arg value ($val) is not y, n or numeric" 0
|
|
incr ix -1
|
|
set parmerror 1
|
|
continue
|
|
}
|
|
}
|
|
lappend ::optlist $arg
|
|
lappend ::optlist $val
|
|
set ::opts($argx) $nval
|
|
continue
|
|
}
|
|
}
|
|
|
|
# check other options
|
|
switch -- $arg {
|
|
|
|
-tgt {
|
|
lappend ::optlist "-tgt"
|
|
incr ix
|
|
set tgtpath [lindex $argl $ix]
|
|
set ::opts(tgtpath) $tgtpath
|
|
lappend ::optlist ::tgtpath
|
|
if {$tgtpath eq "="} {
|
|
set ::opts(tgtchoice) 1
|
|
} else {
|
|
set ::opts(tgtchoice) 3
|
|
if {![file isdirectory $tgtpath]} {
|
|
log "Target '$tgtpath' is not a valid directory" 0
|
|
set parmerror 1
|
|
continue
|
|
}
|
|
}
|
|
}
|
|
|
|
-pq -
|
|
--help -
|
|
-h {
|
|
set ::opt $arg
|
|
}
|
|
|
|
-rs -
|
|
-aq -
|
|
-dq -
|
|
-qq -
|
|
-pr {
|
|
set ::opt $arg
|
|
incr ix
|
|
set file [lindex $argl $ix]
|
|
set ::file $file
|
|
|
|
if {[file isfile $file]} {
|
|
set ::ts [ts fetch $file]
|
|
if {$::ts == 0} {
|
|
log "Cannot process ($file) file is not valid recording" 0
|
|
set parmerror 1
|
|
continue
|
|
}
|
|
} else {
|
|
log "Cannot process ($file) file does not exist" 0
|
|
#puts "Cannot process ($file) file does not exist"
|
|
set parmerror 1
|
|
continue
|
|
}
|
|
}
|
|
|
|
-t {
|
|
incr ix
|
|
set ::time [lindex $argl $ix]
|
|
}
|
|
|
|
default {
|
|
log "Unrecognized option: $arg" 0
|
|
set parmerror 1
|
|
continue
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
if {$::opts(debug) || $::opts(d)} {
|
|
set ::debug 1
|
|
set ::loglevel 2
|
|
set ::auto::loglevel 2
|
|
}
|
|
|
|
if {$parmerror} {
|
|
log "Parameter errors found"
|
|
exit
|
|
}
|
|
|
|
}
|
|
|
|
proc ::detectads::chancheck {ts} {
|
|
# Check recording channel against exclusion list prior to queueing for analysis - mymsman 150404
|
|
set file [$ts get file]
|
|
set channel [$ts get channel_name]
|
|
|
|
log " DETECTADS: Checking $file ($channel) for channel exclusion" 0
|
|
|
|
set dir [file dirname $file]
|
|
if {[file exists "$dir/.autonodetectads"]} {
|
|
log " DETECTADS: No Ad-detection folder flag set $file" 0
|
|
return 0
|
|
}
|
|
|
|
if {[$ts flag "Addetection"]} {
|
|
log " DETECTADS: Ad-detection flag already set $file" 0
|
|
return 0
|
|
}
|
|
|
|
if {[$ts flag "Radio"]} {
|
|
log " DETECTADS: Radio broadcast, skipping $file" 0
|
|
return 0
|
|
}
|
|
|
|
# ignore FlatView directory
|
|
set settings [settings]
|
|
set fvdir [$settings _tval_setting "fv_dir"]
|
|
|
|
if {[file tail $dir] == $fvdir} {
|
|
log " DETECTADS: Flat view directory, skipping $file" 0
|
|
return 0
|
|
}
|
|
|
|
set opts ""
|
|
if {![file exists "$dir/.autodetectads"]} {
|
|
# open and read configuration file
|
|
set cf "/mod/etc/detectads.conf"
|
|
|
|
if {![file exists $cf]} {
|
|
file copy /mod/webif/plugin/detectads/default.conf $cf
|
|
}
|
|
|
|
if {![catch {set fp [open $cf r]}]} {
|
|
set clist [split [read $fp] "\n"]
|
|
} else {
|
|
set clist {}
|
|
}
|
|
|
|
# Match channel against exclusion list
|
|
foreach chan $clist {
|
|
if {![string length $chan]} continue
|
|
log "Checking exclusion entry: $chan" 2
|
|
if {[string match -nocase $chan $channel]} {
|
|
log "Matched exclusion entry $chan - skipping ad detection" 0
|
|
return 0
|
|
}
|
|
}
|
|
} else {
|
|
# Read options from .autodetectads file
|
|
set ado_file "$dir/.autodetectads"
|
|
set hand [open $ado_file]
|
|
set opts [gets $hand]
|
|
close $hand
|
|
}
|
|
|
|
::detectads::checkopts $opts
|
|
|
|
if {[$ts flag "ODEncrypted"]} {
|
|
set cmd [list /mod/webif/plugin/detectads/detectads -pr "$file"]
|
|
append cmd $opts
|
|
exec {*}$cmd >@$::logfd &
|
|
log " DETECTADS: Started $file for chaserun advert detection" 0
|
|
} else {
|
|
set queue_time [$settings _tval_setting "detectads_queue_time"]
|
|
set Qid [::detectads::queue $ts $queue_time]
|
|
log " DETECTADS: Queued $file for advert detection, Qid $Qid" 0
|
|
}
|
|
set ::auto::loglevel ::autologlevel
|
|
}
|
|
|
|
proc ::detectads::queue {ts {time 0} {retrynumb 0}} {
|
|
set file [$ts get file]
|
|
|
|
set start [clock seconds]
|
|
if {[string is integer -strict $time]} {
|
|
set start $time
|
|
} else {
|
|
catch {
|
|
set tstart [clock scan $time -format %H:%M]
|
|
if {$tstart<$start} {incr tstart 86400}
|
|
set start $tstart
|
|
}
|
|
|
|
}
|
|
|
|
if {$start == 0} {set start [clock seconds]}
|
|
|
|
# queue with system Q
|
|
set q [{queue insert} -hold $ts detectads]
|
|
$q set start $start
|
|
$q set args $::optlist
|
|
|
|
if {$retrynumb} {$q set retries $retrynumb}
|
|
set Qid [$q get id]
|
|
$q submit
|
|
log "Queued $file Qid $Qid" 1
|
|
|
|
return $Qid
|
|
}
|
|
|
|
proc ::detectads::run {ts} {
|
|
set file [$ts get file]
|
|
|
|
log " DETECTADS: $file $::optlist" 0
|
|
set retcode {"FAILED" "Unknown = check log"}
|
|
set warning ""
|
|
|
|
|
|
if {![acquire_lock $file]} {
|
|
log "Cannot acquire exclusive lock $file, terminating." 0
|
|
return {"DEFER" "Cannot acquire exclusive lock"}
|
|
}
|
|
|
|
set size [$ts size]
|
|
set numAdBreaks 0
|
|
set bname [file rootname [file tail $file]]
|
|
set bpath [file dirname $file]
|
|
|
|
foreach {key value} [array get ::opts] {
|
|
set $key $value
|
|
}
|
|
|
|
set tailPid 0; # unused (for killing head of pipe on timeout - useful with tail -f recording.ts | ffmpeg ... | silence...)
|
|
|
|
set silenceArgs "\
|
|
$tailPid\
|
|
$sildb\
|
|
$silminsec\
|
|
$brkminct\
|
|
$brkminsec\
|
|
$admaxsec\
|
|
$padsec"
|
|
|
|
set start [clock milliseconds]
|
|
set statustok [system startop -multiple detectads $file]
|
|
|
|
set adDetectOutput [open "|\
|
|
nice -n 19 ffmpeg -nostats -loglevel fatal -i [list $file] -vn -sn -ac 2 -f au pipe:1 2>@$::logfd |\
|
|
/mod/webif/plugin/detectads/silence $silenceArgs 2>@$::logfd" r]
|
|
set pids [pid $adDetectOutput]
|
|
log "adDetect pids $pids" 2
|
|
|
|
# cpulimit if program exists
|
|
if {$cpulimit > 0 & [file exists /mod/bin/cpulimit]} {
|
|
set curppid [lindex $pids 0]
|
|
sleep 3; # mustn't be too quick
|
|
exec /mod/bin/cpulimit -l $cpulimit -p $curppid &
|
|
log "ffmpeg pid $curppid limited to $cpulimit % of cpu"
|
|
}
|
|
|
|
set bookmarks [$ts bookmarks 1]
|
|
log "Initial bookmarks: $bookmarks" 2
|
|
set cropcmd " "
|
|
set totalEndSeconds 0
|
|
|
|
while {[gets $adDetectOutput line] != -1} {
|
|
log $line 2
|
|
|
|
set startMinutes 0
|
|
set startSeconds 0
|
|
|
|
set endMinutes 0
|
|
set endSeconds 0
|
|
|
|
# is it a cut line?
|
|
if {[regexp {^cut@= Cut[^(]*\( *([0-9]+):([0-9]{2})- *([0-9]+):([0-9]{2})} $line \
|
|
wholeMatch \
|
|
startMinutes \
|
|
startSeconds \
|
|
endMinutes \
|
|
endSeconds]} {
|
|
|
|
set totalStartSeconds [expr {$startMinutes * 60 + $startSeconds}]
|
|
set totalEndSeconds [expr {$endMinutes * 60 + $endSeconds}]
|
|
|
|
log " ad break found $startMinutes:$startSeconds-$endMinutes:$endSeconds ($totalStartSeconds - $totalEndSeconds)" 0
|
|
|
|
# ladd will not add them if they already exist
|
|
if {$bmend} {
|
|
ladd bookmarks $totalEndSeconds
|
|
} else {
|
|
# "Invert" first bookmark position to be correct for manually run nicesplice crop (from xyz321)
|
|
if {$cropcmd eq " "} {
|
|
# First bookmark
|
|
if {$totalStartSeconds == 0} {
|
|
ladd bookmarks $totalEndSeconds
|
|
} else {
|
|
ladd bookmarks 0 $totalStartSeconds $totalEndSeconds
|
|
}
|
|
} else {
|
|
ladd bookmarks $totalStartSeconds $totalEndSeconds
|
|
}
|
|
}
|
|
# Update bookmarks and build up crop cmd line as each break is detected.- mymsman 150408
|
|
$ts setbookmarks $bookmarks
|
|
lappend cropcmd -cut $($totalStartSeconds *10) $($totalEndSeconds *10)
|
|
incr numAdBreaks
|
|
|
|
if {$makethm && $numAdBreaks==1} {
|
|
# First ad break and thumbnail creation requested
|
|
# Check if it already exists
|
|
if {![file exists "$bpath/$bname.thm"]} {
|
|
# Doesn't exist create it
|
|
if {$totalStartSeconds == 0} {
|
|
set offset $($totalEndSeconds + $thmoffset)
|
|
} else {
|
|
set offset $thmoffset
|
|
}
|
|
if {$offset < 0} {set offset 0}
|
|
set thmstart [clock milliseconds]
|
|
|
|
system startop thumb $file
|
|
$ts mkthm $offset
|
|
system endop thumb
|
|
set thmend [clock milliseconds]
|
|
if {![file exists "$bpath/$bname.thm"]} {
|
|
log "Thumbnail creation failed" 0
|
|
} else {
|
|
log "Thumbnail created at offset $offset in $(($thmend-$thmstart)/1000) seconds" 0
|
|
}
|
|
}
|
|
}
|
|
}
|
|
# is it the End line?
|
|
if {[regexp {^status@= End[^(] *([0-9]+)- *([0-9]+) \( *([0-9]+):([0-9]{2})- *([0-9]+):([0-9]{2})} $line \
|
|
wholeMatch \
|
|
startFrame \
|
|
endFrame \
|
|
startMinutes \
|
|
startSeconds \
|
|
endMinutes \
|
|
endSeconds]} {
|
|
|
|
set totalEndSeconds [expr {$endMinutes * 60 + $endSeconds}]
|
|
log "End: Frame $endFrame Time: $endMinutes:$endSeconds Seconds: $totalEndSeconds" 1
|
|
break
|
|
}
|
|
|
|
if {$bmsil} {
|
|
# is it a Silence? that we are bookmarking for debuging
|
|
if {[regexp {^debug@ Silence[^(] *([0-9]+)- *([0-9]+) \( *([0-9]+):([0-9]{2})- *([0-9]+):([0-9]{2})} $line \
|
|
wholeMatch \
|
|
startFrame \
|
|
endFrame \
|
|
startMinutes \
|
|
startSeconds \
|
|
endMinutes \
|
|
endSeconds]} {
|
|
|
|
set totalStartSeconds [expr {$startMinutes * 60 + $startSeconds}]
|
|
set totalEndSeconds [expr {$endMinutes * 60 + $endSeconds}]
|
|
ladd bookmarks $totalStartSeconds
|
|
$ts setbookmarks $bookmarks
|
|
log " Silence found $startMinutes:$startSeconds-$endMinutes:$endSeconds ($totalStartSeconds - $totalEndSeconds) Frames: $startFrame - $endFrame" 0
|
|
}
|
|
}
|
|
}
|
|
close $adDetectOutput
|
|
|
|
log "Final bookmarks: $bookmarks" 0
|
|
log "$cropcmd" 2
|
|
$ts setbookmarks $bookmarks
|
|
exec hmt +detectads "$bpath/$bname.hmt"
|
|
|
|
# Check that complete file has been retrieved & detected
|
|
set stime [$ts get start]
|
|
set etime [$ts get end]
|
|
set durn $($etime-$stime)
|
|
set misdetect $(abs($durn-$totalEndSeconds))
|
|
|
|
if {$misdetect > $misdetsec} {
|
|
# Length error in dectection
|
|
set warning "Detection Length error, Bookmarks may be upto [clock format $misdetect -format %T] out"
|
|
if {$misdetect > $misdetalarm} {
|
|
system notify "DetectAds $file $warning"
|
|
}
|
|
log "$file $warning" 0
|
|
}
|
|
|
|
# crop adbreaks out of file - mymsman 150407
|
|
if {$crop & $numAdBreaks>0 & $misdetect <= $misdetsec} {
|
|
set elapsedSeconds [elapsed $start]
|
|
set elapsedTime [clock format $(round($elapsedSeconds)) -format "%H:%M:%S"]
|
|
log "ad detection.processed in ${elapsedSeconds}s $elapsedTime - $numAdBreaks ad breaks bookmarked, crop starting" 0
|
|
|
|
|
|
# copy & paste from crop/execute.jim - mymsman 150407
|
|
set rfile $file
|
|
set dir [file dirname $rfile]
|
|
|
|
set len [$ts duration 1]
|
|
|
|
set cropstart [clock milliseconds]
|
|
|
|
switch -- $tgtchoice {
|
|
3 { # Other - check target directory exists
|
|
if {![file isdirectory $tgtpath]} {
|
|
puts "Target '$tgtpath' is not a valid directory, Check Detectads Settings page"
|
|
log "Target '$tgtpath' is not a valid directory, Check Detectads Settings page" 0
|
|
return [list "FAILED" "Target '$tgtpath' is not a valid directory, $numAdBreaks ad breaks bookmarked, $warning"]
|
|
}
|
|
}
|
|
2 { # store in My Video
|
|
set tgtpath [system mediaroot]
|
|
}
|
|
1 -
|
|
default { # Same path as input
|
|
set tgtpath [file dirname $file]
|
|
}
|
|
}
|
|
log "Target option: $tgtchoice Target path: $tgtpath" 2
|
|
|
|
set base [file rootname $rfile]
|
|
set shname [file tail $base]
|
|
|
|
# Check if thumbnail exists
|
|
if {[file exists "$bpath/$bname.thm"]} {
|
|
# Copy to crop
|
|
file copy "$bpath/$bname.thm" "$tgtpath/$shname-crop.thm"
|
|
}
|
|
|
|
|
|
set cmd [list /mod/webif/plugin/detectads/nsplice \
|
|
-in "$dir/$shname" \
|
|
-out "$tgtpath/$shname-crop" ]
|
|
append cmd " $cropcmd"
|
|
# Cant get awk working - give up for now
|
|
#set awkcmd list[awk {\{ print strftime(\"%d/%m/%Y %H:%M:%S NS([pid])-\"), \$0; fflush(); \}}]
|
|
# >@$::logfd]
|
|
|
|
|
|
log "CMD: $cmd"
|
|
|
|
#log [exec {*}$cmd | {*}$awkcmd >@$::logfd]
|
|
log [exec {*}$cmd]
|
|
|
|
set croptime [expr [expr [clock milliseconds] - $cropstart] / 1000.0]
|
|
log " crop time taken: $croptime [clock format $(round($croptime)) -format %T]" 1
|
|
|
|
if {$delorig && ![system inuse $file]} { # Delete original file no longer wanted
|
|
if {[safe_delete $file detectads]} {
|
|
log "$file deleted" 0
|
|
set cfile "$tgtpath/$shname-crop.ts"
|
|
if {![system inuse $cfile]} { # Rename crop file to original if not in use
|
|
ts renamegroup "$cfile" "$shname"
|
|
}
|
|
} else {
|
|
log "$file safe_delete failed" 0
|
|
}
|
|
} else {
|
|
set title [$ts get title]
|
|
set newtitle [concat $title "-Crop"]
|
|
exec hmt "+settitle=${newtitle}" "$tgtpath/$shname-crop.hmt"
|
|
}
|
|
|
|
set elapsedSeconds [elapsed $start]
|
|
set elapsedTime [clock format $(round($elapsedSeconds)) -format "%H:%M:%S"]
|
|
log "done...processed in ${elapsedSeconds}s $elapsedTime - $numAdBreaks ad breaks cropped out" 0
|
|
set retcode [list "OK" "$numAdBreaks ad breaks cropped out" ]
|
|
} else {
|
|
set elapsedSeconds [elapsed $start]
|
|
set elapsedTime [clock format $(round($elapsedSeconds)) -format "%H:%M:%S"]
|
|
log "done...processed in ${elapsedSeconds}s $elapsedTime - $numAdBreaks ad breaks bookmarked" 0
|
|
set retcode [list "OK" "$numAdBreaks ad breaks bookmarked, $warning"]
|
|
}
|
|
system endop $statustok
|
|
release_lock $file
|
|
set ::auto::loglevel ::autologlevel
|
|
return $retcode
|
|
}
|
|
|
|
proc ::detectads::chaserun {ts {Qid 0} {retrynumb 0}} {
|
|
# run ad detection against currently recording program using dlna helper - mymsman 150505
|
|
# creates decrypted, cropped and shrunk copy of file in video root directory.
|
|
# Original recording has ad bookmarks, set.
|
|
set file [$ts get file]
|
|
|
|
log "==DETECTADS Chase Run: $file $::optlist" 0
|
|
set retcode "OK"
|
|
set retmsg "Unknown = check log"
|
|
set qtime 0
|
|
set warning ""
|
|
set cropcmd " "
|
|
|
|
# Check for and delete any oprhaned files
|
|
::detectads::delete_orphans
|
|
|
|
if {![acquire_lock $file]} {
|
|
log "Cannot acquire exclusive lock $file, terminating." 0
|
|
return {"DEFER" "Cannot acquire exclusive lock"}
|
|
}
|
|
set statustok [system startop -multiple detectads $file]
|
|
set size [$ts size]
|
|
set numAdBreaks 0
|
|
|
|
# set each option from settings/overrides
|
|
foreach {key value} [array get ::opts] {
|
|
set $key $value
|
|
}
|
|
set tailPid 0; # unused (for killing head of pipe on timeout - useful with tail -f recording.ts | ffmpeg ... | silence...)
|
|
|
|
set silenceArgs "\
|
|
$tailPid\
|
|
$sildb\
|
|
$silminsec\
|
|
$brkminct\
|
|
$brkminsec\
|
|
$admaxsec\
|
|
$padsec"
|
|
|
|
set stime [$ts get start]
|
|
set etime [$ts get end]
|
|
set ctime [clock seconds]
|
|
|
|
if {!$dirdecrypt} {
|
|
# Check file sharing enabled
|
|
if {[system param DMS_START_ON]} {
|
|
log "Content Sharing Enabled" 2
|
|
} else {
|
|
puts "Content Sharing Disabled -cannot decrypt files"
|
|
log "Content Sharing Disabled" 0
|
|
system notify "DetectAds: Contents sharing disabled, Enable via Humax Settings menu"
|
|
return {"DEFER" "Content Sharing Disabled"}
|
|
}
|
|
}
|
|
|
|
|
|
switch -- $tgtchoice {
|
|
3 { # Other - check target directory exists
|
|
if {![file isdirectory $tgtpath]} {
|
|
puts "Target '$tgtpath' is not a valid directory, Check Detectads Settings page"
|
|
log "Target '$tgtpath' is not a valid directory, Check Detectads Settings page" 0
|
|
return [list "FAILED" "Target '$tgtpath' is not a valid directory"]
|
|
}
|
|
}
|
|
2 { # store in My Video
|
|
set tgtpath [system mediaroot]
|
|
}
|
|
1 -
|
|
default { # Same path as input
|
|
set tgtpath [file dirname $file]
|
|
}
|
|
}
|
|
log "Target option: $tgtchoice Target path: $tgtpath" 2
|
|
|
|
|
|
# if active recording and not already on queue add a protective queue entry at end+20minutes
|
|
set tempQid 0
|
|
if {$Qid == 0 & $ctime < $etime} {
|
|
set qtime $($etime + 1200)
|
|
set tempQid [::detectads::queue $ts $qtime]
|
|
log "Temp Q entry $tempQid created" 1
|
|
set defertime $qtime
|
|
}
|
|
|
|
|
|
set bname [file rootname [file tail $file]]
|
|
set iname "$bname-inp"
|
|
set tname "$bname-dec"
|
|
set cname "$bname-crop"
|
|
set bpath [file dirname $file]
|
|
#set tpath $tgtpath
|
|
set ipath "/mod/tmp"
|
|
set tpath "/mod/tmp"
|
|
set cpath $tgtpath
|
|
set bfile "$file"
|
|
set ifile "$ipath/$iname.ts"
|
|
set tfile "$tpath/$tname.ts"
|
|
set cfile "$cpath/$cname.ts"
|
|
set status [$ts get status]
|
|
|
|
# Open recording to lock against Auto and Flatten
|
|
set recording [open $file r]
|
|
|
|
if {!$dirdecrypt} {
|
|
if {($stime +$delsec) > $ctime} {
|
|
log "Waiting for recording $delsec seconds" 1
|
|
sleep $($stime +$delsec- $ctime)
|
|
set ctime [clock seconds]
|
|
}
|
|
}
|
|
|
|
set start [clock milliseconds]
|
|
log "starting" 2
|
|
|
|
# Create links to input in tmp for retrieval
|
|
file delete -force "$ipath/$iname.ts"
|
|
catch {file link -hard "$ipath/$iname.ts" "[file normalize [file rootname $file].ts]"}
|
|
file delete -force "$ipath/$iname.nts"
|
|
catch {file link -hard "$ipath/$iname.nts" "[file normalize [file rootname $file].nts]"}
|
|
file delete -force "$ipath/$iname.hmt"
|
|
catch {file link -hard "$ipath/$iname.hmt" "[file normalize [file rootname $file].hmt]"}
|
|
set its [ts fetch $ifile]
|
|
|
|
|
|
# Use link for .nts so updates are visble
|
|
file delete -force "$tpath/$tname.nts"
|
|
catch {file link -hard "$tpath/$tname.nts" "[file normalize [file rootname $file].nts]"}
|
|
|
|
# Copy sidecar files and update program title, encryption flag
|
|
file copy -force "[file rootname $file].hmt" "$tpath/$tname.hmt"
|
|
# Update output hmt to valid, decrypted, ad-detected empty file
|
|
set title [$ts get title]
|
|
set guidance [$ts get guidance]
|
|
exec hmt "-encrypted" "$tpath/$tname.hmt"
|
|
exec hmt "-protect" "$tpath/$tname.hmt"
|
|
exec hmt "+detectads" "$tpath/$tname.hmt"
|
|
exec hmt "+patch8=0x28c:2" "$tpath/$tname.hmt"
|
|
set_HMT_durn "$tpath/$tname" $stime 0
|
|
|
|
set ftime [clock format $stime -format "%Y%m%d%H%M.%S"]
|
|
exec touch $tfile -t $ftime
|
|
set tts [ts fetch $tfile]
|
|
set tfilesize 0 ;# Silence/nsplice cant handle restart midway so force total file retrieval
|
|
|
|
if {$crop} {
|
|
# Set up modified copy of nicesplice to run in pipline if cropping
|
|
# title will be copied to output by nicesplice so we can change again after opening pipe
|
|
set newtitle [concat $title "-Crop"]
|
|
exec hmt "+settitle=${newtitle}" "$tpath/$tname.hmt"
|
|
#exec touch "$cpath/$cname.ts" -t $ftime
|
|
set cropInput [open "|\
|
|
/mod/webif/plugin/detectads/nsplice -in {$tpath/$tname} -out {$cpath/$cname} -stdin |\
|
|
awk {\{ print strftime(\"%d/%m/%Y %H:%M:%S NS([pid])-\"), \$0; fflush(); \}} \
|
|
>@$::logfd" w]
|
|
set cropPids [pid $cropInput]
|
|
log "crop pids $cropPids" 2
|
|
fconfigure $cropInput -buffering line
|
|
sleep 5
|
|
} else {set cropInput [open /dev/null w]}
|
|
|
|
set newtitle [concat $title "-Decrypt"]
|
|
exec hmt "+settitle=${newtitle}" "$tpath/$tname.hmt"
|
|
|
|
if {!$dirdecrypt} {
|
|
# Use chaseget for decryption
|
|
set decrypt "/mod/bin/chaseget {$ifile} $tfilesize"
|
|
} else {
|
|
# Use stripts for decryption
|
|
set decrypt "/mod/bin/stripts -@@ -d -d {$ipath/$iname} - 2>@$::logfd"
|
|
}
|
|
|
|
set adDetectOutput [open "|\
|
|
$decrypt |\
|
|
tee -i {$tfile} |\
|
|
nice -n 19 ffmpeg -nostats -loglevel fatal -i pipe:0 -vn -sn -ac 2 -f au pipe:1 2>@$::logfd |\
|
|
/mod/webif/plugin/detectads/silence $silenceArgs 2>@$::logfd" r]
|
|
set adDetectPids [pid $adDetectOutput]
|
|
set pids [pid $adDetectOutput]
|
|
log "adDetect pids $pids" 2
|
|
|
|
# cpulimit if program exists
|
|
if {$cpulimit > 0 & [file exists /mod/bin/cpulimit]} {
|
|
set curppid [lindex $pids 2]
|
|
sleep 3; # mustn't be too quick
|
|
exec /mod/bin/cpulimit -l $cpulimit -p $curppid &
|
|
log "ffmpeg pid $curppid limited to $cpulimit % of cpu"
|
|
}
|
|
|
|
set bookmarks [$tts bookmarks 1]
|
|
log "Initial bookmarks: $bookmarks" 2
|
|
set totalEndSeconds 0
|
|
|
|
# Loop processing output from Silence
|
|
while {1} {
|
|
if {[catch -break -eval -signal -- {gets $adDetectOutput line} msg opts]} {
|
|
log "caught: $msg $opts" 2
|
|
break
|
|
}
|
|
log $line 2
|
|
if {[eof $adDetectOutput]} {
|
|
log "EOF detected" 2
|
|
break
|
|
}
|
|
|
|
set startMinutes 0
|
|
set startSeconds 0
|
|
|
|
set endMinutes 0
|
|
set endSeconds 0
|
|
|
|
# is it a cut line?
|
|
if {[regexp {^cut@= Cut[^(] *([0-9]+)- *([0-9]+) \( *([0-9]+):([0-9]{2})- *([0-9]+):([0-9]{2})} $line \
|
|
wholeMatch \
|
|
startFrame \
|
|
endFrame \
|
|
startMinutes \
|
|
startSeconds \
|
|
endMinutes \
|
|
endSeconds]} {
|
|
|
|
set totalStartSeconds [expr {$startMinutes * 60 + $startSeconds}]
|
|
set totalEndSeconds [expr {$endMinutes * 60 + $endSeconds}]
|
|
|
|
log " ad break found $startMinutes:$startSeconds-$endMinutes:$endSeconds ($totalStartSeconds - $totalEndSeconds) Frames: $startFrame - $endFrame" 0
|
|
|
|
set_HMT_durn "$tpath/$tname" $stime $totalEndSeconds
|
|
|
|
# ladd will not add them if they already exist
|
|
if {$bmend} {
|
|
ladd bookmarks $totalEndSeconds
|
|
} else {
|
|
# "Invert" first bookmark position to be correct for manually run nicesplice crop (from xyz321)
|
|
if {$cropcmd eq " "} {
|
|
# First bookmark
|
|
if {$totalStartSeconds == 0} {
|
|
ladd bookmarks $totalEndSeconds
|
|
} else {
|
|
ladd bookmarks 0 $totalStartSeconds $totalEndSeconds
|
|
}
|
|
} else {
|
|
ladd bookmarks $totalStartSeconds $totalEndSeconds
|
|
}
|
|
}
|
|
# Update bookmarks and build up crop cmd line as each break is detected.- mymsman 150408
|
|
$ts setbookmarks $bookmarks
|
|
$tts setbookmarks $bookmarks
|
|
set cropline "-cut $($totalStartSeconds *10) $($totalEndSeconds *10)"
|
|
lappend cropcmd -cut $($totalStartSeconds *10) $($totalEndSeconds *10)
|
|
puts $cropInput $cropline
|
|
flush $cropInput
|
|
incr numAdBreaks
|
|
|
|
if {$makethm && $numAdBreaks==1} {
|
|
# First ad break and thumbnail creation requested
|
|
# Check if it already exists
|
|
if {![file exists "$bpath/$bname.thm"]} {
|
|
# Doesn't exist create it
|
|
if {$totalStartSeconds == 0} {
|
|
set offset $($totalEndSeconds + $thmoffset)
|
|
} else {
|
|
set offset $thmoffset
|
|
}
|
|
if {$offset < 0} {set offset 0}
|
|
set thmstart [clock milliseconds]
|
|
|
|
system startop thumb $file
|
|
$tts mkthm $offset
|
|
system endop thumb
|
|
set thmend [clock milliseconds]
|
|
if {![file exists "$tpath/$tname.thm"]} {
|
|
log "Thumbnail creation failed" 0
|
|
} else {
|
|
log "Thumbnail created at offset $offset in $(($thmend-$thmstart)/1000) seconds" 0
|
|
file copy "$tpath/$tname.thm" "$bpath/$bname.thm"
|
|
if {$crop} {
|
|
file copy "$tpath/$tname.thm" "$cpath/$cname.thm"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
# is it a heartbeat line?
|
|
if {[regexp {^status@= HtBeat[^(] *([0-9]+)- *([0-9]+) \( *([0-9]+):([0-9]{2})- *([0-9]+):([0-9]{2})} $line \
|
|
wholeMatch \
|
|
startFrame \
|
|
endFrame \
|
|
startMinutes \
|
|
startSeconds \
|
|
endMinutes \
|
|
endSeconds]} {
|
|
|
|
set totalEndSeconds [expr {$endMinutes * 60 + $endSeconds}]
|
|
set cropline "-chkpt $($totalEndSeconds *10)"
|
|
puts $cropInput $cropline
|
|
flush $cropInput
|
|
set_HMT_durn "$tpath/$tname" $stime $totalEndSeconds
|
|
log "Hearbeat: Frame $endFrame Time: $endMinutes:$endSeconds Seconds: $totalEndSeconds" 1
|
|
}
|
|
# is it the End line?
|
|
if {[regexp {^status@= End[^(] *([0-9]+)- *([0-9]+) \( *([0-9]+):([0-9]{2})- *([0-9]+):([0-9]{2})} $line \
|
|
wholeMatch \
|
|
startFrame \
|
|
endFrame \
|
|
startMinutes \
|
|
startSeconds \
|
|
endMinutes \
|
|
endSeconds]} {
|
|
|
|
set totalEndSeconds [expr {$endMinutes * 60 + $endSeconds}]
|
|
set cropline "-end $($totalEndSeconds *10)"
|
|
puts $cropInput $cropline
|
|
flush $cropInput
|
|
set_HMT_durn "$tpath/$tname" $stime $totalEndSeconds
|
|
log "End: Frame $endFrame Time: $endMinutes:$endSeconds Seconds: $totalEndSeconds" 1
|
|
break
|
|
}
|
|
|
|
if {$bmsil} {
|
|
# is it a Silence? that we are bookmarking for debuging
|
|
if {[regexp {^debug@ Silence[^(] *([0-9]+)- *([0-9]+) \( *([0-9]+):([0-9]{2})- *([0-9]+):([0-9]{2})} $line \
|
|
wholeMatch \
|
|
startFrame \
|
|
endFrame \
|
|
startMinutes \
|
|
startSeconds \
|
|
endMinutes \
|
|
endSeconds]} {
|
|
|
|
set totalStartSeconds [expr {$startMinutes * 60 + $startSeconds}]
|
|
set totalEndSeconds [expr {$endMinutes * 60 + $endSeconds}]
|
|
ladd bookmarks $totalStartSeconds
|
|
$ts setbookmarks $bookmarks
|
|
$tts setbookmarks $bookmarks
|
|
log " Silence found $startMinutes:$startSeconds-$endMinutes:$endSeconds ($totalStartSeconds - $totalEndSeconds) Frames: $startFrame - $endFrame" 0
|
|
}
|
|
}
|
|
}
|
|
log "After process loop" 2
|
|
close $adDetectOutput
|
|
close $cropInput
|
|
|
|
log "Final bookmarks: $bookmarks" 0
|
|
log "$cropcmd" 2
|
|
$ts setbookmarks $bookmarks
|
|
$tts setbookmarks $bookmarks
|
|
|
|
# Delete links to input from /mod/tmp
|
|
$its delete
|
|
|
|
# Check that complete file has been retrieved & detected
|
|
set ts [ts fetch $file]
|
|
set tfilesize [file size $tfile]
|
|
set filesize [file size $file]
|
|
set missing $($filesize -$tfilesize)
|
|
set lengtherr 0
|
|
set dadflag "+detectads"
|
|
set stime [$ts get start]
|
|
set etime [$ts get end]
|
|
set durn $($etime-$stime)
|
|
set misstime $(round(abs($missing)/($filesize/$durn)))
|
|
set misdetect $(abs($durn-$totalEndSeconds))
|
|
|
|
if {$missing != 0} {
|
|
# Length error in decryption
|
|
set lengtherr 1
|
|
set warning "Incomplete data retrieval $missing bytes missing ([clock format $misstime -format %T])"
|
|
system notify "DetectAds $file $warning"
|
|
log "$file $warning" 0
|
|
set newtitle "$title -Len err (decrypt)"
|
|
if {$misstime >= $misrdsec} {
|
|
set qtime [clock seconds]
|
|
if {$etime > $qtime} {set qtime $etime}
|
|
set qtime $($qtime + 900)
|
|
incr retrynumb
|
|
if {$retrynumb < $retmax} {
|
|
set newQid [::detectads::queue $ts $qtime $retrynumb]
|
|
system notify "Queing $file for retry of detectads due to significant file length error"
|
|
log "Queing $file for retry of detectads due to significant file length error" 0
|
|
log "Qid $newQid target start [clock format $qtime -format %T]" 1
|
|
set dadflag "-detectads"
|
|
set tempQid 0
|
|
set retcode "DEFER"
|
|
} else {
|
|
system notify "Retry limit exceded for $file cant process file"
|
|
log "Retry limit exceded for $file cant process file" 0
|
|
set retcode "FAILED"
|
|
}
|
|
} else {
|
|
set dadflag "+detectads"
|
|
}
|
|
} else {
|
|
if {$misdetect > $misdetsec} {
|
|
# Length error in dectection
|
|
set lengtherr 1
|
|
set warning "Detection Length error, Bookmarks may be upto [clock format $misdetect -format %T] out"
|
|
if {$misdetect > $misdetalarm} {
|
|
system notify "DetectAds $file $warning"
|
|
}
|
|
log "$file $warning" 0
|
|
set newtitle "$title -Len err ([clock format $misdetect -format %T])"
|
|
}
|
|
}
|
|
|
|
if {$lengtherr == 0} {
|
|
# All OK (as far as we can tell)
|
|
set newtitle "Done"
|
|
exec hmt $dadflag "$bpath/$bname.hmt"
|
|
close $recording
|
|
|
|
if {$delorig && ![system inuse $file]} { # Delete original file no longer wanted
|
|
if {[safe_delete $file detectads]} {
|
|
log "$file deleted" 0
|
|
|
|
if {$crop} {
|
|
if {![system inuse $cfile]} { # Rename crop file to original if not in use
|
|
exec hmt "+settitle=$title" "$cpath/$cname.hmt"
|
|
ts renamegroup "$cfile" "$bname"
|
|
}
|
|
if {![system inuse $tfile]} { # Delete decrypt file no longer needed
|
|
$tts delete
|
|
log "$tfile deleted" 0
|
|
}
|
|
} else {
|
|
if {![system inuse $tfile]} { # Rename decrypt file to original if not in use
|
|
exec hmt "+settitle=$title" "$tpath/$tname.hmt"
|
|
if {$tpath ne $tgtpath} { # Move to correct directory
|
|
$tts move $tgtpath
|
|
}
|
|
ts renamegroup "$tgtpath/$tname.ts" "$bname"
|
|
}
|
|
}
|
|
} else {
|
|
log "$file safe_delete failed" 0
|
|
}
|
|
} else { # Keeping original, dont rename
|
|
if {$crop} {
|
|
if {![system inuse $tfile]} { # Delete decrypt file no longer needed
|
|
$tts delete
|
|
log "$tfile deleted" 0
|
|
}
|
|
} else {
|
|
if {$tpath ne $tgtpath} { # Move decrypt to correct directory
|
|
$tts move $tgtpath
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
# Somethings amiss with file length, keep original and -crop, delete -dec
|
|
if {![system inuse $tfile]} { # Delete decrypt file no longer needed
|
|
$tts delete
|
|
log "$tfile deleted" 0
|
|
}
|
|
exec hmt $dadflag "$bpath/$bname.hmt"
|
|
if {$crop} {
|
|
exec hmt "+settitle=$newtitle" "$cpath/$cname.hmt"
|
|
}
|
|
close $recording
|
|
}
|
|
|
|
if {$tempQid} {
|
|
# remove temporary entryt from the queue
|
|
log "Removing item $tempQid ($file) from the queue" 1
|
|
{queue delete_by_id} $tempQid
|
|
}
|
|
|
|
set elapsedSeconds [elapsed $start]
|
|
set elapsedTime [clock format $(round($elapsedSeconds)) -format "%H:%M:%S"]
|
|
log "done...processed $file in ${elapsedSeconds}s $elapsedTime - $numAdBreaks ad breaks detected" 0
|
|
set retmsg "$numAdBreaks ad breaks detected, $warning"
|
|
|
|
system endop $statustok
|
|
release_lock $file
|
|
log "=============================================================" 1
|
|
set ::auto::loglevel ::autologlevel
|
|
return [list $retcode $retmsg $qtime]
|
|
}
|
|
|
|
proc set_HMT_durn {hmtfn start durn} {
|
|
# Update recording end & stored recording time in hmt file
|
|
exec hmt "+patch32=0x284:$($durn+$start)" "$hmtfn.hmt"
|
|
exec hmt "+patch32=0x288:$durn" "$hmtfn.hmt"
|
|
|
|
}
|