beta 1.3.4

git-svn-id: file:///root/webif/svn/pkg/webif/trunk@3431 2a923420-c742-0410-a762-8d5b09965624
This commit is contained in:
hummypkg 2016-12-17 23:33:14 +00:00
parent ddeab2831e
commit d1ccf7b2d1
26 changed files with 863 additions and 48 deletions

View File

@ -1,7 +1,7 @@
Package: webif
Priority: optional
Section: web
Version: 1.3.3-3
Version: 1.3.4
Architecture: mipsel
Maintainer: af123@hpkg.tv
Depends: tcpfix,webif-channelicons(>=1.1.24),lighttpd(>=1.4.39-1),jim(>=0.77),jim-oo(>=0.77),jim-sqlite3(>=0.76),jim-cgi(>=0.7-1),jim-binary(>=0.76),service-control(>=2.3),busybox(>=1.20.2-1),lsof(>=4.87),epg(>=1.2.3),hmt(>=2.0.10),ssmtp,cron-daemon(>=1.18.3-3),at(>=3.1.18),anacron,trm(>=1.1),openssl-command,nicesplice,id3v2,file,rsvsync(>=1.1.9),webif-charts(>=1.2-1),stripts(>=1.2.5-3),tmenu(>=1.08),ffmpeg,id3v2,multienv(>=1.6),tcpping(>=1.1),e2fsprogs,wireless-tools(>=29-1),dbupdate,recmon(>=2.0.7),hwctl,nugget(>=0.95),sqlite3(>=3.15.1)

View File

@ -6,6 +6,7 @@ export TZ=GMT+0BST,M3.5.0/1,M10.5.0/2
case "$1" in
start)
/mod/webif/lib/bin/update_queue
/mod/webif/lib/bin/manage_logs
plog activity "System booted (`lbr_descr`)."
;;

View File

@ -376,6 +376,26 @@ Please wait...
<div id=bmpdialogue title="Recording Thumbnail" class=hidden>
<img id=thmbmp class=doublebmp src="about:blank">
</div>
}
set queueactions(decrypt) "Decryption"
set queueactions(shrink) "Shrink"
set queueactions(mp3) "Audio-Extraction"
set queueactions(mpg) "Conversion to MPG"
eval_plugins queueactions
puts {
<div id=selectoverlay title="Selected files" class=hidden>
<button id=so_delete>Delete</button>
<button id=so_queue>Queue for</button>
<select id=so_queueactions>
}
foreach {k v} $queueactions {
puts "<option value=$k>$v</option>"
}
puts {
</select>
<button id=so_dequeue>De-queue</button>
</div>
}

29
webif/html/browse/dequeue.jim Executable file
View File

@ -0,0 +1,29 @@
#!/mod/bin/jimsh
package require cgi
source /mod/webif/lib/setup
require ts.class queue.class
httpheader
set dir [cgi_get dir]
puts "<div id=deleting class=blood><img src=/img/loading.gif>De-queuing...</div>"
puts "<ul style=\"list-style-type: square\">"
foreach file [cgi_get files] {
puts -nonewline "<li>\"$file\"..."
if {[string first "$dir/" $file] != 0} {
puts "Error - outside directory."
continue
}
set ts [ts fetch $file]
if {$ts eq "0"} continue
queue delete $ts
puts "</li>"
}
puts "</ul>"

View File

