diff --git a/CONTROL/control b/CONTROL/control index 376c898..0753ec7 100644 --- a/CONTROL/control +++ b/CONTROL/control @@ -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) diff --git a/etc/init.d/S59webif b/etc/init.d/S59webif index eb907db..9bc5f88 100755 --- a/etc/init.d/S59webif +++ b/etc/init.d/S59webif @@ -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`)." ;; diff --git a/webif/html/browse/assets.jim b/webif/html/browse/assets.jim index 84ead1e..b54556a 100755 --- a/webif/html/browse/assets.jim +++ b/webif/html/browse/assets.jim @@ -376,6 +376,26 @@ Please wait... - +} + +set queueactions(decrypt) "Decryption" +set queueactions(shrink) "Shrink" +set queueactions(mp3) "Audio-Extraction" +set queueactions(mpg) "Conversion to MPG" +eval_plugins queueactions + +puts { + } diff --git a/webif/html/browse/dequeue.jim b/webif/html/browse/dequeue.jim new file mode 100755 index 0000000..79482d8 --- /dev/null +++ b/webif/html/browse/dequeue.jim @@ -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 "
De-queuing...
" +puts "" + diff --git a/webif/html/browse/index.jim b/webif/html/browse/index.jim index 3ae1b87..47d3724 100755 --- a/webif/html/browse/index.jim +++ b/webif/html/browse/index.jim @@ -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 { } } +# Queue +puts { } + # De-duplicate puts { diff --git a/webif/html/browse/queue.jim b/webif/html/browse/queue.jim new file mode 100755 index 0000000..fed764a --- /dev/null +++ b/webif/html/browse/queue.jim @@ -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 "
Queuing...
" +puts "" + diff --git a/webif/html/browse/script.js b/webif/html/browse/script.js index 613a73c..ddf0dfa 100755 --- a/webif/html/browse/script.js +++ b/webif/html/browse/script.js @@ -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() diff --git a/webif/html/diag/diag.jim b/webif/html/diag/diag.jim index 7f9f508..5bf875f 100755 --- a/webif/html/diag/diag.jim +++ b/webif/html/diag/diag.jim @@ -105,6 +105,7 @@ util "shredder" "rma" "RMA" "#" "
" util "bluering" "reboot" "Reboot System" "/restart/" util "maint" "maint" "Maintenance Mode" "#" "
" +util "queuep" "queue" "Queued Tasks" "/diag/queue/" eval_plugins diag diff --git a/webif/html/diag/queue/delete.jim b/webif/html/diag/queue/delete.jim new file mode 100755 index 0000000..6b5d725 --- /dev/null +++ b/webif/html/diag/queue/delete.jim @@ -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 +} + diff --git a/webif/html/diag/queue/index.jim b/webif/html/diag/queue/index.jim new file mode 100755 index 0000000..f53e816 --- /dev/null +++ b/webif/html/diag/queue/index.jim @@ -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 { +

+ + Queued Tasks +

+
+Queued Tasks + + + + + + + + + + + + +} + +foreach q [queue all] { + set name [string map { + "/mnt/hd2/My Video/" "" + "/media/drive1/Video/" "" + "/media/" "" + ".ts" "" + } [$q get file]] + + puts " + + + + + + + + + " +} + +puts { + +
IDSubmittedFileActionStatusLog
+ [$q get id] + [clock format [$q get dat] -format {%c}]$name[$q get action][$q get status]" + if {[$q get status] eq "RUNNING"} { + puts "" + } + puts "[$q get log]
+ + +
+} + +footer + diff --git a/webif/html/diag/queue/script.js b/webif/html/diag/queue/script.js new file mode 100644 index 0000000..10b68f7 --- /dev/null +++ b/webif/html/diag/queue/script.js @@ -0,0 +1,75 @@ +function page_refresh(msg) +{ + if (!msg) + msg = 'Refreshing page...'; + $.blockUI({ + message: '

' + msg + '

' + }); + 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: '

Deleting...

' + }); + + + 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); + +}); + diff --git a/webif/html/diag/queue/style.css b/webif/html/diag/queue/style.css new file mode 100644 index 0000000..48e37b1 --- /dev/null +++ b/webif/html/diag/queue/style.css @@ -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; +} + diff --git a/webif/html/img/queue.png b/webif/html/img/queue.png new file mode 100644 index 0000000..75b1be3 Binary files /dev/null and b/webif/html/img/queue.png differ diff --git a/webif/html/img/queuep.png b/webif/html/img/queuep.png new file mode 100644 index 0000000..8bf27b3 Binary files /dev/null and b/webif/html/img/queuep.png differ diff --git a/webif/html/img/queueps.png b/webif/html/img/queueps.png new file mode 100644 index 0000000..2fc34c8 Binary files /dev/null and b/webif/html/img/queueps.png differ diff --git a/webif/html/settings/modules/auto/init.hook b/webif/html/settings/modules/auto/init.hook new file mode 100644 index 0000000..2418541 --- /dev/null +++ b/webif/html/settings/modules/auto/init.hook @@ -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 + diff --git a/webif/html/settings/modules/auto/settings.hook b/webif/html/settings/modules/auto/settings.hook new file mode 100755 index 0000000..b2eb5f7 --- /dev/null +++ b/webif/html/settings/modules/auto/settings.hook @@ -0,0 +1,79 @@ + +###################################################################### +# Auto-Processing Settings + +puts " +

Auto-Processing Settings

+
+ + Auto-Processing Settings + + +" + +puts -nonewline " + + + + + + +" + +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 " + + + + + + +" + +puts " +
Auto-processing log level + + + +
+
Suspend automatic processing during: +
+ Use Shift and Control to select multiple entries. +
+
+ + + +
+
+" + diff --git a/webif/html/settings/modules/general/init.hook b/webif/html/settings/modules/general/init.hook index f501ad5..104f546 100644 --- a/webif/html/settings/modules/general/init.hook +++ b/webif/html/settings/modules/general/init.hook @@ -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" diff --git a/webif/html/settings/modules/general/settings.hook b/webif/html/settings/modules/general/settings.hook index 44749ea..703f7d6 100755 --- a/webif/html/settings/modules/general/settings.hook +++ b/webif/html/settings/modules/general/settings.hook @@ -38,33 +38,6 @@ if {[system pkginst ir]} { "chanchangenc" $chanchangenc 0 } -puts -nonewline " - -
- Auto-processing log level - - - - -
- -
- -" - puts -nonewline "
diff --git a/webif/html/settings/settings.jim b/webif/html/settings/settings.jim index 13262d9..402425d 100755 --- a/webif/html/settings/settings.jim +++ b/webif/html/settings/settings.jim @@ -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 " + + + $descr + + + + + +
+ +
+ + " +} + ###################################################################### # 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 "

Settings for [file tail $plugin] package

" - puts "
" - if {[catch {source "$plugin/$hook.hook"} msg]} { - puts "ERROR: $msg" - } - puts "
" - } +proc plugin_callback {plugin hook} { + puts "

Settings for [file tail $plugin] package

" + puts "
" + if {[catch {source "$plugin/$hook"} msg]} { + puts "ERROR: $msg" + } + puts "
" } +eval_plugins settings 0 plugin_callback + puts "" footer diff --git a/webif/lib/bin/auto b/webif/lib/bin/auto index d3eabcc..f98205b 100755 --- a/webif/lib/bin/auto +++ b/webif/lib/bin/auto @@ -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 { diff --git a/webif/lib/bin/update_queue b/webif/lib/bin/update_queue new file mode 100755 index 0000000..14acb8d --- /dev/null +++ b/webif/lib/bin/update_queue @@ -0,0 +1,7 @@ +#!/mod/bin/jimsh + +source /mod/webif/lib/setup +require queue.class + +queue boot + diff --git a/webif/lib/plugin b/webif/lib/plugin index 117a47b..bf7f96c 100644 --- a/webif/lib/plugin +++ b/webif/lib/plugin @@ -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} { diff --git a/webif/lib/queue.class b/webif/lib/queue.class new file mode 100644 index 0000000..21e7cb7 --- /dev/null +++ b/webif/lib/queue.class @@ -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 {} +} + diff --git a/webif/lib/rsv.class b/webif/lib/rsv.class index f054b80..3f35895 100755 --- a/webif/lib/rsv.class +++ b/webif/lib/rsv.class @@ -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 { diff --git a/webif/lib/settings.class b/webif/lib/settings.class index ddaa6b6..edfcaac 100644 --- a/webif/lib/settings.class +++ b/webif/lib/settings.class @@ -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] }