2.0.17 - recurse rules

This commit is contained in:
hummypkg 2016-04-29 19:26:07 +00:00
parent cafa786200
commit 1bc30bff86
6 changed files with 218 additions and 113 deletions

View File

@ -1,7 +1,7 @@
Package: sweeper
Priority: optional
Section: misc
Version: 2.0.16
Version: 2.0.17
Architecture: mipsel
Maintainer: af123@hummypkg.org.uk
Depends: webif(>=1.2.5-10)

View File

@ -1,7 +1,6 @@
var select_file_criteria = {};
var select_folder_criteria = {};
var select_global_criteria = {};
$.each(schema.criterion, function(k, v) {
if (v.deprecated)
return;
@ -13,20 +12,15 @@ $.each(schema.criterion, function(k, v) {
case 'folder':
select_folder_criteria[k] = v.desc;
break;
case 'global':
select_global_criteria[k] = v.desc;
break;
case 'all':
select_file_criteria[k] = v.desc;
select_folder_criteria[k] = v.desc;
select_global_criteria[k] = v.desc;
break;
}
});
var select_file_actions = {};
var select_folder_actions = {};
var select_global_actions = {};
$.each(schema.action, function(k, v) {
if (v.deprecated)
return;
@ -38,13 +32,9 @@ $.each(schema.action, function(k, v) {
case 'folder':
select_folder_actions[k] = v.desc;
break;
case 'global':
select_global_actions[k] = v.desc;
break;
case 'all':
select_file_actions[k] = v.desc;
select_folder_actions[k] = v.desc;
select_global_actions[k] = v.desc;
break;
}
});

View File

@ -3,6 +3,7 @@ set ::sweeper::cf "/mod/etc/sweeper.conf"
set ::sweeper::dryrun 0
set ::sweeper::lastruleresult 0
set ::sweeper::stack {}
set ::sweeper::dustbin [system dustbin 1]
proc ::sweeper::unknown {cmd args} {
log "Unknown sweeper rule clause '$cmd'" 0
@ -12,6 +13,12 @@ proc ::sweeper::unknown {cmd args} {
######################################################################
# Utility functions
proc ::sweeper::skipdir {e} {
if {[string match {\[*} [string trimleft $e]]} { return 1 }
if {$e eq $::sweeper::dustbin} { return 1 }
return 0
}
# Perform an integer comparison.
proc ::sweeper::intcomp {ref val} {
lassign $val op num
@ -326,12 +333,10 @@ proc ::sweeper::moveset {ts dst {op rename}} {
# Search for a folder with name 'target' under 'root', skipping 'orig'
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 {\[*} [string trimleft $e]]} continue
if {$e eq $dustbin} continue
if {[::sweeper::skipdir $e]} continue
if {$entry eq $orig} continue
if {$e eq $target} { return $entry }
@ -920,79 +925,15 @@ proc ::sweeper::runrule {ts rule folder} {
return 0
}
proc ::sweeper::apply {dir cf} {
if {[catch {set fp [open $cf r]} msg]} {
log "Error opening sweeper ruleset ($cf), $msg" 0
return
}
set ::sweeper::recalc {}
set rules [split [read $fp] "\n"]
$fp close
set runfolder 0
set nrules 0
foreach rule $rules {
switch -- [lindex $rule 0] {
folder -
global { incr runfolder }
}
if {[string index $rule 0] ne "#" && [llength $rule] > 1} {
incr nrules
}
}
if {!$nrules} return
proc ::sweeper::apply_folder_rules {dir rules} {
log "" 2
log "--- SWEEP SCAN STARTING FOR $dir ($nrules) ---" 2
log " -- FOLDER RULES --" 2
log "" 2
foreach e [readdir -nocomplain $dir] {
set entry "$dir/$e"
if {[file isdirectory $entry]} continue
if {![string match {*.ts} $entry]} continue
log "+ Sweeper processing $entry" 2
if {[catch {set ts [ts fetch $entry]} msg]} {
log "Error reading TS file, $msg" 0
continue
}
if {$ts == "0"} {
log "Invalid TS file." 2
continue
}
if {[$ts inuse]} {
log "Recording in use." 2
continue
}
set ::sweeper::stack {}
foreach rule $rules {
if {[string index $rule 0] eq "#" ||
[llength $rule] < 2} continue
switch -- [lindex $rule 0] {
folder continue
global { set rule [lrange $rule 1 end] }
}
if {[::sweeper::runrule $ts $rule 0]} break
}
}
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 {\[*} [string trimleft $e]]} continue
if {$e eq $dustbin} continue
if {[::sweeper::skipdir $e]} continue
log "" 2
log "==== folder $entry ====" 2
@ -1005,10 +946,10 @@ proc ::sweeper::apply {dir cf} {
set ts 0
foreach de [lsort -command [lambda {a b} {
upvar entry e
return $([file mtime "$e/$b"] - [file mtime "$e/$a"])
}] [lsearch -glob -all -inline \
[readdir -nocomplain $entry] {*.ts}]] {
upvar entry e
return $([file mtime "$e/$b"] - [file mtime "$e/$a"])
}] [lsearch -glob -all -inline \
[readdir -nocomplain $entry] {*.ts}]] {
set dentry "$entry/$de"
log " --- Considering $dentry" 2
@ -1038,17 +979,100 @@ proc ::sweeper::apply {dir cf} {
set ::sweeper::stack {}
foreach rule $rules {
if {[string index $rule 0] eq "#" ||
[llength $rule] < 3} continue
switch -- [lindex $rule 0] {
folder -
global { set rule [lrange $rule 1 end] }
default continue
}
if {[llength $rule] < 1} continue
if {[::sweeper::runrule $ts $rule 1]} break
}
}
}
}
proc ::sweeper::apply_rules {dir rules {depth 0}} {
log "" 2
log "--- SWEEP($depth) STARTING FOR $dir ---" 2
log "" 2
if {$depth > 20} {
log "ERROR: Maximum recursion depth exceeded." 0
return
}
set moredepth 0
set dirs {}
foreach e [readdir -nocomplain $dir] {
set entry "$dir/$e"
if {[file isdirectory $entry]} {
if {![::sweeper::skipdir $e] &&
![file exists "$entry/.nosweep"]} {
lappend dirs $entry
}
continue
}
if {![string match {*.ts} $entry]} continue
log "+ Sweeper processing $entry" 2
if {[catch {set ts [ts fetch $entry]} msg]} {
log "Error reading TS file, $msg" 0
continue
}
if {$ts == "0"} {
log "Invalid TS file." 2
continue
}
if {[$ts inuse]} {
log "Recording in use." 2
continue
}
set ::sweeper::stack {}
foreach rule $rules {
if {[llength $rule] < 3} continue
set rule [lassign $rule level]
if {$level < $depth} continue
if {$level > $depth} { incr moredepth }
if {[::sweeper::runrule $ts $rule 0]} break
}
}
# No rules require greater recursion
if {!$moredepth} return
foreach dir $dirs {
::sweeper::apply_rules $dir $rules $($depth + 1)
}
}
proc ::sweeper::apply {dir cf} {
if {[catch {set fp [open $cf r]} msg]} {
log "Error opening sweeper ruleset ($cf), $msg" 0
return
}
set ::sweeper::recalc {}
set _rules [split [read $fp] "\n"]
$fp close
set rules {}
set folder_rules {}
foreach rule $_rules {
if {[string index $rule 0] eq "#"} continue
switch -- [lindex $rule 0] {
folder { lappend folder_rules [lrange $rule 1 end] }
global { lset rule 0 1; lappend rules $rule }
recurse { lappend rules [lrange $rule 1 end] }
default { lappend rules [linsert $rule 0 0] }
}
}
if {[llength $rules]} {
::sweeper::apply_rules $dir $rules
}
if {[llength $folder_rules]} {
::sweeper::apply_folder_rules $dir $folder_rules
}
foreach dir $::sweeper::recalc {

View File

@ -58,10 +58,10 @@ Add pre-defined ruleset:
<fieldset class=rule>
<legend class=comment>
<span class=commentleft>
<span class="ruleicon folder global hidden">
<span class="ruleicon folder recurse hidden">
<img src=/images/711_1_09_Media_Folder.png>
</span>
<span class="ruleicon file global hidden">
<span class="ruleicon file recurse hidden">
<img src=/img/Video_TS_New.png>
</span>
<span class=comment>Unnamed rule</span>
@ -98,9 +98,9 @@ Add pre-defined ruleset:
<div class="foldercomment hidden">
For each sub-folder, inspect a recording within and:
</div>
<div class="globalcomment hidden">
For each recording and sub-folder, inspect a recording
within and:
<div class="recursecomment hidden">
For each recording and recordings within folders
(<span class=depth></span> deep<a class=editdepth href=#><img src=/img/context/edit.png></a>):
</div>
<a href=# class=addcriterion>
<img src=img/plus.png
@ -151,6 +151,11 @@ For pattern matching, the following special sequences may appear in the pattern:
size=5 maxlength=6 />
</div>
<div class=hidden id=edit_plainint title="Edit int">
<input name=edit_plainint_field id=edit_plainint_field type=number
size=5 maxlength=6 />
</div>
<div class=hidden id=edit_select title="Edit select">
<select name=edit_select_field id=edit_select_field>
</select>
@ -203,11 +208,17 @@ For pattern matching, the following special sequences may appear in the pattern:
value='file' checked />Process Files
<input name=newrule_type id=newrule_type_folder type=radio
value='folder' />Process Folders
<input name=newrule_type id=newrule_type_global type=radio
value='global' />Process Files &amp; Folders
<input name=newrule_type id=newrule_type_recurse type=radio
value='recurse' />Process Files and Files within Folders
<br>
Description:
<input name=newrule_comment id=newrule_comment size=80 maxlength=255 />
<div id=newrule_depth_box class=hidden>
Recursion Depth:
<input name=newrule_depth id=newrule_depth type=number size=5
maxlength=5 />
<span class=footnote>(How many levels deep into the folder structure to look)</span>
</div>
</div>
<div class=hidden id=newcondition title="Add New Condition">

View File

@ -15,8 +15,10 @@ set root [system mediaroot]
if {$dir eq "" || $dir eq $root} {
set dir $root
set cf "/mod/etc/sweeper.conf"
} else {
} elseif {[file isdirectory $dir]} {
set cf "$dir/.sweeper"
} else {
set cf $dir
}
httpheader "application/json"
@ -99,14 +101,22 @@ proc rule {id rule} {
switch -- [lindex $rule 0] {
folder {
set type "folder"
set depth 0
set rule [lrange $rule 1 end]
}
global {
set type "global"
set type "recurse"
set depth 1
set rule [lrange $rule 1 end]
}
recurse {
set type "recurse"
set depth [lindex $rule 1]
set rule [lrange $rule 2 end]
}
default {
set type "file"
set depth 0
}
}
@ -115,6 +125,7 @@ proc rule {id rule} {
add_json " \"raw\": \"[quot $rule]\",\n"
add_json " \"name\": \"[quot $lcomment]\",\n"
add_json " \"type\": \"$type\",\n"
add_json " \"depth\": \"$depth\",\n"
add_json " \"enabled\": \"$enabled\",\n"
add_json " \"criteria\": \[\n"

View File

@ -146,10 +146,11 @@ function ruleconf(rule)
if (rule.hasClass('ruledisabled'))
s += '## ';
if (rule.attr('type') == 'folder')
s += 'folder ';
else if (rule.attr('type') == 'global')
s += 'global ';
else if (rule.attr('depth') > 0)
s += 'recurse ' + rule.attr('depth') + ' ';
s += clauseconf(rule);
@ -203,6 +204,10 @@ function rulerefresh(rule)
rule.find('tr.action th.title').text('Then:');
rule.find('tr.otherwise,div.criteria,div.arrow').show();
}
if (rule.attr('type') == 'recurse')
rule.find('.recursecomment .depth').text(rule.attr('depth') +
' level' + (rule.attr('depth') == 1 ? '' : 's'));
}
function critdesc(cmd, negate)
@ -335,12 +340,22 @@ function addrule(id, data)
.addClass('rule')
.removeClass('hidden');
if (!data.depth)
data.depth = 0;
if (data.type == 'global')
{
data.type = 'recurse';
data.depth = 1;
}
rule.find('span.comment').html(data.name);
switch (data.type)
{
case 'global':
rule.find('.commentleft > span.global').show();
rule.find('.globalcomment').show();
case 'recurse':
rule.find('.commentleft > span.recurse').show();
rule.find('.recursecomment').show()
.find('.depth').text(data.depth + ' level' +
(data.depth == 1 ? '' : 's'));
break;
case 'folder':
rule.find('.commentleft > span.folder').show();
@ -351,6 +366,7 @@ function addrule(id, data)
break;
}
rule.attr('type', data.type);
rule.attr('depth', data.depth);
var $c = rule.find('table.criteria');
$.each(data.criteria, function(key, val) {
@ -451,6 +467,39 @@ function edit_int(obj, title, op, val, callback)
});
}
function edit_plainint(obj, title, val, callback)
{
$('#edit_plainint_field').val(val);
$('#edit_plainint').dialog({
title: title,
height: 'auto', width: 'auto',
draggable: true, resizable: false,
autoOpen: true,
position: {
my: 'bottom left',
at: 'top right',
of: obj,
collision: 'fit'
},
buttons: {
"Save": function() {
var val = $.trim($('#edit_plainint_field')
.val());
if (!val)
alert("Bad value");
else
{
callback(obj, val);
$(this).dialog('close');
}
},
"Close": function() {
$(this).dialog('close');
}
}
});
}
function edit_select(obj, title, options, val, callback)
{
$('#edit_select_field').empty();
@ -718,6 +767,7 @@ $('#b_add').button({icons: {primary: "ui-icon-plus"}})
name: $('#newrule_comment').val(),
type: $('input[name=newrule_type]' +
':checked').val(),
depth: $('#newrule_depth').val(),
criteria: [],
action: {
cmd: 'continue',
@ -733,9 +783,18 @@ $('#b_add').button({icons: {primary: "ui-icon-plus"}})
}
});
$('#newrule_type_file').prop('checked', true);
$('#newrule_depth').val(1);
$('#newrule_depth_box').hide();
$('#newrule_comment').focus().val('').val('Unnamed rule').select();
});
$('input[name=newrule_type]').on('change', function() {
if ($('input[name=newrule_type]:checked').val() == 'recurse')
$('#newrule_depth_box').show();
else
$('#newrule_depth_box').hide();
});
$('#b_edit').button({icons: {primary: "ui-icon-script"}});
$('#buttons')
.on('click', '#b_edit', function(e) {
@ -894,9 +953,6 @@ function addcriterion(rule, target)
case 'folder':
options = select_folder_criteria;
break;
case 'global':
options = select_global_criteria;
break;
default:
options = select_file_criteria;
break;
@ -965,6 +1021,22 @@ $('#ruleset')
changed(1);
});
})
.on('click', 'a.editdepth', function(e) {
e.preventDefault();
var rule = $(this).closest('div.rule');
edit_plainint($(this), 'Edit recursion depth',
rule.attr('depth'),
function(obj, val) {
if (val > 0 && val < 16)
{
rule.attr('depth', val);
if (val > 1)
rule.attr('type', 'recurse');
rulerefresh(rule);
changed(1);
}
});
})
.on('click', 'a.uprule', function(e) {
e.preventDefault();
if ($(this).hasClass('ui-state-disabled'))
@ -1039,9 +1111,6 @@ $('#ruleset')
case 'folder':
options = select_folder_actions;
break;
case 'global':
options = select_global_actions;
break;
default:
options = select_file_actions;
break;