@ -3,7 +3,7 @@
package require cgi
source /mod/webif/lib/setup
require ts.class pretty_size system.class settings.class escape browse.class \
plugin epg.class classdump
plugin epg.class classdump queue.class
set mroot [system mediaroot]
set dir [cgi_get dir $mroot]
@ -216,6 +216,12 @@ proc entry {file} {{i 0}} {
set dlna 1
}
# Queued
set queued [queue status $ts]
if {$queued ne ""} {
icon "/img/queueps.png" "Queued for $queued"
}
# Opt+ button
puts "
@ -373,6 +379,9 @@ if {$nicesplice} {
puts { <button id=join>Join</button> }
}
# Queue
puts { <button id=queue>View Queue</button> }
# De-duplicate
puts {

34
webif/html/browse/queue.jim Executable file
View File

@ -0,0 +1,34 @@
#!/mod/bin/jimsh
package require cgi
source /mod/webif/lib/setup
require ts.class queue.class
httpheader
set dir [cgi_get dir]
set act [cgi_get act -]
if {$act eq "-"} {
puts "No action."
exit;
}
puts "<div id=deleting class=blood><img src=/img/loading.gif>Queuing...</div>"
puts "<ul style=\"list-style-type: square\">"
foreach file [cgi_get files] {
puts -nonewline "<li>\"$file\"..."
if {[string first "$dir/" $file] != 0} {
puts "Error - outside directory."
continue
}
set ts [ts fetch $file]
if {$ts eq "0"} continue
queue insert $ts $act
puts "</li>"
}
puts "</ul>"

View File

@ -880,6 +880,14 @@ $('#bmpdialogue').dialog({
close: function() { $('#thmbmp').attr('src', 'about:blank'); }
});
// Selection overlay
$seloverlay = $('#selectoverlay').dialog({
modal: false, autoOpen: false,
height: 85, width: 460,
show: 'fade', hide: 'fade',
draggable: true, resizable: false
});
// Create re-usable confirmation dialogue.
$confirm = $('#confirm').dialog({
modal: true, autoOpen: false,
@ -926,6 +934,10 @@ $('#dedup').button().click(function() {
+ encodeURIComponent(dir);
});
$('#queue').button().click(function() {
window.location = '/diag/queue/';
});
$('#save_stream').button().click(function() {
$('#savestream_retrieving').show();
$('#savestream_detail').text('').hide();
@ -1058,8 +1070,129 @@ $('input.fs').change(function() {
else
$('#join').disable();
if (num > 0)
{
$seloverlay
.dialog('option', 'position', {
my: "left top",
at: "right bottom",
of: this
})
.dialog('option', 'title', 'Selected files: ' + num)
.dialog('open')
.find('span.selcount').text(num);
}
else
{
$seloverlay.dialog('close');
}
});
$('#so_delete').button()
.click(function() {
var files = new Array();
var els = $('input.fs:checked + a').each(function() {
files.push(decodeURIComponent($(this).attr('file')));
});
//console.log("%o", files);
var str = 'Are you sure you want to delete ' + files.length +
' file';
if (files.length != 1) str += 's';
str += '?';
if (confirm(str))
{
disableall();
$('#deletewait').slideDown('slow');
$('#pwdialogue').dialog({
title: "Deleting",
modal: true, autoOpen: true,
height: 'auto', width: 'auto',
show: 'scale', hide: 'fade',
draggable: false, resizable: false,
closeOnEscape: false,
open: function() {
$('.ui-dialog-titlebar-close').hide();
}
});
$('#pwfeedback').load(
'/browse/delete.jim', {
'dir': dir,
'files': files
}, function() {
$('#pwdialogue').dialog('close');
blockpage();
window.location.reload(true);
});
}
});
$('#so_queue').button()
.click(function() {
var files = new Array();
var els = $('input.fs:checked + a').each(function() {
files.push(decodeURIComponent($(this).attr('file')));
});
disableall();
$('#pwdialogue').dialog({
title: "Queuing",
modal: true, autoOpen: true,
height: 'auto', width: 'auto',
show: 'scale', hide: 'fade',
draggable: false, resizable: false,
closeOnEscape: false,
open: function() {
$('.ui-dialog-titlebar-close').hide();
}
});
$('#pwfeedback').load(
'/browse/queue.jim', {
'dir': dir,
'files': files,
'act': $('#so_queueactions').val()
}, function() {
$('#pwdialogue').dialog('close');
blockpage();
window.location.reload(true);
});
});
$('#so_dequeue').button()
.click(function() {
var files = new Array();
var els = $('input.fs:checked + a').each(function() {
files.push(decodeURIComponent($(this).attr('file')));
});
disableall();
$('#pwdialogue').dialog({
title: "De-queuing",
modal: true, autoOpen: true,
height: 'auto', width: 'auto',
show: 'scale', hide: 'fade',
draggable: false, resizable: false,
closeOnEscape: false,
open: function() {
$('.ui-dialog-titlebar-close').hide();
}
});
$('#pwfeedback').load(
'/browse/dequeue.jim', {
'dir': dir,
'files': files
}, function() {
$('#pwdialogue').dialog('close');
blockpage();
window.location.reload(true);
});
});
var streamsize = 0;
function checkstream()

View File

@ -105,6 +105,7 @@ util "shredder" "rma" "RMA" "#" "<br><span id=rmaresult></span>"
util "bluering" "reboot" "Reboot System" "/restart/"
util "maint" "maint" "Maintenance Mode" "#" "<br><span id=maintresult></span>"
util "queuep" "queue" "Queued Tasks" "/diag/queue/"
eval_plugins diag

View File

@ -0,0 +1,14 @@
#!/mod/bin/jimsh
package require cgi
source /mod/webif/lib/setup
require queue.class
httpheader
set slots [cgi_get slot 0]
foreach slot [split $slots ","] {
queue delete_by_id $slot
}

68
webif/html/diag/queue/index.jim Executable file
View File

@ -0,0 +1,68 @@
#!/mod/bin/jimsh
package require cgi
source /mod/webif/lib/setup
require altrow ts.class queue.class
jqplugin tablesorter2 enadis blockui confirmAction
jscss script.js style.css
header
puts {
<h3 class=va>
<img class=va width=100 src=/img/queuep.png>
Queued Tasks
</h3>
<fieldset class=cleft>
<legend>Queued Tasks</legend>
<table class=borders cellpadding=5>
<thead>
<tr>
<th nowrap>ID<input type=checkbox id=selall></th>
<th>Submitted</th>
<th>File</th>
<th>Action</th>
<th>Status</th>
<th>Log</th>
</tr>
</thead>
<tbody>
}
foreach q [queue all] {
set name [string map {
"/mnt/hd2/My Video/" ""
"/media/drive1/Video/" ""
"/media/" ""
".ts" ""
} [$q get file]]
puts "
<tr>
<td><input type=checkbox class=qid value=[$q get id]>
[$q get id]
</td>
<td>[clock format [$q get dat] -format {%c}]</td>
<td>$name</td>
<td>[$q get action]</td>
<td class=\"status [$q get status]\">[$q get status]"
if {[$q get status] eq "RUNNING"} {
puts "<img src=/img/loading.gif>"
}
puts "</td>
<td>[$q get log]</td>
</tr>
"
}
puts {
</tbody>
</table>
<button id=qdelete>Delete Selected</button>
<button id=refresh>Refresh Page</button>
</fieldset>
}
footer

View File

@ -0,0 +1,75 @@
function page_refresh(msg)
{
if (!msg)
msg = 'Refreshing page...';
$.blockUI({
message: '<h1><img src=/img/loading.gif> ' + msg + '</h1>'
});
window.location.reload(true);
}
$(function() {
$('table')
.tablesorter({
sortList: [[0,1]],
theme: 'webif',
widthFixed: false,
widgets: ['zebra', 'stickyHeaders']
});
$('input.qid:checkbox').prop('checked', false).enable();
$('tr').each(function() {
var status = $(this).find('td.status').text();
if (status == 'RUNNING')
$(this).find('input.qid:checkbox').disable();
});
$('input.qid:checkbox').on('change', function() {
var num = $('input.qid:checked').size();
if (num)
$('#qdelete').enable();
else
$('#qdelete').disable();
}).first().trigger('change');
$('#qdelete').button({icons:{primary:"ui-icon-trash"}})
.on('click', function() {
$(this).dojConfirmAction({
question: 'Delete selected?',
yesAnswer: 'Yes',
cancelAnswer: 'No'
}, function(el) {
$.blockUI({
message: '<h1><img src=/img/loading.gif> Deleting... </h1>'
});
var slots = $('input.qid:checked').map(function() {
return this.value;
}).get();
$.get('delete.jim', {
slot: slots.join(',')
}, function() {
page_refresh();
});
});
});
$('#refresh').button({icons:{primary:"ui-icon-refresh"}})
.on('click', function() {
page_refresh();
});
$('#selall').on('change', function() {
$('input.qid:checkbox').prop('checked', $(this).prop('checked'));
});
setInterval(function() { page_refresh() }, 60000);
});

View File

@ -0,0 +1,28 @@
td.status
{
font-style: italic;
}
td
{
white-space: nowrap;
}
td.status.RUNNING
{
color: red;
}
td.status.COMPLETE
{
color: green;
font-weight: bold;
}
td.status.INTERRUPTED
{
color: #ffa500;
font-weight: bold;
}

BIN
webif/html/img/queue.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

BIN
webif/html/img/queuep.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

BIN
webif/html/img/queueps.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 933 B

View File

@ -0,0 +1,15 @@
set autolog [$settings autolog]
set noautorec [$settings noautorec]
set noautorecimm [$settings noautorecimm]
set autorecperiod [$settings autorecperiod]
if {$autorecperiod == 0} { set autorecperiod 10 }
set noautohours [$settings noautohours]
handle_int_update autolog $autolog "Auto-processing log level"
handle_int_update noautorec $noautorec "Auto-processing during recording"
handle_int_update noautorecimm $noautorecimm "Auto-processing before recording"
handle_int_update autorecperiod $autorecperiod \
"Auto-processing recording wait period"
handle_str_update noautohours $noautohours "Auto processing hours" ascii

View File

@ -0,0 +1,79 @@
######################################################################
# Auto-Processing Settings
puts "
<h4>Auto-Processing Settings</h4>
<div><fieldset style=\"display: inline\">
<legend>
Auto-Processing Settings
</legend>
<table>
"
puts -nonewline "
<tr>
<form class=auto id=autolog method=get action=$env(SCRIPT_NAME)>
<th class=key>Auto-processing log level</th>
<td><select id=autolog name=autolog
class=\"text ui-widget-content ui-corner-all\">
"
puts "<option value=0"
if {$autolog == 0} { puts " selected" }
puts ">Actions and errors only\n"
puts "<option value=1"
if {$autolog == 1} { puts " selected" }
puts ">Actions, errors and scan information\n"
puts "<option value=2"
if {$autolog == 2} { puts " selected" }
puts ">Debugging information\n"
puts "
</select>
<small>
<input name=autolog value=\"set\" type=submit>
</small>
<div id=autolog_output></div>
</td>
</form>
</tr>
"
setting_toggle "Suspend automatic processing whilst recording?" \
"noautorec" $noautorec
setting_toggle "Suspend automatic processing if will record soon?" \
"noautorecimm" $noautorecimm
setting_number autorecperiod "...how many minutes is soon?" $autorecperiod
puts -nonewline "
<tr>
<form class=auto id=noautohours method=get action=$env(SCRIPT_NAME)>
<th class=key>Suspend automatic processing during:
<div class=blood>
Use Shift and Control to select multiple entries.
</div>
</th>
<td><select name=\"noautohours\[]\"
multiple size=8
class=\"text ui-widget-content ui-corner-all\">
"
loop h 0 23 {
puts -nonewline "<option value=$h"
if {$h in $noautohours} { puts -nonewline " selected" }
puts ">[format "%02d:00 - %02d:59" $h $h]</option>"
}
puts "
</select>
<small>
<input name=noautohours value=\"set\" type=submit>
</small>
<div id=noautohours_output></div>
</td>
</form>
</tr>
"
puts "
</table></fieldset></div>
"

View File

@ -7,7 +7,6 @@ set notwitfeed [$settings notwitfeed]
set nounwatchedcount [$settings nounwatchedcount]
set hidevisualota [$settings hidevisualota]
set chanchangenc [$settings chanchangenc]
set autolog [$settings autolog]
set audiomp3 [$settings audiomp3]
handle_str_update hostname $hostname Hostname
@ -19,6 +18,5 @@ handle_int_update nounwatchedcount $nounwatchedcount "Disable unwatched count"
handle_int_update hidevisualota $hidevisualota "Hide OTA from visual view"
handle_int_update chanchangenc $chanchangenc \
"Disable channel change confirmation"
handle_int_update autolog $autolog "Auto-processing log level"
handle_int_update audiomp3 $audiomp3 "MP3 type"

View File

@ -38,33 +38,6 @@ if {[system pkginst ir]} {
"chanchangenc" $chanchangenc 0
}
puts -nonewline "
<tr>
<form class=auto id=autolog method=get action=$env(SCRIPT_NAME)>
<th class=key>Auto-processing log level</th>
<td><select id=autolog name=autolog
class=\"text ui-widget-content ui-corner-all\">
"
puts "<option value=0"
if {$autolog == 0} { puts " selected" }
puts ">Actions and errors only\n"
puts "<option value=1"
if {$autolog == 1} { puts " selected" }
puts ">Actions, errors and scan information\n"
puts "<option value=2"
if {$autolog == 2} { puts " selected" }
puts ">Debugging information\n"
puts "
</select>
<small>
<input name=autolog value=\"set\" type=submit>
</small>
<div id=autolog_output></div>
</td>
</form>
</tr>
"
puts -nonewline "
<tr>
<form class=auto id=audiomp3 method=get action=$env(SCRIPT_NAME)>

View File

@ -8,6 +8,8 @@ cgi_input
httpheader
set modules {general auto tvdb web epg network advanced}
set settings [settings new]
if {![dict exists $env SCRIPT_NAME]} { set env(SCRIPT_NAME) "" }
@ -44,7 +46,7 @@ proc handle_str_update {var old {text "Value"} {class alnum} {trim 1}} {
# Settings Modules
set moddir /mod/webif/html/settings/modules
foreach mod {general tvdb web epg network advanced} {
foreach mod $modules {
if {[file exists "$moddir/$mod/.disabled"]} continue
if {[catch {source "$moddir/$mod/init.hook"} msg]} {
puts "ERROR: $msg"
@ -84,10 +86,29 @@ proc setting_toggle {name attr checked {invert 0} {val 0}} {
"
}
proc setting_number {name descr val} {
puts -nonewline "
<tr>
<form class=auto id=${name} method=get action=$::env(SCRIPT_NAME)>
<th class=key>$descr</th>
<td>
<input name=${name} size=5 type=number
class=\"text ui-widget-content ui-corner-all\"
maxlength=10 value=\"$val\">
<small>
<input value=\"set\" type=submit>
</small>
<div id=${name}_output></div>
</td>
</form>
</tr>
"
}
######################################################################
# Settings Modules
foreach mod {general tvdb web epg network advanced} {
foreach mod $modules {
if {[file exists "$moddir/$mod/.disabled"]} continue
if {[catch {source "$moddir/$mod/settings.hook"} msg]} {
puts "ERROR: $msg"
@ -97,18 +118,17 @@ foreach mod {general tvdb web epg network advanced} {
######################################################################
# Plugins
set hook settings
foreach plugin [lsort [glob -nocomplain /mod/webif/plugin/*]] {
if {[file isfile "$plugin/$hook.hook"]} {
puts "<h4>Settings for <i>[file tail $plugin]</i> package</h4>"
puts "<div class=pluginsettings>"
if {[catch {source "$plugin/$hook.hook"} msg]} {
puts "ERROR: $msg"
}
puts "</div>"
}
proc plugin_callback {plugin hook} {
puts "<h4>Settings for <i>[file tail $plugin]</i> package</h4>"
puts "<div class=pluginsettings>"
if {[catch {source "$plugin/$hook"} msg]} {
puts "ERROR: $msg"
}
puts "</div>"
}
eval_plugins settings 0 plugin_callback
puts "</div>"
footer

View File

@ -2,7 +2,7 @@
source /mod/webif/lib/setup
require lock system.class ts.class pretty_size browse.class \
safe_delete settings.class plugin
safe_delete settings.class plugin queue.class rsv.class
set settings [settings]
set loglevel [$settings autolog]
@ -10,6 +10,14 @@ set audiomp3 [$settings audiomp3]
set modules {decrypt dedup shrink mpg mp3 expire}
set queue_actions {
decrypt do_decrypt
strip do_shrink
shrink do_shrink
mpg do_mpg
mp3 do_mp3
}
set root [system mediaroot]
set logfile "/mod/tmp/auto.log"
@ -17,6 +25,7 @@ set logfile "/mod/tmp/auto.log"
set logfd "unset"
set logprefix ""
set prelocked 0
set earlyexit 0
while {[llength $argv]} {
switch -- [lindex $argv 0] {
-d {
@ -32,6 +41,9 @@ while {[llength $argv]} {
set logprefix [lindex $argv 0]
}
}
-test {
set earlyexit 1
}
default {
# Unknown option, pass to rest of script.
break
@ -40,11 +52,16 @@ while {[llength $argv]} {
set argv [lrange $argv 1 end]
}
#########################################################################
if {$logfd ne "unset"} {
puts $logfd "Acquiring lock..."
}
if {!$prelocked && ![acquire_lock webif_auto 10 1]} {
if {$loglevel > 1} {
system plog auto "Could not acquire lock."
}
puts "Could acquire exclusive lock, terminating."
puts "Could not acquire exclusive lock, terminating."
exit
}
@ -64,6 +81,50 @@ proc log {msg {level 1}} {
flush $::logfd
}
proc oktorun {} {
global settings
set now [clock seconds]
# Ongoing scheduled recording
if {[$settings noautorec]} {
# Use redring helper files if available.
set recs [glob -nocomplain /tmp/.rec*]
set events [rsv list tbl_reservation \
" where ersvtype = 3
and nsttime - ulPreOffset <= $now
and nsttime + nduration + ulPostOffset >= $now "]
if {[llength $recs] || [llength $events]} {
log "Aborted, recording in progress." 2
exit
}
}
# Imminent recording
if {[$settings noautorecimm]} {
set autorecperiod $([$settings autorecperiod] * 60)
set events [rsv list tbl_reservation \
" where ersvtype = 3
and nsttime - $now < $autorecperiod
and nsttime > $now "]
if {[llength $events]} {
set event [lindex $events 0]
log [concat \
"Aborted, will record '[$event name]' " \
"on [$event channel_name] at " \
"[clock format [$event get nsttime] -format {%H:%M}]" \
] 2
exit
}
}
# Non-running hours
set hour $([clock format [clock seconds] -format %H] + 0)
if {$hour in [$settings noautohours]} {
log "Aborted, not running during hour $hour" 2
exit
}
}
proc inuse {ts} {
set retries 5
while {$retries > 0 && [$ts inuse]} {
@ -114,6 +175,10 @@ proc register {type fn {priority 50}} {
}
}
proc register_queue {action function} {
set ::queue_actions($action) $function
}
proc runplugin {name {ts 0}} {
set var "hook_$name"
global $var
@ -130,6 +195,14 @@ proc runplugin {name {ts 0}} {
}
}
# Check if it's ok to run now.
oktorun
if {$earlyexit} {
puts "Early exit."
exit
}
eval_plugins auto 1
set scanstart [clock milliseconds]
@ -253,6 +326,7 @@ proc do_shrink {ts} {
$ts set_shrunk
return
}
oktorun
set size [$ts size]
dsc $size
system startop shrink [$ts get file]
@ -360,6 +434,7 @@ proc do_decrypt {ts} {
}
# Perform the decryption by requesting the file from the DLNA server.
oktorun
set size [$ts size]
dsc $size
runplugin predecrypt $ts
@ -397,8 +472,10 @@ proc do_decrypt {ts} {
if {$anencd != "0"} {
log " $file - File did not decrypt properly." 0
system notify "$file - auto-decrypt failed."
file tdelete "$tmp/$bfile"
if {[clock seconds] - [$ts get end] > 3 * 3600} {
system notify "$file - auto-decrypt failed."
}
system endop decrypt
return
}
@ -462,6 +539,7 @@ proc do_mpg {ts} {
log " $file - In use."
return
}
oktorun
system startop mpg [$ts get file]
runplugin prempg $ts
dsc [$ts size]
@ -515,6 +593,7 @@ proc do_mp3 {ts} {
log " $file - In use."
return
}
oktorun
system startop mp3 [$ts get file]
runplugin premp3 $ts
dsc [$ts size]
@ -733,6 +812,7 @@ proc xscan {dir attr {force 0} {recurse 1} {seen {}}} {{indent 0} {forceflag ""}
set forceflag "$dir/.auto${attr}r"
}
oktorun
dsc
if {$force} {
@ -799,6 +879,33 @@ log "Root device: $rootdev" 2
if {[lindex $argv 0] eq "-singledir"} {
scansingle [lrange $argv 1 end]
} elseif {[lindex $argv 0] eq "-queue"} {
log "Processing queue..." 2
while {[llength [set q [queue pop]]]} {
oktorun
if {[catch {set ts [ts fetch [$q get file]]}]} {
$q update FAILED "Could not open recording." 1
continue
}
if {$ts == 0} {
$q update FAILED "Could not open recording." 1
continue
}
set act [$q get action]
if {![dict exists $::queue_actions $act]} {
log "Unknown queue action, $act"
$q update FAILED "Unknown queue action, $act" 1
continue
}
set func $::queue_actions($act)
$q update RUNNING "Started at [clock format [clock seconds]]"
if {[catch {$func $ts} msg]} {
$q update FAILED $msg 1
continue
}
$q update COMPLETE "Completed at [clock format [clock seconds]]"
}
} elseif {[llength $argv] > 0} {
set loglevel 2
foreach arg $argv {

7
webif/lib/bin/update_queue Executable file
View File

@ -0,0 +1,7 @@
#!/mod/bin/jimsh
source /mod/webif/lib/setup
require queue.class
queue boot

View File

@ -1,8 +1,12 @@
proc eval_plugins {hook {verbose 0}} {
proc eval_plugins {hook {verbose 0} {callback ""}} {
foreach plugin [lsort [glob -nocomplain /mod/webif/plugin/*]] {
if {[file exists "$plugin/.disabled"]} continue
if {[file isfile "$plugin/$hook.hook"]} {
if {$callback ne ""} {
$callback $plugin $hook.hook
continue
}
if {[catch \
{uplevel source "$plugin/$hook.hook"} msg]} {
if {$verbose} {

169
webif/lib/queue.class Normal file
View File

@ -0,0 +1,169 @@
if {![exists -proc class]} { package require oo }
if {![exists -proc sqlite3.open]} { package require sqlite3 }
class queue {
id -1
dat 0
file ""
action ""
log ""
status ""
retry 0
}
proc {queue dbhandle} {args} {
if {"-close" in $args} {
if {[info exists ::queue::db]} {
catch {$::queue::db close}
unset ::queue::db
return 1
}
return 0
}
if {[info exists ::queue::db]} {
return $::queue::db
}
if {![file exists /mod/etc/queue.db]} {
set ::queue::db [sqlite3.open /mod/etc/queue.db]
$::queue::db query {
create table queue(
id integer primary key autoincrement,
dat integer,
file text,
action text,
status text default 'PENDING',
log text default '',
retry integer default 0
);
}
$::queue::db query {
create unique index file on queue(file, action);
}
} else {
set ::queue::db [sqlite3.open /mod/etc/queue.db]
}
return $::queue::db
}
queue method update {_status {_log ""} {_retry 0}} {
set db [queue dbhandle]
$db query {
update queue
set status = '%s', log = '%s', retry = retry + %s
where id = %s
} $_status $_log $_retry $id
}
proc {queue boot} {} {
set db [queue dbhandle]
$db query {
update queue
set status = 'INTERRUPTED',
log = 'System was shut down. Job will be retried automatically.',
retry = retry + 1
where status in ('RUNNING', 'INTERRUPTED')
}
$db query {
delete from queue
where status in ('COMPLETE', 'FAILED')
and dat < %s
} [expr [clock seconds] - 86400 * 3]
}
proc {queue insert} {ts action} {
set db [queue dbhandle]
$db query {
insert or ignore into queue(dat, file, action)
values(%s, '%s', '%s')
} [clock seconds] [file normalize [$ts get file]] $action
return [$db lastid]
}
proc {queue delete} {ts {action "*"}} {
set db [queue dbhandle]
set q "
delete from queue
where file = '%s'
and status in ('PENDING', 'INTERRUPTED', 'COMPLETE', 'FAILED')
"
if {$action ne "*"} {
append q " and action = '%s'"
}
$db query $q [file normalize [$ts get file]] $action
}
proc {queue delete_by_id} {id} {
set db [queue dbhandle]
set q "
delete from queue
where id = '%s'
and status in ('PENDING', 'INTERRUPTED', 'COMPLETE', 'FAILED')
"
$db query $q $id
}
proc {queue status} {ts} {
set db [queue dbhandle]
set ret [$db query {
select group_concat(action)
from queue
where file = '%s'
and status not in ('COMPLETE', 'FAILED')
} [file normalize [$ts get file]]]
set q ""
if {[llength $ret] == 1} {
lassign [lindex $ret 0] x q
}
return $q
}
proc {queue all} {} {
set db [queue dbhandle]
set ret {}
foreach row [$db query {select * from queue order by id}] {
lappend ret [queue new $row]
}
return $ret
}
proc {queue pending} {} {
set db [queue dbhandle]
set ret {}
foreach row [$db query {
select * from queue
where status in ('PENDING', 'INTERRUPTED')
order by id
}] {
lappend ret [queue new $row]
}
return $ret
}
proc {queue pop} {} {
set db [queue dbhandle]
foreach row [$db query {
select * from queue
where status in ('PENDING', 'INTERRUPTED')
order by id
limit 1
}] {
return [queue new $row]
}
return {}
}

View File

@ -199,6 +199,15 @@ rsv method end {} {
return $([$self start] + $nduration)
}
rsv method showing {} {
set now [clock seconds]
if {$nsttime - $ulPreOffset <= $now &&
$nsttime + $nduration + $ulPostOffset >= $now} {
return 1
}
return 0
}
rsv method icon {} {
set rsvicon ""
switch $ersvtype {

View File

@ -24,6 +24,7 @@ class settings {
smtp_server ""
pkgdev 0
notoolbar 0
noautorec 0
tvdb 0
tvdb_debug 0
nomobile 0
@ -35,6 +36,10 @@ class settings {
epgscroll 0
genrededup 0
autolog 0
noautorec 0
noautorecimm 0
autorecperiod 10
noautohours ""
changechangenc 0
audiomp3 0
logsize 1048576
@ -225,6 +230,23 @@ settings method autolog {{level -1}} {
return [$self _nval_setting autolog $level]
}
settings method noautorec {{val -1}} {
return [$self _nval_setting noautorec $val]
}
settings method noautorecimm {{val -1}} {
return [$self _nval_setting noautorecimm $val]
}
settings method autorecperiod {{val -1}} {
return [$self _nval_setting autorecperiod $val]
}
settings method noautohours {{val -1}} {
set val [$self _tval_setting noautohours $val]
return $val
}
settings method audiomp3 {{val -1}} {
return [$self _nval_setting audiomp3 $val]
}