2013-07-12 22:43:15 +00:00
|
|
|
|
|
|
|
set ::sweeper::cf "/mod/etc/sweeper.conf"
|
|
|
|
|
|
|
|
proc ::sweeper::unknown {cmd args} {
|
|
|
|
log "Unknown sweeper rule clause '$cmd'" 0
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2013-09-03 20:38:54 +00:00
|
|
|
proc ::sweeper::expand {ts str} {
|
|
|
|
if {[string first "%" $str] == -1} {
|
|
|
|
return $str
|
|
|
|
}
|
|
|
|
|
|
|
|
set glist [ts genrelist]
|
|
|
|
set tsg [$ts get genre]
|
|
|
|
if {![dict exists $glist $tsg]} {
|
|
|
|
set genre "Unknown"
|
|
|
|
} else {
|
|
|
|
set genre [lindex $glist($tsg) 0]
|
|
|
|
}
|
|
|
|
|
|
|
|
set timestamp [clock format [$ts get start] -format "%Y%m%d%H%M%S"]
|
|
|
|
|
|
|
|
set map [list \
|
|
|
|
"%title" [$ts get title] \
|
|
|
|
"%genre" $genre \
|
|
|
|
"%definition" [$ts get definition] \
|
|
|
|
"%lcn" [$ts get channel_num] \
|
|
|
|
"%channel" [$ts get channel_name] \
|
|
|
|
"%duration" [$ts duration] \
|
|
|
|
"%timestamp" $timestamp \
|
|
|
|
]
|
|
|
|
|
|
|
|
set ret [string map $map $str]
|
|
|
|
log " Expanded to \[$ret]" 2
|
|
|
|
return $ret
|
|
|
|
}
|
|
|
|
|
2013-07-12 22:43:15 +00:00
|
|
|
proc ::sweeper::intcomp {ref val} {
|
|
|
|
lassign $val op num
|
|
|
|
|
|
|
|
if {$num eq ""} {
|
|
|
|
set num $op
|
|
|
|
set op "=="
|
|
|
|
}
|
|
|
|
|
|
|
|
return [expr $ref $op $num]
|
|
|
|
}
|
|
|
|
|
|
|
|
proc ::sweeper::strcontains {ref val} {
|
|
|
|
return [expr \
|
|
|
|
[string first [string tolower $val] [string tolower $ref]] \
|
|
|
|
>= 0]
|
|
|
|
}
|
|
|
|
|
|
|
|
######################################################################
|
|
|
|
# Rule clauses
|
|
|
|
|
|
|
|
proc ::sweeper::flag {ts flag} {
|
|
|
|
return [$ts flag $flag]
|
|
|
|
}
|
|
|
|
|
2013-08-30 21:31:52 +00:00
|
|
|
proc ::sweeper::lcn {ts num} {
|
2013-07-12 22:43:15 +00:00
|
|
|
return [::sweeper::intcomp [$ts get channel_num] $num]
|
|
|
|
}
|
|
|
|
|
|
|
|
proc ::sweeper::duration {ts dur} {
|
|
|
|
return [::sweeper::intcomp [$ts duration] $dur]
|
|
|
|
}
|
|
|
|
|
2013-09-04 23:20:59 +00:00
|
|
|
proc ::sweeper::hour {ts str} {
|
|
|
|
set hour [clock format [$ts get start] -format "%H"]
|
|
|
|
return [::sweeper::intcomp $hour $str]
|
|
|
|
}
|
|
|
|
|
2013-07-12 22:43:15 +00:00
|
|
|
proc ::sweeper::schedduration {ts dur} {
|
|
|
|
return [::sweeper::intcomp [$ts get scheddur] $dur]
|
|
|
|
}
|
|
|
|
|
|
|
|
proc ::sweeper::size {ts size} {
|
|
|
|
return [::sweeper::intcomp [$ts size] $size]
|
|
|
|
}
|
|
|
|
|
2013-12-17 23:27:57 +00:00
|
|
|
proc ::sweeper::age {ts age} {
|
|
|
|
set recage $(([clock seconds] - [$ts get end]) / 3600)
|
|
|
|
log " ... Recording age: $recage" 2
|
|
|
|
return [::sweeper::intcomp $recage $age]
|
|
|
|
}
|
|
|
|
|
2014-05-19 20:36:08 +00:00
|
|
|
proc ::sweeper::wage {ts age} {
|
|
|
|
set recage $(([clock seconds] - [$ts lastmod]) / 3600)
|
|
|
|
log " ... Watched age: $recage" 2
|
|
|
|
return [::sweeper::intcomp $recage $age]
|
|
|
|
}
|
|
|
|
|
2013-07-12 22:43:15 +00:00
|
|
|
proc ::sweeper::definition {ts def} {
|
|
|
|
return [::sweeper::strcontains [$ts get definition] $def]
|
|
|
|
}
|
|
|
|
|
|
|
|
proc ::sweeper::title {ts str} {
|
|
|
|
return [::sweeper::strcontains [$ts get title] $str]
|
|
|
|
}
|
|
|
|
|
|
|
|
proc ::sweeper::synopsis {ts str} {
|
|
|
|
return [::sweeper::strcontains [$ts get synopsis] $str]
|
|
|
|
}
|
|
|
|
|
|
|
|
proc ::sweeper::guidance {ts str} {
|
|
|
|
return [::sweeper::strcontains [$ts get guidance] $str]
|
|
|
|
}
|
|
|
|
|
|
|
|
proc ::sweeper::genre {ts genre} {
|
|
|
|
set glist [ts genrelist]
|
|
|
|
|
|
|
|
set tsg [$ts get genre]
|
|
|
|
if {![dict exists $glist $tsg]} { return 0 }
|
|
|
|
|
|
|
|
if {[lindex $glist($tsg) 0] eq $genre} { return 1 }
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2013-09-04 23:20:59 +00:00
|
|
|
proc ::sweeper::lock {ts g} {
|
|
|
|
if {$g} {
|
|
|
|
log "Locked recording." 0
|
|
|
|
$ts lock
|
|
|
|
} else {
|
|
|
|
log "Unlocked recording." 0
|
|
|
|
$ts unlock
|
|
|
|
}
|
2013-09-05 19:05:31 +00:00
|
|
|
return 1
|
2013-09-04 23:20:59 +00:00
|
|
|
}
|
|
|
|
|
2013-07-12 22:43:15 +00:00
|
|
|
######################################################################
|
|
|
|
|
2013-07-17 08:54:34 +00:00
|
|
|
proc ::sweeper::action {ts cmds} {
|
2013-07-12 22:43:15 +00:00
|
|
|
global root
|
|
|
|
|
2013-07-17 08:54:34 +00:00
|
|
|
lassign $cmds cmd rest
|
2013-07-12 22:43:15 +00:00
|
|
|
|
|
|
|
log "ACTION: $cmd\($rest)" 2
|
|
|
|
|
2013-09-03 20:38:54 +00:00
|
|
|
switch $cmd {
|
2013-07-12 22:43:15 +00:00
|
|
|
preserve { return 1 }
|
2013-09-03 20:38:54 +00:00
|
|
|
move -
|
2013-08-30 21:31:52 +00:00
|
|
|
movecreate {
|
2013-09-03 20:38:54 +00:00
|
|
|
set rest [::sweeper::expand $ts $rest]
|
2013-08-30 21:31:52 +00:00
|
|
|
if {![file isdirectory "$root/$rest"]} {
|
2013-09-03 20:38:54 +00:00
|
|
|
if {$cmd eq "move"} {
|
|
|
|
log " ... No such directory $root/$rest" 2
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
system mkdir_p "$root/$rest"
|
|
|
|
if {![file isdirectory "$root/$rest"]} {
|
|
|
|
log "Error creating directory $root/$rest" 1
|
|
|
|
return 1
|
|
|
|
} else {
|
|
|
|
log " ... created directory $root/$rest" 2
|
|
|
|
}
|
2013-08-30 21:31:52 +00:00
|
|
|
}
|
|
|
|
log "Moving [$ts get file] to $rest" 0
|
|
|
|
foreach f [$ts fileset] {
|
|
|
|
log " ....... $f"
|
|
|
|
file rename $f "$root/$rest/[file tail $f]"
|
2013-09-05 19:05:31 +00:00
|
|
|
if {"$root/$rest" ni $::sweeper::recalc} {
|
|
|
|
lappend ::sweeper::recalc "$root/$rest"
|
2013-08-30 21:31:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return 1
|
|
|
|
}
|
2013-09-04 23:20:59 +00:00
|
|
|
default {
|
|
|
|
log "Unknown action '$cmd'" 0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
proc ::sweeper::find {root target orig} {
|
|
|
|
set dustbin [system dustbin 1]
|
|
|
|
foreach e [readdir -nocomplain $root] {
|
|
|
|
regsub -all -- {//} "$root/$e" "/" entry
|
|
|
|
if {![file isdirectory $entry]} continue
|
|
|
|
if {[string match {\[*} $e]} continue
|
|
|
|
if {$e eq $dustbin} continue
|
|
|
|
if {$entry eq $orig} continue
|
|
|
|
|
|
|
|
if {$e eq $target} { return $entry }
|
|
|
|
set ret [::sweeper::find $entry $target $orig]
|
|
|
|
if {$ret ne ""} { return $ret }
|
|
|
|
}
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
|
|
|
proc ::sweeper:folder_merge {src dst} {
|
2013-10-29 20:11:39 +00:00
|
|
|
if {$src eq $dst} return
|
2013-09-04 23:20:59 +00:00
|
|
|
log "Moving recordings from $src to $dst" 0
|
|
|
|
foreach e [readdir -nocomplain $src] {
|
|
|
|
if {![string match {*.ts} $e]} continue
|
|
|
|
set entry "$src/$e"
|
|
|
|
|
2014-02-23 16:11:15 +00:00
|
|
|
log "+ Sweeper processing $entry" 2
|
|
|
|
|
2013-09-04 23:20:59 +00:00
|
|
|
if {[catch {set ts [ts fetch $entry]} msg} {
|
|
|
|
log "Error reading TS file, $msg" 0
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if {$ts == "0"} {
|
2014-02-23 16:11:15 +00:00
|
|
|
log "Invalid TS file." 2
|
2013-09-04 23:20:59 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if {[$ts inuse]} {
|
|
|
|
log "Recording in use." 2
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach f [$ts fileset] {
|
|
|
|
log " ....... $f"
|
|
|
|
file rename $f "$dst/[file tail $f]"
|
|
|
|
}
|
|
|
|
}
|
2013-09-05 19:05:31 +00:00
|
|
|
if {![system rmdir_if_empty $src]} {
|
2013-10-29 20:11:39 +00:00
|
|
|
log "Failed to remove directory" 0
|
|
|
|
foreach l [system rmdir_if_empty $src 1] {
|
|
|
|
log "Blocking file: $l" 0
|
|
|
|
}
|
2013-09-04 23:20:59 +00:00
|
|
|
}
|
|
|
|
if {$dst ni $::sweeper::recalc} {
|
|
|
|
lappend ::sweeper::recalc $dst
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
proc ::sweeper::folder_action {ts cmds} {
|
|
|
|
global root
|
|
|
|
|
|
|
|
lassign $cmds cmd rest
|
|
|
|
|
|
|
|
set folder [file dirname [$ts get file]]
|
|
|
|
set lfolder [file tail $folder]
|
|
|
|
|
|
|
|
log "FOLDER ACTION: $cmd\($rest) @\[$folder]" 2
|
|
|
|
|
|
|
|
switch $cmd {
|
|
|
|
preserve { return 1 }
|
2013-09-09 20:25:23 +00:00
|
|
|
movecreate -
|
|
|
|
move {
|
|
|
|
set rest [::sweeper::expand $ts $rest]
|
|
|
|
if {![file isdirectory "$root/$rest"]} {
|
|
|
|
if {$cmd eq "move"} {
|
|
|
|
log " ... No such directory $root/$rest" 2
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
system mkdir_p "$root/$rest"
|
|
|
|
if {![file isdirectory "$root/$rest"]} {
|
|
|
|
log "Error creating directory $root/$rest" 1
|
|
|
|
return 1
|
|
|
|
} else {
|
|
|
|
log " ... created directory $root/$rest" 2
|
|
|
|
}
|
|
|
|
}
|
|
|
|
::sweeper:folder_merge $folder "$root/$rest"
|
|
|
|
return 1
|
|
|
|
}
|
2013-09-04 23:20:59 +00:00
|
|
|
fileundercreate -
|
|
|
|
fileunder {
|
|
|
|
if {![file isdirectory "$root/$rest"]} {
|
|
|
|
log " ... No such directory $root/$rest" 2
|
|
|
|
return 1
|
|
|
|
}
|
|
|
|
log " - searching for $lfolder under $root/$rest" 2
|
|
|
|
set target [::sweeper::find $root/$rest $lfolder $folder]
|
|
|
|
log " = $target" 2
|
|
|
|
if {$target eq "" || ![file isdirectory $target]} {
|
|
|
|
log "Did not find directory." 2
|
|
|
|
if {$cmd ne "fileundercreate"} { return 1 }
|
|
|
|
set target "$root/$rest/$lfolder"
|
2013-09-05 19:05:31 +00:00
|
|
|
log "Creating $target" 0
|
2013-09-04 23:20:59 +00:00
|
|
|
system mkdir_p $target
|
|
|
|
}
|
|
|
|
::sweeper:folder_merge $folder $target
|
2013-09-09 20:27:54 +00:00
|
|
|
return 1
|
2013-09-04 23:20:59 +00:00
|
|
|
}
|
|
|
|
default {
|
|
|
|
log "Unknown action '$cmd'" 0
|
|
|
|
}
|
2013-07-12 22:43:15 +00:00
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
proc ::sweeper::runrule {ts rule} {
|
|
|
|
log "Processing \[$rule]" 2
|
|
|
|
|
2013-08-30 21:31:52 +00:00
|
|
|
if {[string index $rule 0] eq "#" || [llength $rule] < 2} { return 0 }
|
|
|
|
|
2013-09-04 23:20:59 +00:00
|
|
|
set folder 0
|
|
|
|
if {[lindex $rule 0] eq "folder"} {
|
|
|
|
set folder 1
|
|
|
|
set rule [lrange $rule 1 end]
|
|
|
|
}
|
2013-07-12 22:43:15 +00:00
|
|
|
while {[llength $rule] > 1} {
|
|
|
|
set rule [lassign $rule cmd arg]
|
|
|
|
log " $cmd\($arg)" 2
|
2013-09-04 23:20:59 +00:00
|
|
|
if {$folder && [exists -proc ::sweeper::folder_$cmd]} {
|
|
|
|
set ret [::sweeper::folder_$cmd $ts $arg]
|
|
|
|
} else {
|
|
|
|
set ret [::sweeper::$cmd $ts $arg]
|
|
|
|
}
|
2013-07-12 22:43:15 +00:00
|
|
|
if {$cmd eq "action"} { return $ret }
|
|
|
|
if {!$ret} {
|
|
|
|
log " Nomatch" 2
|
|
|
|
break
|
|
|
|
}
|
|
|
|
log " MATCH" 2
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2013-07-17 08:54:34 +00:00
|
|
|
proc ::sweeper::apply {dir cf} {
|
|
|
|
if {[catch {set fp [open $cf r]} msg]} {
|
|
|
|
log "Error opening sweeper ruleset ($cf), $msg" 0
|
2013-07-12 22:43:15 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2013-08-30 21:31:52 +00:00
|
|
|
set ::sweeper::recalc {}
|
|
|
|
|
2013-07-12 22:43:15 +00:00
|
|
|
set rules [split [read $fp] "\n"]
|
|
|
|
$fp close
|
|
|
|
|
2013-09-04 23:20:59 +00:00
|
|
|
set runfolder 0
|
|
|
|
foreach rule $rules {
|
|
|
|
if {[lindex $rule 0] eq "folder"} { incr runfolder }
|
|
|
|
}
|
|
|
|
|
2013-07-17 08:54:34 +00:00
|
|
|
log "Sweep scan starting for $dir" 2
|
2013-07-12 22:43:15 +00:00
|
|
|
|
2013-07-17 08:54:34 +00:00
|
|
|
foreach e [readdir -nocomplain $dir] {
|
|
|
|
set entry "$dir/$e"
|
2013-07-12 22:43:15 +00:00
|
|
|
if {[file isdirectory $entry]} continue
|
2013-11-06 22:14:37 +00:00
|
|
|
#if {![string match {*.ts} $entry]} continue
|
2013-07-12 22:43:15 +00:00
|
|
|
|
|
|
|
log "+ Sweeper processing $entry" 2
|
|
|
|
|
|
|
|
if {[catch {set ts [ts fetch $entry]} msg} {
|
|
|
|
log "Error reading TS file, $msg" 0
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if {$ts == "0"} {
|
2014-02-23 16:11:15 +00:00
|
|
|
log "Invalid TS file." 2
|
2013-07-12 22:43:15 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2013-07-13 19:57:31 +00:00
|
|
|
if {[$ts inuse]} {
|
|
|
|
log "Recording in use." 2
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
2013-07-12 22:43:15 +00:00
|
|
|
foreach rule $rules {
|
2013-09-04 23:20:59 +00:00
|
|
|
if {[lindex $rule 0] eq "folder"} continue
|
|
|
|
if {[string index $rule 0] eq "#" || \
|
|
|
|
[llength $rule] < 2} continue
|
2013-07-12 22:43:15 +00:00
|
|
|
if {[::sweeper::runrule $ts $rule]} break
|
|
|
|
}
|
|
|
|
}
|
2013-08-30 21:31:52 +00:00
|
|
|
|
2013-09-04 23:20:59 +00:00
|
|
|
if {$runfolder > 0} {
|
|
|
|
log "" 2
|
|
|
|
log " -- FOLDER RULES --" 2
|
|
|
|
log "" 2
|
|
|
|
set dustbin [system dustbin 1]
|
|
|
|
foreach e [readdir -nocomplain $dir] {
|
|
|
|
set entry "$dir/$e"
|
|
|
|
if {![file isdirectory $entry]} continue
|
|
|
|
if {[string match {\[*} $e]} continue
|
|
|
|
if {$e eq $dustbin} continue
|
|
|
|
|
|
|
|
log "+ Sweeper processing folder $entry" 2
|
|
|
|
|
|
|
|
if {![file exists "$entry/.series"]} {
|
|
|
|
log "Not series folder." 2
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
set ts 0
|
|
|
|
foreach de [readdir -nocomplain $entry] {
|
|
|
|
set dentry "$entry/$de"
|
|
|
|
if {[file isdirectory $dentry]} {
|
|
|
|
set ts 0
|
|
|
|
break
|
|
|
|
}
|
|
|
|
if {$ts ne "0"} continue
|
|
|
|
if {![string match {*.ts} $dentry]} continue
|
|
|
|
|
|
|
|
log " --- Considering $dentry" 2
|
|
|
|
|
|
|
|
if {[catch {set ts [ts fetch $dentry]} msg} {
|
|
|
|
log "Error reading TS file, $msg" 2
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if {$ts == "0"} {
|
|
|
|
log "Invalid TS file." 2
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if {[$ts inuse]} {
|
|
|
|
log "Recording in use." 2
|
|
|
|
set ts 0
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
if {$ts == "0"} {
|
|
|
|
log "No usable recordings in folder." 2
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach rule $rules {
|
|
|
|
if {[string index $rule 0] eq "#" || \
|
|
|
|
[llength $rule] < 2} continue
|
|
|
|
if {[lindex $rule 0] ne "folder"} continue
|
|
|
|
if {[::sweeper::runrule $ts $rule]} break
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-30 21:31:52 +00:00
|
|
|
foreach dir $::sweeper::recalc {
|
2013-09-05 19:05:31 +00:00
|
|
|
log "Resetting unwatched recording flag for $dir" 0
|
|
|
|
ts resetnew $dir
|
2013-08-30 21:31:52 +00:00
|
|
|
}
|
2013-07-12 22:43:15 +00:00
|
|
|
}
|
|
|
|
|
2013-07-17 08:54:34 +00:00
|
|
|
proc ::sweeper::scan {args} {
|
|
|
|
::sweeper::apply $::root $::sweeper::cf
|
|
|
|
}
|
|
|
|
|
2013-07-12 22:43:15 +00:00
|
|
|
if {[file exists $::sweeper::cf]} {
|
|
|
|
register postdecryptscan ::sweeper::scan
|
|
|
|
}
|
|
|
|
|