sweeper 2.0.0 + add and/or, tooltips, moveset
This commit is contained in:
parent
270701873d
commit
d5319e6f0d
|
@ -1 +0,0 @@
|
|||
etc/sweeper.conf
|
|
@ -1,9 +1,9 @@
|
|||
Package: sweeper
|
||||
Priority: optional
|
||||
Section: misc
|
||||
Version: 1.0.19
|
||||
Version: 2.0.0
|
||||
Architecture: mipsel
|
||||
Maintainer: af123@hummypkg.org.uk
|
||||
Depends: webif(>=1.0.14-8)
|
||||
Description: Sweeper is a package for managing recordings in a variety of ways using custom rules [Add delete action. Some online help.]
|
||||
Depends: webif(>=1.0.14-10)
|
||||
Description: Sweeper is a package for managing recordings in a variety of ways using custom rules [Add and/or clauses. See forum.]
|
||||
Tags: http://hummy.tv/forum/threads/5138/
|
||||
|
|
|
@ -69,67 +69,135 @@ proc ::sweeper::strcontains {ref val} {
|
|||
>= 0]
|
||||
}
|
||||
|
||||
######################################################################
|
||||
# Rule criteria
|
||||
proc ::sweeper::moveset {ts dst {op rename}} {
|
||||
set file [$ts get file]
|
||||
log "${op}set($file) -> $dst" 0
|
||||
|
||||
proc ::sweeper::flag {ts flag} {
|
||||
# Handle alias for rename
|
||||
if {$op eq "move"} { set op "rename" }
|
||||
|
||||
# Determine whether this is a cross-filesystem move.
|
||||
file stat [$ts get file] sts
|
||||
file stat $dst std
|
||||
set xfs 0
|
||||
if {$sts(dev) ne $std(dev)} {
|
||||
log " Cross-filesystem - will copy then delete." 0
|
||||
set xfs 1
|
||||
}
|
||||
|
||||
set fset [lsort [$ts fileset]]
|
||||
|
||||
if {$xfs && $op eq "rename"} {
|
||||
# For cross-filesystem moves, copy the whole file set
|
||||
# and then delete the originals if all the copies were
|
||||
# successful.
|
||||
foreach f $fset {
|
||||
set tail [file tail $f]
|
||||
if {[catch {file copy $f "$dst/$tail"} msg]} {
|
||||
log " ....... $f: XFS copy failed, $msg." 0
|
||||
file delete -force "$dst/$tail"
|
||||
log " .... Leaving originals intact." 0
|
||||
return
|
||||
}
|
||||
log " ....... $f: OK" 0
|
||||
}
|
||||
log " Now deleting original files." 0
|
||||
foreach f $fset {
|
||||
set tail [file tail $f]
|
||||
if {[file exists "$dst/$tail"] &&
|
||||
[file size "$dst/$tail"] ==
|
||||
[file size $f]} {
|
||||
file tdelete $f
|
||||
log " ....... $f: OK" 0
|
||||
} else {
|
||||
log " ....... $f: ERROR, sizes differ." 0
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
# Otherwise - copy or local FS move.
|
||||
|
||||
foreach f $fset {
|
||||
set tail [file tail $f]
|
||||
if {$op eq "copy" && [file exists "$dst/$tail"]} {
|
||||
if {[file size "$dst/$tail"] == [file size $f]} {
|
||||
log " ....... $f: Already copied." 2
|
||||
continue
|
||||
}
|
||||
log "Deleting truncated copy $dst/$tail" 0
|
||||
file tdelete "$dst/$tail"
|
||||
}
|
||||
log " ....... $f"
|
||||
if {[catch {file $op $f "$dst/[file tail $f]"} msg]} {
|
||||
log "$op failed, $msg.", 0
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
######################################################################
|
||||
# Rule conditions
|
||||
|
||||
proc ::sweeper::flag {ts flag folder} {
|
||||
return [$ts flag $flag]
|
||||
}
|
||||
|
||||
proc ::sweeper::lcn {ts num} {
|
||||
proc ::sweeper::lcn {ts num folder} {
|
||||
return [::sweeper::intcomp [$ts get channel_num] $num]
|
||||
}
|
||||
|
||||
proc ::sweeper::duration {ts dur} {
|
||||
proc ::sweeper::duration {ts dur folder} {
|
||||
return [::sweeper::intcomp [$ts duration] $dur]
|
||||
}
|
||||
|
||||
proc ::sweeper::hour {ts str} {
|
||||
proc ::sweeper::hour {ts str folder} {
|
||||
set hour [clock format [$ts get start] -format "%H"]
|
||||
return [::sweeper::intcomp $hour $str]
|
||||
}
|
||||
|
||||
proc ::sweeper::schedduration {ts dur} {
|
||||
proc ::sweeper::schedduration {ts dur folder} {
|
||||
return [::sweeper::intcomp [$ts get scheddur] $dur]
|
||||
}
|
||||
|
||||
proc ::sweeper::size {ts size} {
|
||||
proc ::sweeper::size {ts size folder} {
|
||||
return [::sweeper::intcomp [$ts size] $size]
|
||||
}
|
||||
|
||||
proc ::sweeper::age {ts age} {
|
||||
proc ::sweeper::age {ts age folder} {
|
||||
set recage $(([clock seconds] - [$ts get end]) / 3600)
|
||||
log " ... Recording age: $recage" 2
|
||||
return [::sweeper::intcomp $recage $age]
|
||||
}
|
||||
|
||||
proc ::sweeper::wage {ts age} {
|
||||
proc ::sweeper::wage {ts age folder} {
|
||||
set recage $(([clock seconds] - [$ts lastmod]) / 3600)
|
||||
log " ... Watched age: $recage" 2
|
||||
return [::sweeper::intcomp $recage $age]
|
||||
}
|
||||
|
||||
proc ::sweeper::definition {ts def} {
|
||||
proc ::sweeper::definition {ts def folder} {
|
||||
return [::sweeper::strcontains [$ts get definition] $def]
|
||||
}
|
||||
|
||||
proc ::sweeper::filename {ts str} {
|
||||
proc ::sweeper::filename {ts str folder} {
|
||||
return [::sweeper::strcontains [$ts bfile] $str]
|
||||
}
|
||||
|
||||
proc ::sweeper::title {ts str} {
|
||||
proc ::sweeper::title {ts str folder} {
|
||||
return [::sweeper::strcontains [$ts get title] $str]
|
||||
}
|
||||
|
||||
proc ::sweeper::synopsis {ts str} {
|
||||
proc ::sweeper::synopsis {ts str folder} {
|
||||
return [::sweeper::strcontains [$ts get synopsis] $str]
|
||||
}
|
||||
|
||||
proc ::sweeper::guidance {ts str} {
|
||||
proc ::sweeper::guidance {ts str folder} {
|
||||
return [::sweeper::strcontains [$ts get guidance] $str]
|
||||
}
|
||||
|
||||
proc ::sweeper::genre {ts genre} {
|
||||
proc ::sweeper::genre {ts genre folder} {
|
||||
set glist [ts genrelist]
|
||||
|
||||
set tsg [$ts get genre]
|
||||
|
@ -139,7 +207,7 @@ proc ::sweeper::genre {ts genre} {
|
|||
return 0
|
||||
}
|
||||
|
||||
proc ::sweeper::lock {ts g} {
|
||||
proc ::sweeper::lock {ts g folder} {
|
||||
if {$g} {
|
||||
if {![$ts flag Locked]} {
|
||||
log "Locked recording." 0
|
||||
|
@ -154,13 +222,13 @@ proc ::sweeper::lock {ts g} {
|
|||
return 1
|
||||
}
|
||||
|
||||
proc ::sweeper::folder_fflag {ts flag} {
|
||||
proc ::sweeper::folder_fflag {ts flag folder} {
|
||||
return [file exists "[file dirname [$ts get file]]/.$flag"]
|
||||
}
|
||||
|
||||
######################################################################
|
||||
|
||||
proc ::sweeper::action {ts cmds} {
|
||||
proc ::sweeper::action {ts cmds folder} {
|
||||
global root
|
||||
|
||||
lassign $cmds cmd rest
|
||||
|
@ -171,12 +239,19 @@ proc ::sweeper::action {ts cmds} {
|
|||
continue { return 0 }
|
||||
stop { return 1 }
|
||||
preserve { return 1 }
|
||||
copy -
|
||||
copycreate -
|
||||
move -
|
||||
movecreate {
|
||||
set rest [::sweeper::expand $ts $rest]
|
||||
set dir [::sweeper::resolvedir $rest]
|
||||
set create 0
|
||||
if {[string range $cmd end-5 end] eq "create"} {
|
||||
set create 1
|
||||
set cmd [string range $cmd 0 end-6]
|
||||
}
|
||||
if {![file isdirectory $dir]} {
|
||||
if {$cmd eq "move"} {
|
||||
if {!$create} {
|
||||
log " ... No such directory $dir" 2
|
||||
return 1
|
||||
}
|
||||
|
@ -190,14 +265,11 @@ proc ::sweeper::action {ts cmds} {
|
|||
}
|
||||
}
|
||||
}
|
||||
log "Moving [$ts get file] to $rest" 0
|
||||
foreach f [$ts fileset] {
|
||||
log " ....... $f"
|
||||
if {!$::sweeper::dryrun} {
|
||||
file rename $f "$dir/[file tail $f]"
|
||||
if {"$dir" ni $::sweeper::recalc} {
|
||||
lappend ::sweeper::recalc $dir
|
||||
}
|
||||
log "$cmd [$ts get file] to $rest" 0
|
||||
if {!$::sweeper::dryrun} {
|
||||
::sweeper::moveset $ts $dir $cmd
|
||||
if {"$dir" ni $::sweeper::recalc} {
|
||||
lappend ::sweeper::recalc $dir
|
||||
}
|
||||
}
|
||||
return 1
|
||||
|
@ -291,7 +363,8 @@ proc ::sweeper::folder_apply {dir callback} {
|
|||
|
||||
proc ::sweeper:folder_merge {src dst {op rename}} {
|
||||
if {$src eq $dst} return
|
||||
log "Moving recordings from $src to $dst" 0
|
||||
if {$op eq "move"} { set op "rename" }
|
||||
log "$op recordings from $src to $dst" 0
|
||||
foreach e [readdir -nocomplain $src] {
|
||||
if {![string match {*.ts} $e]} continue
|
||||
set entry "$src/$e"
|
||||
|
@ -313,12 +386,7 @@ proc ::sweeper:folder_merge {src dst {op rename}} {
|
|||
continue
|
||||
}
|
||||
|
||||
foreach f [$ts fileset] {
|
||||
if {$op eq "copy" \
|
||||
&& [file exists "$dst/[file tail $f]"]} continue
|
||||
log " ....... $f"
|
||||
file $op $f "$dst/[file tail $f]"
|
||||
}
|
||||
::sweeper::moveset $ts $dst $op
|
||||
}
|
||||
if {$op eq "rename" && ![system rmdir_if_empty $src]} {
|
||||
log "Failed to remove directory" 0
|
||||
|
@ -331,7 +399,7 @@ proc ::sweeper:folder_merge {src dst {op rename}} {
|
|||
}
|
||||
}
|
||||
|
||||
proc ::sweeper::folder_action {ts cmds} {
|
||||
proc ::sweeper::folder_action {ts cmds folder} {
|
||||
global root
|
||||
|
||||
lassign $cmds cmd rest
|
||||
|
@ -345,12 +413,19 @@ proc ::sweeper::folder_action {ts cmds} {
|
|||
continue { return 0 }
|
||||
stop { return 1 }
|
||||
preserve { return 1 }
|
||||
copycreate -
|
||||
copy -
|
||||
movecreate -
|
||||
move {
|
||||
set rest [::sweeper::expand $ts $rest]
|
||||
set dir [::sweeper::resolvedir $rest]
|
||||
set create 0
|
||||
if {[string range $cmd end-5 end] eq "create"} {
|
||||
set create 1
|
||||
set cmd [string range $cmd 0 end-6]
|
||||
}
|
||||
if {![file isdirectory $dir]} {
|
||||
if {$cmd eq "move"} {
|
||||
if {!$create} {
|
||||
log " ... No such directory $dir" 2
|
||||
return 1
|
||||
}
|
||||
|
@ -365,7 +440,7 @@ proc ::sweeper::folder_action {ts cmds} {
|
|||
}
|
||||
}
|
||||
if {!$::sweeper::dryrun} {
|
||||
::sweeper:folder_merge $folder $dir
|
||||
::sweeper:folder_merge $folder $dir $cmd
|
||||
}
|
||||
return 1
|
||||
}
|
||||
|
@ -450,6 +525,64 @@ proc ::sweeper::folder_action {ts cmds} {
|
|||
return 0
|
||||
}
|
||||
|
||||
proc ::sweeper::or {ts clause folder} {
|
||||
log " --> OR:" 2
|
||||
set ret 0
|
||||
while {[llength $clause] > 1} {
|
||||
set clause [lassign $clause cmd arg]
|
||||
set ret [::sweeper::clause $folder $cmd $arg $ts]
|
||||
if {$ret} {
|
||||
log " <-- OR true." 2
|
||||
break
|
||||
}
|
||||
}
|
||||
if {!$ret} {
|
||||
log " <-- OR false." 2
|
||||
}
|
||||
return $ret
|
||||
}
|
||||
|
||||
proc ::sweeper::and {ts clause folder} {
|
||||
log " --> AND:" 2
|
||||
set ret 0
|
||||
while {[llength $clause] > 1} {
|
||||
set clause [lassign $clause cmd arg]
|
||||
set ret [::sweeper::clause $folder $cmd $arg $ts]
|
||||
if {!$ret} {
|
||||
log " <-- AND false." 2
|
||||
break
|
||||
}
|
||||
}
|
||||
if {$ret} {
|
||||
log " <-- AND true." 2
|
||||
}
|
||||
return $ret
|
||||
}
|
||||
|
||||
proc ::sweeper::clause {folder cmd arg ts} {
|
||||
log " $cmd\($arg)" 2
|
||||
|
||||
if {[string index $cmd 0] eq "!"} {
|
||||
set negate 1
|
||||
set cmd [string range $cmd 1 end]
|
||||
} else {
|
||||
set negate 0
|
||||
}
|
||||
if {$folder && [exists -proc ::sweeper::folder_$cmd]} {
|
||||
set ret [::sweeper::folder_$cmd $ts $arg $folder]
|
||||
} else {
|
||||
set ret [::sweeper::$cmd $ts $arg $folder]
|
||||
}
|
||||
if {$cmd eq "action"} { return $ret }
|
||||
if {$negate} { set ret $(!$ret) }
|
||||
if {!$ret} {
|
||||
log " Nomatch" 2
|
||||
} else {
|
||||
log " MATCH" 2
|
||||
}
|
||||
return $ret
|
||||
}
|
||||
|
||||
proc ::sweeper::runrule {ts rule} {
|
||||
log "Processing \[$rule]" 2
|
||||
|
||||
|
@ -462,25 +595,9 @@ proc ::sweeper::runrule {ts rule} {
|
|||
}
|
||||
while {[llength $rule] > 1} {
|
||||
set rule [lassign $rule cmd arg]
|
||||
log " $cmd\($arg)" 2
|
||||
if {[string index $cmd 0] eq "!"} {
|
||||
set negate 1
|
||||
set cmd [string range $cmd 1 end]
|
||||
} else {
|
||||
set negate 0
|
||||
}
|
||||
if {$folder && [exists -proc ::sweeper::folder_$cmd]} {
|
||||
set ret [::sweeper::folder_$cmd $ts $arg]
|
||||
} else {
|
||||
set ret [::sweeper::$cmd $ts $arg]
|
||||
}
|
||||
set ret [::sweeper::clause $folder $cmd $arg $ts]
|
||||
if {$cmd eq "action"} { return $ret }
|
||||
if {$negate} { set ret $(!$ret) }
|
||||
if {!$ret} {
|
||||
log " Nomatch" 2
|
||||
break
|
||||
}
|
||||
log " MATCH" 2
|
||||
if {!$ret} break
|
||||
}
|
||||
|
||||
return 0
|
||||
|
@ -498,12 +615,18 @@ proc ::sweeper::apply {dir cf} {
|
|||
$fp close
|
||||
|
||||
set runfolder 0
|
||||
set nrules 0
|
||||
foreach rule $rules {
|
||||
if {[lindex $rule 0] eq "folder"} { incr runfolder }
|
||||
if {[string index $rule 0] ne "#" && [llength $rule] > 1} {
|
||||
incr nrules
|
||||
}
|
||||
}
|
||||
|
||||
if {!$nrules} return
|
||||
|
||||
log "" 2
|
||||
log "--- SWEEP SCAN STARTING FOR $dir ---" 2
|
||||
log "--- SWEEP SCAN STARTING FOR $dir ($nrules) ---" 2
|
||||
log "" 2
|
||||
|
||||
foreach e [readdir -nocomplain $dir] {
|
||||
|
@ -530,7 +653,7 @@ proc ::sweeper::apply {dir cf} {
|
|||
|
||||
foreach rule $rules {
|
||||
if {[lindex $rule 0] eq "folder"} continue
|
||||
if {[string index $rule 0] eq "#" || \
|
||||
if {[string index $rule 0] eq "#" ||
|
||||
[llength $rule] < 2} continue
|
||||
if {[::sweeper::runrule $ts $rule]} break
|
||||
}
|
||||
|
@ -608,7 +731,7 @@ proc ::sweeper::apply {dir cf} {
|
|||
}
|
||||
|
||||
foreach rule $rules {
|
||||
if {[string index $rule 0] eq "#" || \
|
||||
if {[string index $rule 0] eq "#" ||
|
||||
[llength $rule] < 2} continue
|
||||
if {[lindex $rule 0] ne "folder"} continue
|
||||
if {[::sweeper::runrule $ts $rule]} break
|
||||
|
|
|
@ -74,30 +74,29 @@ Add pre-defined ruleset:
|
|||
</span>
|
||||
<a class=enadisrule href=#>
|
||||
<img src=img/disable.png
|
||||
alt="Enable/Disable Rule"
|
||||
title="Enable/Disable Rule">
|
||||
</a>
|
||||
<a class=delrule href=#>
|
||||
<img src=/img/context/delete.png
|
||||
alt="Delete Rule" title="Delete Rule">
|
||||
title="Delete Rule">
|
||||
</a>
|
||||
<a class=cprule href=#>
|
||||
<img src=/img/context/page_white_copy.png
|
||||
alt="Duplicate Rule" title="Duplicate Rule">
|
||||
title="Duplicate Rule">
|
||||
</a>
|
||||
<a class=uprule href=#>
|
||||
<img src=/img/nav/up.png
|
||||
alt="Move Rule Up" title="Move Rule Up">
|
||||
title="Move Rule Up">
|
||||
</a>
|
||||
<a class=downrule href=#>
|
||||
<img src=/img/nav/down.png
|
||||
alt="Move Rule Down" title="Move Rule Down">
|
||||
title="Move Rule Down">
|
||||
</a>
|
||||
</span>
|
||||
</legend>
|
||||
<a href=# class=addcriterion>
|
||||
<img src=/img/context/plus.png
|
||||
alt="Add condition" title="Add condition">
|
||||
<img src=img/plus.png
|
||||
title="Add condition">
|
||||
</a>
|
||||
<div class=criteria>
|
||||
<table class="criteria"><tbody></tbody></table>
|
||||
|
@ -153,7 +152,7 @@ Add pre-defined ruleset:
|
|||
<select id=newcondition_cmd name=newcondition_cmd></select>
|
||||
</td></tr><tr><th>Negate?</th><td>
|
||||
<input id=newcondition_negate name=newcondition_negate type=checkbox
|
||||
value='1' />
|
||||
value='1' title="Invert the sense of the condition."/>
|
||||
</td></tr>
|
||||
</table>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
|
||||
source /mod/webif/lib/setup
|
||||
require lock system.class ts.class pretty_size browse.class \
|
||||
safe_delete settings.class plugin
|
||||
|
||||
proc log {msg {level 1}} {
|
||||
puts "[\
|
||||
clock format [clock seconds] -format "%d/%m/%Y %H:%M"\
|
||||
] - $msg"
|
||||
}
|
||||
|
||||
proc elapsed {start} {
|
||||
return $(([clock milliseconds] - $start) / 1000.0)
|
||||
}
|
||||
|
||||
proc startclock {} {
|
||||
set ::startclock_s [clock milliseconds]
|
||||
}
|
||||
|
||||
proc endclock {size} {
|
||||
set el [elapsed $::startclock_s]
|
||||
set rate $($size / $el)
|
||||
return "[pretty_size $size] in $el seconds - [pretty_size $rate]/s"
|
||||
}
|
||||
|
||||
proc register {args} {}
|
||||
|
||||
proc scan_run {dir flag callback} {
|
||||
global dustbin
|
||||
|
||||
if {[string match {\[*} [file tail $dir]]} return
|
||||
|
||||
if {[file exists "$dir/.$flag"]} { $callback $dir }
|
||||
|
||||
foreach entry [readdir -nocomplain $dir] {
|
||||
if {[file isdirectory "$dir/$entry"]} {
|
||||
scan_run "$dir/$entry" $flag $callback
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set root [system mediaroot]
|
||||
|
||||
source auto.hook
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
|
@ -6,6 +6,10 @@ require system.class
|
|||
|
||||
set dir [cgi_get dir ""]
|
||||
|
||||
if {$dir eq "" && [llength $argv]} {
|
||||
set dir [lindex $argv 0]
|
||||
}
|
||||
|
||||
set root [system mediaroot]
|
||||
|
||||
if {$dir eq "" || $dir eq $root} {
|
||||
|
@ -45,8 +49,43 @@ proc quot {str} {
|
|||
return [cgi_quote_html $str]
|
||||
}
|
||||
|
||||
set composite {and or}
|
||||
|
||||
proc clause {cmd arg {indent 6}} {
|
||||
global lockfound composite
|
||||
|
||||
set istr [string repeat " " $indent]
|
||||
|
||||
if {[string index $cmd 0] eq "!"} {
|
||||
set negate 1
|
||||
set cmd [string range $cmd 1 end]
|
||||
} else {
|
||||
set negate 0
|
||||
}
|
||||
if {$cmd eq "lock"} { set lockfound $arg }
|
||||
|
||||
add_json "$istr{\n"
|
||||
add_json "$istr \"negate\": $negate,\n"
|
||||
add_json "$istr \"cmd\": \"[quot $cmd]\",\n"
|
||||
add_json "$istr \"arg\": \"[quot $arg]\""
|
||||
if {$cmd in $composite} {
|
||||
add_json ",\n"
|
||||
add_json "$istr \"criteria\": \[\n"
|
||||
set c 0
|
||||
while {[llength $arg] > 1} {
|
||||
set arg [lassign $arg subcmd subarg]
|
||||
if {$c} { add_json ",\n" }
|
||||
incr c
|
||||
clause $subcmd $subarg $($indent + 6)
|
||||
}
|
||||
add_json "\n$istr ]"
|
||||
}
|
||||
add_json "\n"
|
||||
add_json "$istr}"
|
||||
}
|
||||
|
||||
proc rule {id rule} {
|
||||
global clausedescr lcomment
|
||||
global lcomment lockfound
|
||||
|
||||
set enabled 1
|
||||
if {[lindex $rule 0] eq "##"} {
|
||||
|
@ -76,22 +115,11 @@ proc rule {id rule} {
|
|||
set lockfound -1
|
||||
while {[llength $rule] > 1} {
|
||||
set rule [lassign $rule cmd arg]
|
||||
if {[string index $cmd 0] eq "!"} {
|
||||
set negate 1
|
||||
set cmd [string range $cmd 1 end]
|
||||
} else {
|
||||
set negate 0
|
||||
}
|
||||
if {$cmd eq "action"} break
|
||||
if {$cmd eq "lock"} { set lockfound $arg }
|
||||
if {$c} { add_json ",\n" }
|
||||
incr c
|
||||
|
||||
add_json " {\n"
|
||||
add_json " \"negate\": $negate,\n"
|
||||
add_json " \"cmd\": \"[quot $cmd]\",\n"
|
||||
add_json " \"arg\": \"[quot $arg]\"\n"
|
||||
add_json " }"
|
||||
clause $cmd $arg
|
||||
}
|
||||
add_json "\n"
|
||||
if {$cmd ne "action"} {
|
||||
|
|
|
@ -4,42 +4,49 @@ var schema = {
|
|||
'class': 'all',
|
||||
type: 'int',
|
||||
desc: 'Logical Channel Number',
|
||||
negate: true,
|
||||
def: "0"
|
||||
},
|
||||
duration: {
|
||||
'class': 'all',
|
||||
type: 'int',
|
||||
desc: 'Recording duration (in minutes)',
|
||||
negate: true,
|
||||
def: "0"
|
||||
},
|
||||
schedduration: {
|
||||
'class': 'all',
|
||||
type: 'int',
|
||||
desc: 'Scheduled duration (in minutes)',
|
||||
negate: true,
|
||||
def: "0"
|
||||
},
|
||||
size: {
|
||||
'class': 'all',
|
||||
type: 'int',
|
||||
desc: 'Recording size (in bytes)',
|
||||
negate: true,
|
||||
def: "0"
|
||||
},
|
||||
hour: {
|
||||
'class': 'all',
|
||||
type: 'int',
|
||||
desc: 'Hour in which the recording started',
|
||||
negate: true,
|
||||
def: "0"
|
||||
},
|
||||
age: {
|
||||
'class': 'all',
|
||||
type: 'int',
|
||||
desc: 'Age (in hours)',
|
||||
negate: true,
|
||||
def: "0"
|
||||
},
|
||||
wage: {
|
||||
'class': 'all',
|
||||
type: 'int',
|
||||
desc: 'Time since last watched, or recorded (in hours)',
|
||||
negate: true,
|
||||
def: "0"
|
||||
},
|
||||
title: {
|
||||
|
@ -47,6 +54,7 @@ var schema = {
|
|||
type: 'substr',
|
||||
desc: 'Recording Title contains',
|
||||
idesc: 'Recording Title does not contain',
|
||||
negate: true,
|
||||
def: 'Enter text here...'
|
||||
},
|
||||
synopsis: {
|
||||
|
@ -54,6 +62,7 @@ var schema = {
|
|||
type: 'substr',
|
||||
desc: 'Synopsis contains',
|
||||
idesc: 'Synopsis does not contain',
|
||||
negate: true,
|
||||
def: 'Enter text here...'
|
||||
},
|
||||
guidance: {
|
||||
|
@ -61,12 +70,14 @@ var schema = {
|
|||
type: 'substr',
|
||||
desc: 'Guidance Text contains',
|
||||
idesc: 'Guidance Text does not contain',
|
||||
negate: true,
|
||||
def: 'Enter text here...'
|
||||
},
|
||||
genre: {
|
||||
'class': 'all',
|
||||
type: 'select',
|
||||
desc: 'Recording Genre',
|
||||
negate: true,
|
||||
select: {
|
||||
Unclassified: 'Unclassified',
|
||||
Film: 'Film',
|
||||
|
@ -84,6 +95,7 @@ var schema = {
|
|||
'class': 'all',
|
||||
type: 'select',
|
||||
desc: 'Recording Definition',
|
||||
negate: true,
|
||||
select: {
|
||||
SD: 'Standard Definition',
|
||||
HD: 'High Definition'
|
||||
|
@ -95,6 +107,7 @@ var schema = {
|
|||
type: 'select',
|
||||
desc: 'Recording Flagged as',
|
||||
idesc: 'Recording not Flagged as',
|
||||
negate: true,
|
||||
select: {
|
||||
Locked: 'Locked',
|
||||
New: 'New',
|
||||
|
@ -110,6 +123,7 @@ var schema = {
|
|||
'class': 'all',
|
||||
type: 'select',
|
||||
desc: 'Change Recording Lock',
|
||||
negate: true,
|
||||
select: {
|
||||
1: 'Lock Recording',
|
||||
0: 'Unlock Recording'
|
||||
|
@ -121,6 +135,8 @@ var schema = {
|
|||
'class': 'all',
|
||||
type: 'substr',
|
||||
desc: 'Filename contains',
|
||||
idesc: 'Filename does not contain',
|
||||
negate: true,
|
||||
def: 'Enter text here...'
|
||||
},
|
||||
fflag: {
|
||||
|
@ -128,7 +144,24 @@ var schema = {
|
|||
type: 'string',
|
||||
desc: 'Folder flagged as',
|
||||
idesc: 'Folder not flagged as',
|
||||
negate: true,
|
||||
def: 'nosweep'
|
||||
},
|
||||
'or': {
|
||||
'class': 'all',
|
||||
type: 'composite',
|
||||
label: 'Or',
|
||||
desc: 'If any of...',
|
||||
negate: false,
|
||||
def: ''
|
||||
},
|
||||
'and': {
|
||||
'class': 'all',
|
||||
type: 'composite',
|
||||
label: 'And',
|
||||
desc: 'If all of...',
|
||||
negate: false,
|
||||
def: ''
|
||||
}
|
||||
},
|
||||
action: {
|
||||
|
@ -150,24 +183,24 @@ var schema = {
|
|||
desc: 'Move recording to folder...',
|
||||
continues: false
|
||||
},
|
||||
lock: {
|
||||
'class': 'all',
|
||||
argtype: 'none',
|
||||
desc: 'Lock recordings',
|
||||
continues: true
|
||||
},
|
||||
unlock: {
|
||||
'class': 'all',
|
||||
argtype: 'none',
|
||||
desc: 'Unlock recordings',
|
||||
continues: true
|
||||
},
|
||||
movecreate: {
|
||||
'class': 'all',
|
||||
argtype: 'folder',
|
||||
desc: 'Move recording to folder (creating if necessary)',
|
||||
continues: false
|
||||
},
|
||||
copy: {
|
||||
'class': 'all',
|
||||
argtype: 'folder',
|
||||
desc: 'Copy recording to folder...',
|
||||
continues: false
|
||||
},
|
||||
copycreate: {
|
||||
'class': 'all',
|
||||
argtype: 'folder',
|
||||
desc: 'Copy recording to folder (creating if necessary)',
|
||||
continues: false
|
||||
},
|
||||
fileunder: {
|
||||
'class': 'folder',
|
||||
argtype: 'folder',
|
||||
|
@ -187,6 +220,18 @@ var schema = {
|
|||
desc: 'Rename recording files to...',
|
||||
continues: true
|
||||
},
|
||||
lock: {
|
||||
'class': 'all',
|
||||
argtype: 'none',
|
||||
desc: 'Lock recordings',
|
||||
continues: true
|
||||
},
|
||||
unlock: {
|
||||
'class': 'all',
|
||||
argtype: 'none',
|
||||
desc: 'Unlock recordings',
|
||||
continues: true
|
||||
},
|
||||
delete: {
|
||||
'class': 'all',
|
||||
argtype: 'none',
|
||||
|
@ -216,47 +261,38 @@ var macros = {
|
|||
example: {
|
||||
desc: 'Example rules',
|
||||
rules: [
|
||||
{
|
||||
"raw": "lcn {>= 70} lcn {<= 79} duration {>= 90} action {move Children/Films}",
|
||||
"name": "Move any Children's films (by length)",
|
||||
{
|
||||
"raw": "lcn {>= 70} lcn {<= 79} or {duration {>= 90} genre Film } action {move Children/Films}",
|
||||
"name": "Move any Children's films",
|
||||
"type": "file",
|
||||
"enabled": "0",
|
||||
"criteria": [
|
||||
{
|
||||
"negate": 0,
|
||||
"cmd": "lcn",
|
||||
"arg": ">= 70"
|
||||
},
|
||||
{
|
||||
"negate": 0,
|
||||
"cmd": "lcn",
|
||||
"arg": "<= 79"
|
||||
},
|
||||
{
|
||||
"cmd": "duration",
|
||||
"arg": ">= 90"
|
||||
}
|
||||
],
|
||||
"action": {
|
||||
"cmd": "move",
|
||||
"arg": "Children/Films"
|
||||
}
|
||||
},
|
||||
{
|
||||
"raw": "lcn {>= 70} lcn {<= 79} genre Film action {move Children/Films}",
|
||||
"name": "Move any Children's films (by genre)",
|
||||
"type": "file",
|
||||
"enabled": "0",
|
||||
"criteria": [
|
||||
{
|
||||
"cmd": "lcn",
|
||||
"arg": ">= 70"
|
||||
},
|
||||
{
|
||||
"cmd": "lcn",
|
||||
"arg": "<= 79"
|
||||
},
|
||||
{
|
||||
"cmd": "genre",
|
||||
"arg": "Film"
|
||||
"negate": 0,
|
||||
"cmd": "or",
|
||||
"arg": "duration {>= 90} genre Film ",
|
||||
"criteria": [
|
||||
{
|
||||
"negate": 0,
|
||||
"cmd": "duration",
|
||||
"arg": ">= 90"
|
||||
},
|
||||
{
|
||||
"negate": 0,
|
||||
"cmd": "genre",
|
||||
"arg": "Film"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"action": {
|
||||
|
|
|
@ -90,16 +90,20 @@ var getters = {
|
|||
}
|
||||
};
|
||||
|
||||
function ruleconf(rule)
|
||||
function clauseconf(clause)
|
||||
{
|
||||
var s = '';
|
||||
|
||||
if (rule.hasClass('ruledisabled'))
|
||||
s += '## ';
|
||||
if (rule.attr('type') == 'folder')
|
||||
s += 'folder ';
|
||||
|
||||
rule.find('tr.clause').each(function(i) {
|
||||
clause.find('tbody:first > tr.clause,tbody:first > tr.compositeclause')
|
||||
.each(function() {
|
||||
if ($(this).hasClass('compositeclause'))
|
||||
{
|
||||
cc = clauseconf($(this).find('table:first'));
|
||||
cmd = $(this).attr('cmd');
|
||||
if (cc && cc.length)
|
||||
s += cmd + ' {' + cc + '} ';
|
||||
return;
|
||||
}
|
||||
cmd = $(this).find('th.cmd').attr('cmd');
|
||||
negate = $(this).find('th.cmd').attr('negate');
|
||||
c = schema.criterion[cmd];
|
||||
|
@ -111,6 +115,19 @@ function ruleconf(rule)
|
|||
s += '!';
|
||||
s += cmd + ' ' + quot(val) + ' ';
|
||||
});
|
||||
return s;
|
||||
}
|
||||
|
||||
function ruleconf(rule)
|
||||
{
|
||||
var s = '';
|
||||
|
||||
if (rule.hasClass('ruledisabled'))
|
||||
s += '## ';
|
||||
if (rule.attr('type') == 'folder')
|
||||
s += 'folder ';
|
||||
|
||||
s += clauseconf(rule);
|
||||
|
||||
act = rule.find('tr.action th.cmd').attr('cmd');
|
||||
arg = $.trim(rule.find('tr.action td.val').text());
|
||||
|
@ -144,18 +161,23 @@ function rulerefresh(rule)
|
|||
if (!showraw)
|
||||
rule.find('.raw').hide();
|
||||
rule.find('.raw').html(ruleconf(rule));
|
||||
rule.find('tr.clause th.title').text('And:').first().text('If:');
|
||||
if (rule.find('tr.clause').length < 1)
|
||||
rule.find('tr.clause th.title,tr.compositeclause th.title')
|
||||
.text('And:').first().text('If:');
|
||||
rule.find('tr.compositeclause').each(function(e) {
|
||||
cmd = $(this).attr('cmd');
|
||||
label = schema.criterion[cmd].label;
|
||||
$(this).find('table th.title').text(label + ':')
|
||||
.first().text('If:');
|
||||
});
|
||||
if (rule.find('tr.clause,tr.compositeclause').length < 1)
|
||||
{
|
||||
rule.find('tr.action th.title').text('Always:');
|
||||
rule.find('tr.otherwise').hide();
|
||||
rule.find('div.criteria,div.arrow').hide();
|
||||
rule.find('tr.otherwise,div.criteria,div.arrow').hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
rule.find('tr.action th.title').text('Then:');
|
||||
rule.find('tr.otherwise').show();
|
||||
rule.find('div.criteria,div.arrow').show();
|
||||
rule.find('tr.otherwise,div.criteria,div.arrow').show();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -172,7 +194,34 @@ function critdesc(cmd, negate)
|
|||
return c.desc;
|
||||
}
|
||||
|
||||
function criterion(data)
|
||||
function composite_criterion(c, data)
|
||||
{
|
||||
s = '<tr class="compositeclause" cmd=' + data.cmd + '>' +
|
||||
'<th class=title>And:</th>' +
|
||||
'<td colspan=3>' +
|
||||
'<table class=compositeclause>' +
|
||||
'<tr><td colspan=4>' +
|
||||
'<a href=# class=addsubcriterion>' +
|
||||
'<img src=img/plus.png height=15 ' +
|
||||
'title="Add condition to sub-clause"></a>' +
|
||||
' ' +
|
||||
'<a class=delsubclause href=# ' +
|
||||
'title="Delete sub-clause and the conditions within it">' +
|
||||
'<img src=/img/context/delete.png></a>' +
|
||||
' ' +
|
||||
c.desc +
|
||||
'</td></tr>';
|
||||
|
||||
$.each(data.criteria, function(key, val) {
|
||||
s += criterion(val, 'comp');
|
||||
});
|
||||
|
||||
s += '</table></td></tr>';
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
function criterion(data, classes)
|
||||
{
|
||||
var c = schema.criterion[data.cmd];
|
||||
var s;
|
||||
|
@ -182,7 +231,12 @@ function criterion(data)
|
|||
alert('Unknown Criterion (' + data.cmd + ')');
|
||||
return;
|
||||
}
|
||||
s = '<tr class=clause><th class=title>And:</th>' +
|
||||
if (c.type == 'composite')
|
||||
return composite_criterion(c, data);
|
||||
|
||||
s = '<tr class="clause';
|
||||
if (classes) s += ' ' + classes;
|
||||
s += '"><th class=title>And:</th>' +
|
||||
'<th class=cmd negate=' + data.negate + ' cmd=' + data.cmd + '>' +
|
||||
critdesc(data.cmd, data.negate) + '</th><td class=val>';
|
||||
|
||||
|
@ -192,10 +246,10 @@ function criterion(data)
|
|||
s += 'UNKNOWN (' + data.arg + ')';
|
||||
|
||||
s += '</td><td>' +
|
||||
'<a class=editclause href=#>' +
|
||||
'<a class=editclause href=# title="Edit condition">' +
|
||||
'<img src=/img/context/edit.png></a>' +
|
||||
' ' +
|
||||
'<a class=delclause href=#>' +
|
||||
'<a class=delclause href=# title="Delete condition">' +
|
||||
'<img src=/img/context/delete.png></a>' +
|
||||
'</td></tr>';
|
||||
return s;
|
||||
|
@ -264,8 +318,12 @@ function addrule(id, data)
|
|||
$.each(data.criteria, function(key, val) {
|
||||
if (val.cmd == 'lock' && (
|
||||
data.action.cmd == 'lock' || data.action.cmd == 'unlock'))
|
||||
{
|
||||
alert('Removed legacy lock/unlock - ' +
|
||||
'check rules before saving.');
|
||||
return;
|
||||
$c.find('tbody').append(criterion(val));
|
||||
}
|
||||
$c.find('tbody:first').append(criterion(val));
|
||||
});
|
||||
$c.find('th.title:first').text('If:');
|
||||
|
||||
|
@ -599,7 +657,7 @@ $('#macros').on('click', '#b_macro', function(e) {
|
|||
|
||||
changed(0);
|
||||
|
||||
function addcriterion(rule)
|
||||
function addcriterion(rule, target)
|
||||
{
|
||||
var type = rule.attr('type');
|
||||
|
||||
|
@ -616,6 +674,7 @@ function addcriterion(rule)
|
|||
);
|
||||
});
|
||||
$('#newcondition_negate').prop('checked', false);
|
||||
$('#newcondition_cmd').trigger('change');
|
||||
|
||||
$('#newcondition').dialog({
|
||||
height: 'auto', width: 'auto',
|
||||
|
@ -624,21 +683,22 @@ function addcriterion(rule)
|
|||
position: {
|
||||
my: 'bottom left',
|
||||
at: 'top right',
|
||||
of: rule
|
||||
of: target
|
||||
},
|
||||
buttons: {
|
||||
"Add Condition": function() {
|
||||
$(this).dialog('close');
|
||||
var id = rule.attr('id');
|
||||
var val = $('#newcondition_cmd').val();
|
||||
var negate = $('#newcondition_negate')
|
||||
.prop('checked') ? '1' : '0';
|
||||
rule.find('table.criteria tbody')
|
||||
.append(criterion({
|
||||
var obj = {
|
||||
cmd: val,
|
||||
negate: negate,
|
||||
arg: schema.criterion[val].def
|
||||
}));
|
||||
arg: schema.criterion[val].def,
|
||||
criteria: []
|
||||
};
|
||||
target.find('tbody:first')
|
||||
.append(criterion(obj));
|
||||
changed(1);
|
||||
rulerefresh(rule);
|
||||
},
|
||||
|
@ -656,7 +716,8 @@ $('#ruleset')
|
|||
})
|
||||
.on('click', 'a.addcriterion', function(e) {
|
||||
e.preventDefault();
|
||||
addcriterion($(this).closest('div.rule'));
|
||||
var rule = $(this).closest('div.rule');
|
||||
addcriterion(rule, rule.find('table.criteria'));
|
||||
})
|
||||
.on('click', 'a.editcomment', function(e) {
|
||||
e.preventDefault();
|
||||
|
@ -827,6 +888,32 @@ $('#ruleset')
|
|||
.html($('#empty_rulebase').html());
|
||||
});
|
||||
});
|
||||
})
|
||||
.on('click', 'a.delsubclause', function(e) {
|
||||
e.preventDefault();
|
||||
$(this).dojConfirmAction({
|
||||
question: 'Delete sub-condition?',
|
||||
yesAnswer: 'Yes',
|
||||
cancelAnswer: 'No'
|
||||
}, function(el) {
|
||||
var rule = $(el).closest('div.rule');
|
||||
$(el).closest('tr.compositeclause')
|
||||
.fadeOut('slow', function() {
|
||||
$(this).remove();
|
||||
rulerefresh(rule);
|
||||
changed(1);
|
||||
});
|
||||
});
|
||||
})
|
||||
.on('click', 'a.addsubcriterion', function(e) {
|
||||
e.preventDefault();
|
||||
var rule = $(this).closest('div.rule');
|
||||
var clause = $(this).closest('table.compositeclause');
|
||||
addcriterion(rule, clause);
|
||||
})
|
||||
.on('dblclick', 'div.raw', function(e) {
|
||||
e.preventDefault();
|
||||
$(this).toggleClass("rawvis");
|
||||
});
|
||||
|
||||
$('#edit_action_act').on('change', function(e) {
|
||||
|
@ -837,7 +924,17 @@ $('#ruleset')
|
|||
$('#edit_action_arg').enable();
|
||||
$('.edit_action_help').hide();
|
||||
$('#edit_action_help_' + schema.action[cmd].argtype).show();
|
||||
})
|
||||
});
|
||||
|
||||
$('#newcondition_cmd').on('change', function(e) {
|
||||
var cmd = $(this).val();
|
||||
if (schema.criterion[cmd].negate)
|
||||
$('#newcondition_negate').enable();
|
||||
else
|
||||
$('#newcondition_negate')
|
||||
.prop('checked', false)
|
||||
.disable();
|
||||
});
|
||||
|
||||
// Set up macros
|
||||
$.each(macros, function(key, val) {
|
||||
|
@ -854,5 +951,7 @@ $('#ruleset')
|
|||
});
|
||||
|
||||
loadrules($('span.dir').text());
|
||||
|
||||
$(document).tooltip();
|
||||
});
|
||||
|
||||
|
|
|
@ -62,6 +62,11 @@ div.raw
|
|||
right: 12px;
|
||||
}
|
||||
|
||||
div.rawvis
|
||||
{
|
||||
background: #ccc;
|
||||
}
|
||||
|
||||
div#buttons
|
||||
{
|
||||
padding-top: 1em;
|
||||
|
@ -107,6 +112,7 @@ span.legendright
|
|||
table
|
||||
{
|
||||
border: 0;
|
||||
line-height: 1em;
|
||||
}
|
||||
|
||||
table th
|
||||
|
|
|
@ -1,50 +1,12 @@
|
|||
#!/mod/bin/jimsh
|
||||
|
||||
source /mod/webif/lib/setup
|
||||
require lock system.class ts.class tdelete pretty_size browse.class \
|
||||
safe_delete settings.class plugin
|
||||
source /mod/webif/plugin/sweeper/harness.jim
|
||||
|
||||
proc log {msg {level 1}} {
|
||||
puts "[\
|
||||
clock format [clock seconds] -format "%d/%m/%Y %H:%M"\
|
||||
] - $msg"
|
||||
if {![llength $argv]} {
|
||||
::sweeper::scan 0
|
||||
} else {
|
||||
scan_run [lindex $argv 0] sweeper ::sweeper::sweep
|
||||
}
|
||||
|
||||
proc elapsed {start} {
|
||||
return $(([clock milliseconds] - $start) / 1000.0)
|
||||
}
|
||||
|
||||
proc startclock {} {
|
||||
set ::startclock_s [clock milliseconds]
|
||||
}
|
||||
|
||||
proc endclock {size} {
|
||||
set el [elapsed $::startclock_s]
|
||||
set rate $($size / $el)
|
||||
return "[pretty_size $size] in $el seconds - [pretty_size $rate]/s"
|
||||
}
|
||||
|
||||
proc register {args} {}
|
||||
|
||||
proc scan_run {dir flag callback} {
|
||||
global dustbin
|
||||
|
||||
if {[string match {\[*} [file tail $dir]]} return
|
||||
|
||||
if {[file exists "$dir/.$flag"]} { $callback $dir }
|
||||
|
||||
foreach entry [readdir -nocomplain $dir] {
|
||||
if {[file isdirectory "$dir/$entry"]} {
|
||||
scan_run "$dir/$entry" $flag $callback
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set root [system mediaroot]
|
||||
|
||||
source auto.hook
|
||||
|
||||
::sweeper::scan 0
|
||||
#::sweeper::apply $::root $::sweeper::cf
|
||||
|
||||
|
||||
|
|
|
@ -1,14 +1,11 @@
|
|||
#!/mod/bin/jimsh
|
||||
|
||||
package require cgi
|
||||
source /mod/webif/lib/setup
|
||||
require lock system.class ts.class tdelete pretty_size browse.class \
|
||||
safe_delete settings.class plugin
|
||||
source /mod/webif/plugin/sweeper/harness.jim
|
||||
|
||||
httpheader
|
||||
|
||||
set dir [cgi_get dir ""]
|
||||
set root [system mediaroot]
|
||||
|
||||
set cf "/tmp/sweepertest.cf"
|
||||
|
||||
|
@ -31,30 +28,6 @@ if {[catch {set fp [open $cf w]} msg]} {
|
|||
$fp puts -nonewline $data
|
||||
close $fp
|
||||
|
||||
proc log {msg {level 1}} {
|
||||
puts $msg
|
||||
}
|
||||
|
||||
proc elapsed {start} {
|
||||
return $(([clock milliseconds] - $start) / 1000.0)
|
||||
}
|
||||
|
||||
proc startclock {} {
|
||||
set ::startclock_s [clock milliseconds]
|
||||
}
|
||||
|
||||
proc endclock {size} {
|
||||
set el [elapsed $::startclock_s]
|
||||
set rate $($size / $el)
|
||||
return "[pretty_size $size] in $el seconds - [pretty_size $rate]/s"
|
||||
}
|
||||
|
||||
proc register {args} {}
|
||||
|
||||
set root [system mediaroot]
|
||||
|
||||
source auto.hook
|
||||
|
||||
set ::sweeper::dryrun 1
|
||||
::sweeper::apply $dir $cf
|
||||
|
||||
|
|
Loading…
Reference in New Issue