checkpoint sweeper

This commit is contained in:
hummypkg 2014-06-01 23:35:24 +00:00
parent 17ed75c684
commit 047bdc208f
12 changed files with 387 additions and 174 deletions

View File

@ -1,7 +1,7 @@
#!/bin/sh
for f in webif/plugin/sweeper/; do
rsync -avr humax:/mod/$f ./$f
rsync -avr --delete --exclude=.svn humax:/mod/$f ./$f
done

View File

@ -6,6 +6,9 @@ proc ::sweeper::unknown {cmd args} {
return 0
}
######################################################################
# Helper functions
proc ::sweeper::expand {ts str} {
if {[string first "%" $str] == -1} {
return $str
@ -140,6 +143,8 @@ proc ::sweeper::action {ts cmds} {
log "ACTION: $cmd\($rest)" 2
switch $cmd {
continue { return 0 }
stop { return 1 }
preserve { return 1 }
move -
movecreate {
@ -241,6 +246,8 @@ proc ::sweeper::folder_action {ts cmds} {
log "FOLDER ACTION: $cmd\($rest) @\[$folder]" 2
switch $cmd {
continue { return 0 }
stop { return 1 }
preserve { return 1 }
movecreate -
move {

View File

@ -3,7 +3,6 @@
package require cgi
source /mod/webif/lib/setup
require system.class
source helper
set dir [cgi_get dir ""]
@ -14,99 +13,38 @@ if {$dir eq ""} {
set cf "[system mediaroot]/$dir/.rulelist"
}
jscss {schema.js script.js} style.css
header
# Load rules
if {![file exists $cf]} {
set rules {}
} else {
if {[catch {set fp [open $cf r]} msg]} {
log "Error opening sweeper ruleset ($cf), $msg" 0
exit
}
set rules [split [$fp read] "\n"]
}
jscss script.js style.css
puts "
<fieldset width=100%>
<legend>Sweeper rules for $dir</legend>
<h3>
<img src=img/icon22.png> Sweeper rules for
<span class=dir>$dir</span>
</h3>
<div id=ruleset> </div>
"
set lcomment ""
proc comment {id comment} {
set ::lcomment $comment
}
proc rule {id rule} {
global clausedescr lcomment
if {$lcomment eq ""} { set lcomment "Unnamed rule" }
puts "<div id=\"rule_${id}\"><fieldset width=100%><legend>"
puts "<div id=\"comment_${id}\" class=comment>$lcomment"
puts "<img class=editbutton src=/img/context/edit.png></div>"
puts "<div id=\"comment_${id}_edit\" class=\"commentedit edit hidden\">
<input id=\"${id}_comment\" name=\"${id}_comment\"
value=\"$lcomment\" size=120 maxlength=255></div>"
set lcomment ""
puts "</legend><table class=\"keyval cleft\">"
set c 0
while {[llength $rule] > 1} {
incr c
set rule [lassign $rule cmd arg]
if {$cmd eq "action"} break
if {[dict exists $clausedescr $cmd]} {
set title $clausedescr($cmd)
} else {
set title [string totitle $cmd]
}
puts "<tr><th nowrap>$title</th><td>"
puts "<div id=\"rule_${id}_${c}\">"
set broken 0
if {[catch {::display::$cmd $id $arg}]} {
puts "<i>$arg</i>"
set broken 1
}
if {!$broken} {
puts "<img class=editbutton src=/img/context/edit.png>"
puts "</div>"
puts "<div id=\"rule_${id}_${c}_edit\"
class=\"clauseedit edit\" hidden>"
::edit::$cmd "rule_${id}_${c}" $arg
}
puts "</div>"
puts "</td></tr>"
}
puts "</table><table class=\"keyval left padleft\">
<tr><th>Action</th><td>"
puts $arg
puts "</td></tr></table>"
puts "</fieldset></div>"
}
set n 0
foreach rule $rules {
incr n
if {[string index $rule 0] eq "#"} {
if {[string index $rule 1] ne "#"} {
comment $n [string range $rule 1 end]
}
continue
}
if {[llength $rule] < 2} continue
rule $n $rule
}
puts "
</table>
puts {
<div id=rule_template class="rule hidden">
<fieldset class=rule>
<legend class=comment>
<span class=comment>Unnamed rule</span>
<img class=edit src=/img/context/edit.png>
</legend>
<div class=criteria>
<table class="criteria keyval"><tbody>
<tr><th colspan=3 class=title>If all of:</th></tr>
</tbody></table>
</div>
<div class=action>
<table class="action keyval"><tbody>
<tr><th colspan=2 class=title>Then:</th></tr>
</tbody></table>
</div>
<div class="raw cleft"></div>
</fieldset>
"
</div>
}
footer

View File

@ -1,60 +0,0 @@
proc ::edit::unknown {cmd args} {
puts "Unhandled clause, $cmd"
}
proc ::display::unknown {cmd args} {
puts "Unhandled clause, $cmd"
}
proc ::display::int {id val} {
lassign $val op num
if {$num eq ""} {
set num $op
set op "=="
}
puts [cgi_quote_html "$op $num"]
}
proc ::edit::int {id val} {
lassign $val op num
if {$num eq ""} {
set num $op
set op "=="
}
puts "<select id=op_$id name=op_$id>"
foreach pop {== > < >= <=} {
set qpop [cgi_quote_html $pop]
puts -nonewline "<option value=\"$qpop\""
if {$op eq $pop} { puts -nonewline " selected" }
puts ">$qpop"
}
puts "</select>"
puts "<input name=\"num_$id\" type=number min=1 size=10 maxlength=10
value=\"$num\">"
}
proc ::display::substr {id val} {
puts "contains '$val'"
}
proc ::edit::substr {id val} {
puts "<input name=\"str_$id\" type=text min=1
size=40 maxlength=80 value=\"$val\">"
}
set clausedescr {}
proc clause {id handler descr} {
set ::clausedescr($id) $descr
alias ::display::$id ::display::$handler
alias ::edit::$id ::edit::$handler
}
source schema.def

Binary file not shown.

After

Width:  |  Height:  |  Size: 612 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 953 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

View File

@ -0,0 +1,108 @@
#!/mod/bin/jimsh
package require cgi
source /mod/webif/lib/setup
require system.class
set dir [cgi_get dir ""]
set root [system mediaroot]
if {$dir eq "" || $dir eq $root} {
set dir $root
set cf "/mod/etc/sweeper.conf"
} else {
set cf "[system mediaroot]/$dir/.sweeper"
}
httpheader "application/json"
# Load rules
if {![file exists $cf]} {
set rules {}
} else {
if {[catch {set fp [open $cf r]} msg]} {
log "Error opening sweeper ruleset ($cf), $msg" 0
exit
}
set rules [split [$fp read] "\n"]
}
set lcomment ""
proc comment {id comment} {
set ::lcomment [string trim $comment]
}
set json ""
proc add_json {str} {
global json
append json $str
}
proc quot {str} {
return [cgi_quote_html $str]
}
proc rule {id rule} {
global clausedescr lcomment
if {$lcomment eq ""} { set lcomment "Unnamed rule" }
if {[lindex $rule 0] eq "folder"} {
set type "folder"
set rule [lrange $rule 1 end]
} else {
set type "file"
}
if {$id > 1} { add_json ",\n" }
add_json " {\n"
add_json " \"raw\": \"[quot $rule]\",\n"
add_json " \"name\": \"[quot $lcomment]\",\n"
add_json " \"type\": \"$type\",\n"
add_json " \"criteria\": \[\n"
set lcomment ""
set c 0
while {[llength $rule] > 1} {
set rule [lassign $rule cmd arg]
if {$cmd eq "action"} break
if {$c} { add_json ",\n" }
incr c
add_json " {\n"
add_json " \"cmd\": \"[quot $cmd]\",\n"
add_json " \"arg\": \"[quot $arg]\"\n"
add_json " }"
}
add_json "\n"
if {$cmd ne "action"} { set arg "continue" }
lassign $arg cmd arg
if {$cmd eq "preserve"} { set cmd 'stop' }
add_json " ],\n"
add_json " \"action\": {\n"
add_json " \"cmd\": \"[quot $cmd]\",\n"
add_json " \"arg\": \"[quot $arg]\"\n"
add_json " }\n"
add_json " }"
}
add_json "\[\n"
set n 0
foreach rule $rules {
if {[string index $rule 0] eq "#"} {
if {[string index $rule 1] ne "#"} {
comment $n [string range $rule 1 end]
}
continue
}
if {[llength $rule] < 2} continue
incr n
rule $n $rule
}
add_json "\n]\n"
puts $json

View File

@ -1,14 +0,0 @@
clause lcn int "Channel Number"
clause duration int "Recording duration (in minutes)"
clause schedduration int "Scheduled duration (in minutes)"
clause size int "Recording size (in bytes)"
#clause definition \
# {select {{SD "Standard Definition"} {HD "High Definition"}} \
# "Recording definition"
clause title substr "Part of the recording title"
clause synopsis substr "Part of the synopsis"
clause guidance substr "Part of the guidance text"
#clause flag tsflag "Recording flag"
#clause genre tsgenre "Recording genre"
#action preserve 0 "Leave recording alone"
#action move folderpicker "Move recording to..."

View File

@ -0,0 +1,122 @@
var schema = {
criterion: {
lcn: {
type: 'int',
desc: 'Channel Number'
},
duration: {
type: 'int',
desc: 'Recording duration (in minutes)'
},
schedduration: {
type: 'int',
desc: 'Scheduled duration (in minutes)'
},
size: {
type: 'int',
desc: 'Recording size (in bytes)'
},
hour: {
type: 'int',
desc: 'Hour in which the recording started'
},
age: {
type: 'int',
desc: 'Age (in hours)'
},
wage: {
type: 'int',
desc: 'Time since last watched, or recorded (in hours)'
},
title: {
type: 'substr',
desc: 'Part of the recording title'
},
synopsis: {
type: 'substr',
desc: 'Part of the synopsis'
},
guidance: {
type: 'substr',
desc: 'Part of the guidance text'
},
genre: {
type: 'select',
desc: 'Recording genre',
select: {
Unclassified: 'Unclassified',
Film: 'Film',
Children: 'Children',
'News & Factual': 'News & Factual',
Entertainment: 'Entertainment',
Sport: 'Sport',
Education: 'Education',
Lifestyle: 'Lifestyle',
Drama: 'Drama'
}
},
definition: {
type: 'select',
desc: 'Recording definition',
select: {
SD: 'Standard Definition',
HD: 'High Definition'
}
},
flag: {
type: 'select',
desc: 'Recording flag',
select: {
Locked: 'Locked',
New: 'New',
Encrypted: 'Encrypted',
Guidance: 'Guidance',
ODEncrypted: 'Encrypted On-Disk',
Shrunk: 'Shrunk',
Deduped: 'De-duplicated'
}
},
lock: {
type: 'select',
desc: 'Change recording lock',
select: {
1: 'Lock Recording',
0: 'Unlock Recording'
}
}
},
action: {
continue: {
class: 'all',
argtype: 'none',
desc: 'Continue to next rule'
},
stop: {
class: 'all',
argtype: 'none',
desc: 'Do nothing and stop processing rules'
},
move: {
class: 'all',
argtype: 'folder',
desc: 'Move recording to folder...'
},
movecreate: {
class: 'all',
argtype: 'folder',
desc: 'Move recording to folder (create folder if necessary)'
},
fileunder: {
class: 'folder',
argtype: 'folder',
desc: 'Scan for folder of same name and merge'
},
fileundercreate: {
class: 'folder',
argtype: 'folder',
desc: 'Scan for folder of same name and merge ' +
'(create folder if necessary)'
}
}
};

View File

@ -1,18 +1,99 @@
var printers = {
int: function(cmd, a) {
var b = a.split(" ");
if (b.length == 1)
{
op = '=';
val = a;
}
else
{
op = b[0];
val = b[1];
}
return op + ' ' + val;
},
substr: function(cmd, a) {
return a;
},
select: function(cmd, a) {
return schema.criterion[cmd].select[a];
}
};
function criterion(data)
{
var c = schema.criterion[data.cmd];
var s;
s = '<tr><th>' + c.desc + '</th><td>';
if (printers[c.type])
s += printers[c.type](data.cmd, data.arg);
else
s += 'RAW (' + data.arg + ')';
s += '</td><td>' +
'<img class=edit src=/img/context/edit.png>' +
'&nbsp;' +
'<img class=delete src=/img/context/delete.png>' +
'</td></tr>';
return s;
}
function action(data)
{
var c = schema.action[data.cmd];
var s;
s = '<tr>' +
'<th>' + c.desc + '</th>' +
'<td>' + data.arg + '</td>' +
'</tr>';
return s;
}
function addrule(id, data)
{
var rule = $('#rule_template')
.clone()
.attr('id', 'rule_' + id)
.removeClass('hidden');
rule.find('span.comment').text(data.name);
var $c = rule.find('table.criteria');
$.each(data.criteria, function(key, val) {
$($c).find('tbody').append(criterion(val));
});
var $a = rule.find('table.action');
$($a).find('tbody').append(action(data.action));
rule.find('.raw').html(data.raw);
// rule.find('.raw').append('<pre>' + JSON.stringify(data) + '</pre>');
$('#ruleset').append(rule);
}
function loadrules(dir)
{
$('#ruleset')
.html('<img src=/img/loading.gif> Loading rules...');
$.getJSON('rules_json.jim', 'dir=' + dir, function(data) {
$('#ruleset').empty();
$.each(data, function(key, val) {
addrule(key, val);
});
});
}
$(function() {
$('img.editbutton').hover(
function() { $(this).css('cursor', 'pointer'); },
function() { $(this).css('cursor', 'auto'); }
).on('click', function(e) {
e.preventDefault();
var id = $(this).parent().attr('id');
console.log('%O', id);
$('.edit').hide('fast');
$('#' + id + '_edit').show('slow');
});;
loadrules($('span.dir').text());
});

View File

@ -1,4 +1,35 @@
fieldset
{
width: 95%;
}
div.action
{
padding-left: 1em;
float: left;
}
div.criteria
{
clear: left;
float: left;
}
div.raw
{
font-style: italic;
color: #ff4000;
background: transparent;
}
th.title
{
line-height: 1em;
text-align: left !important;
background: #eee !important;
}
div.comment
{
font-style: italic;