Merge branch 'master' into df-playmedia-patch

This commit is contained in:
df 2021-03-15 15:51:11 +00:00
commit f6a3b999c4
38 changed files with 807 additions and 271 deletions

View File

@ -1,7 +1,7 @@
Package: webif
Priority: optional
Section: web
Version: 1.4.9
Version: 1.4.9-3
Architecture: mipsel
Maintainer: af123@hpkg.tv
Depends: tcpfix,webif-channelicons(>=1.1.27),lighttpd(>=1.4.39-1),jim(>=0.79),jim-pack(>=0.79),jim-oo(>=0.77),jim-sqlite3(>=0.77),jim-cgi(>=0.7-2),jim-binary(>=0.76),service-control(>=2.3),busybox(>=1.20.2-1),lsof(>=4.87),epg(>=1.2.8),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.13),webif-charts(>=1.2-1),stripts(>=1.4.2),tmenu(>=1.21-2),ffmpeg(>=2.8),id3v2,multienv(>=1.6),tcpping(>=1.1),e2fsprogs,wireless-tools(>=29-1),dbupdate,recmon(>=2.0.7),hwctl,nugget(>=0.98),sqlite3(>=3.15.1),jim-xconv,zip(>=3.0-1),wget

View File

@ -31,7 +31,7 @@ if {[$record get sched_type] < 1} {
[system tuners]]
if {[llength $conflicts]} {
puts {
<div class=warningbox style="width: 100%; margin: 0.2em"><div>
<div class=warningbox style="width: auto; margin: 0.2em"><div>
This event conflicts with the following items in your scheduled recording list.
<ul>
}

View File

@ -2,7 +2,7 @@
package require cgi
source /mod/webif/lib/setup
require pkg.class system.class
require pkg.class system.class settings.class
cgi_input
#cgi_dump
@ -61,6 +61,11 @@ if {$cmd eq "dependinfo"} {
}
if {$cmd eq "upgrade"} { opkg update }
if {$cmd eq "remove" && [[settings] noautoremove] ne "1"} {
append cmd " --autoremove"
}
opkg "$cmd $cmdargs"
if {$cmd eq "update" || $cmd eq "upgrade"} {

View File

@ -7,7 +7,7 @@ require system.class epg.class rsv.class svc.class plugin
set runmode cli
if {[string match {*jim} $argv0]} { set runmode cgi }
set schedtime 1200
set schedtime 1200
switch $runmode {
cgi {
set type [cgi_get type "full"]
@ -15,8 +15,7 @@ switch $runmode {
}
cli {
set type "full"
if {"-X" in $argv} { set schedtime 7200 }
if {"-x" in $argv} { set schedtime 7200 }
if {[lsearch -nocase $argv "-x"] >= 0} { set schedtime 7200 }
}
}
@ -61,11 +60,11 @@ proc register_statusop {op name icon} {
eval_plugins status 1
proc get_data {} {
global pid exts
global pid exts stream tsr tsrcnt
set ret {}
if {[catch {set data \
[exec /mod/webif/lib/bin/lsof -X -Fns -p $pid]} msg]} {
[exec /mod/webif/lib/bin/lsof -Fnsa -p $pid]} msg]} {
debug "Error: $msg"
set ret {}
} else {
@ -73,35 +72,64 @@ proc get_data {} {
foreach line [split $data "\n"] {
set typ [string index $line 0]
switch $typ {
a {
set access [string index $line 1]
}
s {
set size [string range $line 1 end]
}
n {
if {[string first Video/ $line] == -1 && \
[string first /media/ $line] == -1} {
# strip initial n and trailing " (...)" if
# present
regsub -all -- {(^n)|( \([^\)]+\)$)} \
$line "" line
set file [subst -nocommands -novariables $line]
set ext [file extension $line]
# Note but skip TSR buffers
if {[file rootname $file] eq $tsr} {
if {$ext eq ".nts"} {
incr tsrcnt
}
continue
}
regsub -- { \([^\)]+\)$} $line "" line
set ext [file extension $line]
if {$ext ni $exts} continue
set file [subst -nocommands -novariables \
[string range $line 1 end]]
# Skip HD-Fox TSR buffer
if {$file eq "/media/drive1/.tsr/0.ts"} {
if {[string first Video/ $line] >= 0 ||
[string first /media/ $line] >= 0} {
if {$ext ni $exts} {
continue
}
} elseif {[string first $line /] >= 0} {
# fast skip other files
continue
} elseif {[regexp -- {[A-Za-z0-9._-]+:([0-9]+)->([A-Za-z0-9._-]+):([0-9]+)} $line _ sprt host dprt]} {
if {$sprt == 9000} {
incr stream
continue
} elseif {$dprt == 9000} {
set file [\
format "DLNA from %s" $host]
set size 0
set ext ""
} else {
continue
}
} else {
continue
}
# Handle chase play (same file open twice
# and recently written)
if {[dict exists $ret $file] && \
if {[dict exists $ret $file] &&
$ext eq ".ts"} {
set age [expr [clock seconds] - \
[file mtime $file]]
set age [expr [clock seconds] \
- [file mtime $file]]
if {$age < 60} {
set ret($file) -1
set access [lindex \
[dict get $ret $file] 1]
set ret($file) [list -1 $access]
}
} else {
debug "$file = $size"
set ret($file) $size
} else {
debug "$file = $size,$access"
set ret($file) [list $size $access]
}
}
}
@ -109,11 +137,9 @@ proc get_data {} {
}
foreach file [dict keys $::ops] {
if {![dict exists $ret $file]} {
if {[file exists $file]} {
set ret($file) [file size $file]
} else {
set ret($file) 0
}
set sz 0
if {[file exists $file]} { set sz [file size $file] }
set ret($file) [list $sz u]
}
}
return $ret
@ -139,9 +165,12 @@ proc add_output {icon mode name} {
set play 0
set rec 0
set stream 0
set output {}
set ops {}
set model [system model]
set tsr [file rootname [system tsr]]
set tsrcnt 0
foreach opfile [glob -nocomplain -directory /tmp -tails -- ".bgop.*"] {
set op [string range $opfile 6 end]
@ -179,8 +208,9 @@ if {[llength $data]} {
debug " NDATA: ($ndata)"
set rr 0
}
set bnames [lsort [lmap x [array names data] { file tail $x }]]
foreach file [array names data] {
set bname [file rootname [file tail $file]]
set bname [file tail $file]
set name [string map {
"/mnt/hd2/My Video/" ""
@ -189,17 +219,22 @@ if {[llength $data]} {
".ts" ""
} $file]
if {$data($file) == -1} {
if {[lindex $data($file) 0] == -1} {
set mode chase
} elseif {$rr} {
if {$file in $recs} {
set mode rec
} elseif {[llength [\
lsearch -all $bnames $bname]] == 2} {
# two different files having same file.ext open
set mode copy
} else {
set mode play
}
} else {
if {![dict exists $ndata $file]} continue
if {$ndata($file) > $data($file)} {
if {[lindex $ndata($file) 0] > \
[lindex $data($file) 0]} {
set mode rec
} else {
set mode play
@ -231,8 +266,20 @@ if {[llength $data]} {
}
play {
incr play
set mode "Playing"
set icon "745_1_10_Video_2Live.png"
if {$play > $stream} {
set mode "Playing"
set icon "745_1_10_Video_2Live.png"
} else {
set mode "Streaming"
set icon "/img/dlna.png"
}
}
copy {
if {[lindex $data($file) 1] ne "r"} {
continue
}
set mode "Copying"
set icon "/img/dlna.png"
}
default {
if {[dict exists $statusops $mode]} {
@ -272,23 +319,33 @@ if {![system instandby] && $play < 1} {
if {[llength $epgs] == 1} {
lassign $epgs epg
set prog "- [$epg get name] ("
append prog "[clock format [$epg get start] -format %H:%M] - "
append prog "[clock format $([$epg get start] + [$epg get duration]) -format %H:%M]"
append prog "[clock format [\
$epg get start] -format %H:%M] - "
append prog "[clock format $([$epg get start] \
+ [$epg get duration]) -format %H:%M]"
append prog ") \[[$epg percent]%\]"
}
if {$runmode eq "cgi"} {
set s "
<span class=\"va stitem\">
[epg channelicon $name 30 \
{vertical-align: middle; padding: 0 4px 0 2px}]
<span>Watching <i>$lcn: $name $prog</i></span>
"
append s "</span>"
lappend output $s
# 0 => no TSR; >=2 => TSR
if {$tsrcnt == 0 || $tsrcnt == 2} {
set s "Watching"
} elseif {$tsrcnt == 3} {
set s "Watching (delayed)"
} else {
set s "Watching $lcn: $name $prog"
lappend output $s
debug "tsrcnt=$tsrcnt"
set s "Not watching"
}
if {$runmode eq "cgi"} {
lappend output [format "
<span class=\"va stitem\">
[epg channelicon %s 30 \
{vertical-align: middle; padding: 0 4px 0 2px}]
<span>%s <i>%s: %s %s</i></span>
</span>
" $name $s $lcn $name $prog]
} else {
lappend output [format "%s %s: %s %s" \
$s $lcn $name $prog]
}
}
}
@ -314,7 +371,7 @@ if {[system instandby]} {
# Upcoming recordings
set events [rsv list tbl_reservation \
" where ersvtype = 3 and nsttime - [clock seconds] < $schedtime
" where ersvtype = 3 and nsttime - [clock seconds] < $schedtime
and nsttime > [clock seconds] "]
foreach event $events {
if {$runmode eq "cgi"} {

View File

@ -103,6 +103,8 @@ if {[llength $plugins(dmenu)]} {
}
}
# the maxlength values for title and synopsis are 1 less than the maximum to
# allow for an extra byte to indicate character encoding (see rename.jim)
puts {
</ul>
@ -131,20 +133,51 @@ puts {
</th>
<td>
<input type=text name="rename_title" id="rename_title"
value="" size=70 maxlength=48
value="" size=70 maxlength=47
class="text ui-widget-content ui-corner-all">
</td>
</tr>
<tr style="display: none" class=tstype>
<th>
<label for="rename_seriesnum" style="padding-top: 0.5em">
<b>New Series Number</b>
</label>
</th>
<td>
<span title="Series number">
<input type=number name="rename_seriesnum" id="rename_seriesnum"
value=0 max=255
class="uint8_t ui-widget-content ui-corner-all">
</span>
<label for="rename_episodenum" style="padding-top: 0.5em">
<b>Episode</b>
</label>
<span title="Episode number">
<input type=number name="rename_episodenum"
id="rename_episodenum" value=0 max=255
class="uint8_t ui-widget-content ui-corner-all">
</span>
<label for="rename_episodetot" style="padding-top: 0.5em">
<b>of</b>
</label>
<span title="Episode total">
<input type=number name="rename_episodetot"
id="rename_episodetot" value=0 max=255
class="uint8_t ui-widget-content ui-corner-all">
</span>
</td>
</tr>
<tr style="display: none" class=tstype>
<th>
<label for="rename_synopsis" style="padding-top: 0.5em">
<b>New Synopsis</b>
</label>
</th>
<td>
<td colspan=3>
<textarea name="rename_synopsis" id="rename_synopsis"
value="" cols=70 rows=4
value="" cols=70 rows=4 maxlength=251
class="text ui-widget-content ui-corner-all"></textarea>
</td>
</tr>

View File

@ -2,7 +2,7 @@
package require cgi
source /mod/webif/lib/setup
require ts.class pretty_size
require ts.class system.class pretty_size
jscss script.js style.css
jqplugin touchpunch
@ -15,6 +15,10 @@ set erfile [string map {' \\'} $rfile]
set len [$ts duration 1]
set start -1
set incr 1
set limit $(1-$start)
puts "
<script type=text/javascript>
var initbookmarks = '[$ts bookmarks]';
@ -39,10 +43,38 @@ var dir = '$dir';
<button class=left id=addbmark>Add Bookmark</button>
<button class=left id=delbmark>Remove Bookmark</button>
</td><td><div id=slider></div></td></tr>
<tr><td align=right>
<span class=left>Current: <span id=curbmk></span></span><br><br><br>
<button id=genthumbs title=\"Generate Thumbnails\"
class=left>Generate Thumbnails</button>
</td><td>
<div id=thumbs class=hidden>
<table><tr>
"
set times {}
loop v $start $limit $incr {
lappend times $v
puts "
<th style=\"text-align: center\"><span class=mark>
[format "%+d" $v]</span>s</th>
"
}
puts "</tr><tr>"
foreach v $times {
puts "<td><img class=bmp src=/img/generating.png pos=$v></td>"
}
puts "
</tr></table>
</div></td></tr>
</table>
<div id=buttons>
<button id=save>Save Bookmarks</button>
<button id=back>Back to Media Browser</button>
"
if {[system pkginst nicesplice]} {
puts "<button id=crop>Go to Crop</button>"
}
puts "
</div>
<div id=results class=\"hidden blood\"></div>
"

View File

@ -1,11 +1,26 @@
var curval = 0;
var $slider;
var values;
function
toTimeStr(tval)
{
return new Date(null, null, null, null, null, tval)
.toTimeString().match(/\d{2}:\d{2}:\d{2}/)[0] + ' ';
}
function
valarray(valstr)
{
return valstr.trim().split(/ +/);
}
function
setvals()
{
values = $.trim($('#bookmarks').val()).split(/ +/);
if (!values.length || values[0] == '')
var nvalues;
values = valarray($('#bookmarks').val());
if (values.length > 0 && values[0] != '')
{
refreshtimes();
return;
@ -20,6 +35,7 @@ setvals()
});
values = nvalues;
$('#bookmarks').val(values.join(' '));
values = valarray($('#bookmarks').val());
sortmarks();
refreshtimes();
}
@ -32,7 +48,6 @@ draw_slider()
else
$slider = $('#slider');
setvals();
values = $.trim($('#bookmarks').val()).split(/ +/);
if (!values.length || values[0] == '')
{
$slider = null;
@ -55,55 +70,95 @@ draw_slider()
var marks = '';
for (var i = 0; i < ui.values.length; ++i)
marks += ui.values[i] + ' ';
$('#bookmarks').val($.trim(marks));
$('#bookmarks').val(marks.trim());
setvals();
}
});
refreshtimes();
};
function
regenthumbs(curbmkstr)
{
$('#curbmk').html(curbmkstr);
$('#thumbs').hide();
$('#genthumbs')
.button('enable')
.button('option', 'icon', 'ui-icon-zoomin');
}
function
update_slider()
{
setvals();
/* slider values are strings */
var curvalstr = "" + curval;
if (!values.includes(curvalstr)) {
/* try to map current selected bmk to new bmk */
var ovalues = $slider.slider("option", "values");
var nn = ovalues.indexOf(curvalstr);
if (nn < 0) {
curval = 0;
} else {
if (nn >= values.length)
nn = values.length - 1;
curval = nn >= 0 ? values[nn] : 0;
}
regenthumbs(toTimeStr(curval));
}
$('#slider .ui-slider-handle').each(function(i) {
if (i >= values.length)
$(this).hide();
else
$(this).show();
});
$slider.slider("option", "values", values);
};
function
refreshtimes()
{
var t = '';
values = $.trim($('#bookmarks').val()).split(/ +/);
if (!values.length || values[0] == '')
{
$('#bookmarkstime').text(t);
return;
$.each(values, function(k, v) {
t += toTimeStr(v);
});
$('#slider .ui-slider-handle').each(function(i) {
$(this).attr('title', toTimeStr(values[i]));
});
}
$.each(values, function(k, v) {
t += new Date(null, null, null, null, null, v)
.toTimeString().match(/\d{2}:\d{2}:\d{2}/)[0] + ' ';
});
$('#bookmarkstime').text(t);
}
function
sortmarks()
{
var a = $.trim($('#bookmarks').val()).split(/ +/);
a.sort(function(a, b){return a-b});
$('#bookmarks').val(a.join(" "));
values.sort(function(a, b){return a - b});
$('#bookmarks').val(values.join(" "));
}
$(function() {
$('#bookmarks').val($('#bookmarks').attr('init'));
draw_slider();
$('#curbmk').html(toTimeStr(curval));
$('#addbmark').button({icons: {primary: "ui-icon-plus"}, text: false})
.on('click', function() {
$('#bookmarks').val('0 ' + $('#bookmarks').val());
draw_slider();
curval = 0;
update_slider();
});
$('#delbmark').button({icons: {primary: "ui-icon-minus"}, text: false})
.on('click', function() {
var cur = $('#bookmarks').val();
cur = $.trim(cur.replace(
new RegExp('(^| )' + curval + '( |$)', ''), ' '));
cur = cur.replace(
new RegExp('(^| )' + curval + '( |$)', ''), ' ').trim();
$('#bookmarks').val(cur);
draw_slider();
update_slider();
});
$('#save').button({icons: {primary: "ui-icon-disk"}})
@ -122,11 +177,62 @@ $('#back').button({icons: {primary: "ui-icon-arrowreturnthick-1-w"}})
window.location = '/go/browse?dir=' + encodeURIComponent(dir);
});
$('#crop').button({icons: {primary: "ui-icon-arrowreturnthick-1-e"}})
.on('click', function() {
window.location =
window.location.href.replace('/bookmarks/?','/crop/crop.jim?');
});
$('#update').button()
.on('click', function() {
draw_slider();
update_slider();
});
$('#slider')
.on('slidechange', function(evt, ui) {
var tstr = toTimeStr(curval);
if (tstr != $('#curbmk').html())
regenthumbs(tstr);
});
$('#genthumbs').button({icons: {primary: "ui-icon-zoomin"}, disabled: false})
.on('click', function() {
var start;
var incr = -1;
var last;
$(this)
.button('disable')
.button('option', 'icon', 'ui-icon-refresh');
$('img.bmp').each(function(i) {
if (start === undefined) {
start = $(this).attr('pos') | 0;
} else {
last = $(this).attr('pos') | 0;
}
incr++;
});
incr = (last - start) / incr;
$.get('/browse/thumbnail/mkrange.jim', {
'file': file,
's': start+curval,
'e': last+curval,
'i': incr
}, function() {
$('#thumbs').show();
$('img.bmp').each(function(i) {
/* cast to "int" */
var pos = $(this).attr('pos')|0;
$(this).attr('src',
'/browse/thumbnail/fetch.jim?' +
'file=' + encodeURIComponent(file) +
'&pos=' + (curval+pos).toFixed(1));
});
$('#genthumbs').button('option', 'icon', 'ui-icon-zoomin');
});
});
});

View File

@ -14,6 +14,7 @@ set ts [ts fetch $rfile]
set dir [file dirname $rfile]
set len [$ts duration 1]
set planwidth 500
puts "
<fieldset>
@ -29,12 +30,17 @@ puts [join [lmap i [$ts bookmarks 1] {
clock format $i -format "%T"
}] ", "]
puts "</td></tr><tr><th>&nbsp;</th><td id=cutplan>"
# set minimum width as positioned contents doesn't resize its cell
puts "</td></tr><tr><th>&nbsp;</th><td id=cutplan style=\"min-width: ${planwidth}px\">"
puts "<div style=\"position: relative; top: -10px\">"
proc div {type left right} {
set width $($right - $left)
if {$width < 0} {
# negative values are invalid for CSS width
set width 0
}
puts "<div class=$type style=\"left: ${left}px; width: ${width}px\">
$type</div>"
}
@ -64,8 +70,8 @@ foreach b $bookmarks {
incr cur $l
append newbookmarks "[expr $cur + 3] "
set left $($start * 500 / $len)
set right $($end * 500 / $len)
set left $($start * $planwidth / $len)
set right $($end * $planwidth / $len)
div cut $last $($left - 1)
div keep $left $($right - 1)
@ -78,11 +84,11 @@ foreach b $bookmarks {
if {$start > 0} {
# Still in a keep section...
incr keeping $($len - $start)
set left $($start * 500 / $len)
set left $($start * $planwidth / $len)
div cut $last $($left - 1)
div keep $left 500
div keep $left $planwidth
} else {
div cut $last 500
div cut $last $planwidth
}
if {$cur > $keeping - 8 && $keeping - 8 > 0} {
@ -115,7 +121,7 @@ puts [join [lmap i $newbookmarks {
puts " )</td></tr>"
puts "
<tr><th>Time:</th>
<tr id=esttime><th>Time:</th>
<td>Cropping will take around [clock format $esttime -format "%T"]</td></tr>
</table>
@ -130,9 +136,9 @@ puts "
<td><button id=invert invert=$invert>Invert selection</button></td>
<td><button id=cropit>Perform crop operation</button></td>
<td>
Save new bookmarks?
<label id=saveitlabel for=saveit>Save new bookmarks?</label>
<input id=saveit type=checkbox name=saveit checked>
<label id=saveitlabel for=saveit>&nbsp;</label>
&nbsp;
</td>
</tr></table>
</div>

View File

@ -1,12 +1,5 @@
var handle = 0;
function escapestring(str)
{
str = JSON.stringify(String(str));
str = str.substring(1, str.length - 1);
return str;
}
function update()
{
$.get('progress.jim', {
@ -27,7 +20,8 @@ $('[type="checkbox"]').iphoneStyle({
$('#progressbar').reportprogress(0);
$('#back').button().click(function() {
$('#back').button({icons: {primary: "ui-icon-arrowreturnthick-1-w"}})
.on('click', function() {
window.location = '/go/browse?dir=' + $('#params').attr('dir');
});
@ -44,10 +38,17 @@ $('#save').button({icons: {primary: "ui-icon-disk"}})
.slideUp('slow');
$('#originalbookmarks')
.html($('#newbookmarks').clone());
$('#esttime').hide();
if ($('#results').html().indexOf(' successful') < 0) {
$('#saveit').hide();
$('#saveitlabel').hide();
$('#save').show();
}
});
});
$('#cropit').button().click(function() {
$('#cropit').button({icons: {primary: "ui-icon-scissors"}})
.on('click', function() {
$('#cropdiv').hide('slow');
$('#progressdiv').show('slow');
$('#back').hide();
@ -56,7 +57,7 @@ $('#cropit').button().click(function() {
.load('execute.jim', {
'file': $('#params').attr('file'),
'invert': $('#invert').attr('invert')
}, function() {
}, function() {
clearInterval(handle);
handle = 0;
$('#back,#save').show();
@ -73,10 +74,10 @@ $('#cropit').button().click(function() {
});
});
$('#invert').button().on('click', function() {
window.location = 'crop.jim?file=' +
escapestring($('#params').attr('file')) +
'&invert=' + ($(this).attr('invert') == '1' ? '0' : '1');
$('#invert').button({icons: {primary: "ui-icon-shuffle"}})
.on('click', function() {
window.location = window.location.href.replace(/&invert=[01]/,'') +
'&invert=' + ($(this).attr('invert') == '1' ? '0' : '1');
});
});

View File

@ -11,3 +11,8 @@ div.sliderlabel
line-height: 40px;
}
#cutplan {
/* ensure cut plan segments are aligned left */
padding-left: 0;
}

View File

@ -14,6 +14,9 @@ puts "{"
puts "\"title\" : \"[jescape [$ts get title]]\","
puts "\"synopsis\" : \"[jescape [$ts get synopsis]]\","
puts "\"guidance\" : \"[jescape [$ts get guidance]]\","
puts "\"genre\" : [jescape [$ts genrenib]]"
puts "\"genre\" : [jescape [$ts genrenib]],"
puts "\"seriesnum\" : [jescape [$ts get seriesnum]],"
puts "\"episodenum\" : [jescape [$ts get episodenum]],"
puts "\"episodetot\" : [jescape [$ts get episodetot]]"
puts "}"

View File

@ -58,6 +58,10 @@ proc icon {img {hover ""} {extra ""} {class "va"}} {
puts ">"
}
proc nbsp {str} {
return [string map {" " &nbsp;} $str]
}
proc directory {file bfile tbfile} {
puts "<div class=\"va relative\">"
set img "/images/711_1_09_Media_Folder.png"
@ -69,7 +73,7 @@ proc directory {file bfile tbfile} {
puts "<a class=dbf
href=\"$::env(SCRIPT_NAME)?dir=[cgi_quote_url $file]\"
file=\"[cgi_quote_html $file]\">"
puts "$bfile</a><span class=filesize id=\"$tbfile\">
puts "[nbsp $bfile]</a><span class=filesize id=\"ID$tbfile\">
</span>"
lassign [dir iconset $file] icons attrs
@ -106,13 +110,12 @@ proc entry {file} {{i 0}} {
global dircount filecount dinuse
set bfile [file tail $file]
regsub -all " +" $bfile "" tbfile
if {[string index $bfile 0] == "\025"} {
set bfile [string range $bfile 1 end]
}
if {[file isdirectory "$file"]} {
incr dircount
directory $file $bfile $tbfile
directory $file $bfile [b64uencode [jsescape $bfile]]
return
}
set ext [string tolower [file extension $file]]
@ -182,7 +185,7 @@ proc entry {file} {{i 0}} {
<input class=\"$fscl\" type=checkbox>
<a class=bf title=\"$synopsis\"
file=\"[cgi_quote_html $file]\" type=$type href=#>
$bfile
[nbsp $bfile]
</a>
"
@ -370,7 +373,7 @@ foreach sl $sortlist {
set tag " (current)"
if {$order != $index} {
set qs [regsub -all {&order=[[[:digit:]]+} $env(QUERY_STRING) ""]
set qs [regsub -all {&order=[[:digit:]]+} $env(QUERY_STRING) ""]
puts "<a href=\"$env(SCRIPT_NAME)?$qs&order=$index\" title=\"$tt\">"
set tag ""
set ket "a"

View File

@ -30,8 +30,7 @@ if {[file isdirectory $file]} {
set new "\025$new"
}
if {$new ne $old} {
if {$attr eq "guidance" ||
[string length $new] > 0} {
if {$attr eq guidance || $new ne ""} {
$ts set$attr $new
}
}
@ -39,6 +38,45 @@ if {[file isdirectory $file]} {
puts "$attr: $msg"
}
}
# deal with series number/ep num/ep total, which get set together
# list the old values seen in case a later one is changed
set epdataold {}
# list values to be set, or {}
set epdatanew {}
foreach attr {seriesnum episodenum episodetot} {
if {[catch {
set new [string map {"\n" ""} [
string trim [cgi_get "rename_$attr"]]]
set old [$ts get $attr]
if {$new ne $old} {
switch $attr {
seriesnum {
set epdatanew [list $new]
}
episodenum -
episodetot {
if {$epdatanew eq {}} {
set epdatanew $epdataold
}
lappend epdatanew $new
}
}
} elseif {$epdatanew eq {}} {
# nothing to be changed yet
lappend epdataold $old
} else {
# fill to-be-set list with old value
lappend epdatanew $old
}
} msg]} {
puts "$attr: $msg"
}
}
if {$epdatanew ne {}} {
if {[catch {$ts storeepisode $epdatanew} msg]} {
puts "ts::storeepisode: $msg"
}
}
if {"$dir/$newfile.ts" ne "$file"} { ts renamegroup $file $newfile }
} else {

View File

@ -10,6 +10,18 @@ var plugins = {
dmenu_prepare: {}
};
// pattern matches directory path prefix
var pathre = /.*\/|\.[^.]*$/g;
// IDs of size, img elements for folders use RFC4648 s5 encoding of name
function folderID(folder)
{
return btoa(escape(folder))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
}
function blockpage(msg)
{
if (!msg)
@ -105,23 +117,21 @@ function epginfo_callback(data, status, xhr)
$('#rename_synopsis').val(data.synopsis);
$('#rename_guidance').val(data.guidance);
$('#rename_genre').val(data.genre);
$('#rename_seriesnum').val(data.seriesnum);
$('#rename_episodenum').val(data.episodenum);
$('#rename_episodetot').val(data.episodetot);
$('tr.tstype').show('slow');
}
function insert_folder_size(folder, size)
{
folder = folder.replace(/ /g, '');
folder = folder.replace(/([ #;&,.+*~\':"!^$[\]()=>|\/@])/g, '\\$1');
// folder = folder.replace(/([ #;&,.+*~\':"!^$[\]()=>|\/@])/g, '\\$1');
size += (size.search(/\d$/) == -1 ? 'iB' : ' bytes');
folder = folderID(folder);
//console.log("Folder: (%s) = (%s)", folder, size);
if (size.search(/\d$/) == -1)
size += 'iB';
else
size += ' bytes';
if (folder == "")
$('#dirsize').text(' (' + size + ')');
else
$('#' + folder).text(' (' + size + ')');
$(folder == "" ? '#dirsize' : '#ID' + folder)
.text(' (' + size + ')');
}
function folder_size_callback(data, status, xhr)
@ -133,11 +143,9 @@ function folder_size_callback(data, status, xhr)
function set_folder_new(folder, cnt)
{
folder = folder.replace(/ /g, '');
folder = folder.replace(/([ #;&,.+*~\':"!^$[\]()=>|\/@])/g, '\\$1');
//console.log("Folder: (%s) = (%s)", folder, cnt);
left = cnt > 99 ? 11 : (cnt > 9 ? 14 : 17);
$('#img' + folder)
$('#img' + folderID(folder))
.attr('src', '/img/Folder_New.png')
.next('span.foldernum')
.css('left', left + 'px')
@ -156,10 +164,8 @@ function new_folder_callback(data, status, xhr)
function set_folder__(folder)
{
folder = folder.replace(/ /g, '');
folder = folder.replace(/([ #;&,.+*~\':"!^$[\]()=>|\/@])/g, '\\$1');
//console.log("Folder: (%s)", folder);
$('#img' + folder + ' ~ span.folderu').show();
$('#img' + folderID(folder) + ' ~ span.folderu').show();
}
function __folder_callback(data, status, xhr)
@ -256,7 +262,7 @@ var $confirm; // Populated after DOM is loaded.
function confirm_action(action, callback, file, type, id)
{
var bfile = file.replace(/.*\/|\.[^.]*$/g, '');
var bfile = file.replace(pathre, '');
$confirm.dialog('option', 'buttons', {
'Yes': function() { $(this).dialog('close');
callback(file, type, id); },
@ -429,7 +435,7 @@ var menuclick = function(action, el, pos)
{
var file = $(el).parent().prevAll('a.bf').last().attr('file');
var efile = encodeURIComponent(file);
var bfile = file.replace(/.*\/|\.[^.]*$/g, '');
var bfile = file.replace(pathre, '');
bfile = bfile.replace(/[\x00-\x1f]+/g, '');
var type = $(el).attr('type');
var id = $(el).attr('did');

View File

@ -30,3 +30,8 @@ img.qb
color: #ff4000;
}
input.uint8_t
{
width: 6ch;
}

View File

@ -19,7 +19,7 @@ foreach arg $argv {
lappend dirs $arg
}
}
if {![llength $dirs]} { lappend dirs [exec pwd] }
if {![llength $dirs]} { lappend dirs [pwd] }
foreach dir $dirs {
if {[string index $dir end] eq "/"} {

View File

@ -46,12 +46,16 @@ There are no tasks in the queue.
</tbody>
</table>
<div class=buttonbar>
<button id=selcomplete class=needsdata>Select Completed</button>
<button id=selfailed class=needsdata>Select Failed</button>
<button id=selpending class=needsdata>Select Pending</button>
<button id=selall class=needsdata>Select All</button>
<button id=selnone class=needsdata>Select None</button>
</div>
<div class=buttonbar>
<button id=qdelete act=delete class="submit needssel">Delete</button>
<button id=qresubmit act=resubmit class="submit needssel">Re-submit</button>
<button id=qhold act=hold class="submit needssel">Hold</button>
<button id=selcomplete class=needsdata>Select Completed</button>
<button id=selall class=needsdata>Select All</button>
<button id=selnone class=needsdata>Select None</button>
<button class=refresh id=refresh>Refresh</button>
<span class=isloading><img src=/img/spin.gif></span>
</div>

View File

@ -40,7 +40,8 @@ function load()
$('<td>').append($('<a>', {
'class': 'file',
href: '#',
html: v.file
html: v.file,
title: v.file
})).appendTo($row);
$('<td>', { html: v.action + ' ' + v.args })
.appendTo($row);
@ -162,6 +163,18 @@ $('#selall').button({icons:{primary:"ui-icon-star"}})
$('#queuetab input:checkbox').prop('checked', true).trigger('change');
});
$('#selpending').button({icons:{primary:"ui-icon-check"}})
.on('click', function() {
$('#queuetab input:checkbox[status="PENDING"]').prop('checked', true)
.trigger('change');
});
$('#selfailed').button({icons:{primary:"ui-icon-check"}})
.on('click', function() {
$('#queuetab input:checkbox[status="FAILED"]').prop('checked', true)
.trigger('change');
});
$('#selcomplete').button({icons:{primary:"ui-icon-check"}})
.on('click', function() {
$('#queuetab input:checkbox[status="COMPLETE"]').prop('checked', true)

View File

@ -1,3 +1,10 @@
/* constrain File column width */
td:nth-child(3), th:nth-child(3)
{
max-width: 50ch;
overflow: hidden;
text-overflow: ellipsis;
}
td.status
{

View File

@ -1 +0,0 @@
img/fav/favicon.ico

Before

Width:  |  Height:  |  Size: 19 B

After

Width:  |  Height:  |  Size: 10 KiB

BIN
webif/html/favicon.ico Normal file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 B

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -28,6 +28,7 @@ if {[cgi_get act] eq "cryptokey"} {
set pkgdev [$settings pkgdev]
set rtschedule [$settings rtschedule]
set noautoremove [$settings noautoremove]
set logsize [$settings logsize]
set logkeep [$settings logkeep]
set logage [$settings logage]
@ -44,6 +45,7 @@ if {![catch {set ck_fd [open "/mod/boot/cryptokey"]}]} {
handle_int_update pkgdev $pkgdev "Development Package Display"
handle_int_update rtschedule $rtschedule "Real-time scheduling"
handle_int_update noautoremove $noautoremove "Package auto-remove"
handle_int_update logsize $logsize "Log rotation size"
handle_int_update logkeep $logkeep "Logs to keep"
handle_int_update logage $logage "Rotated log max age"

View File

@ -16,6 +16,9 @@ if {[system nuggeted]} {
setting_toggle "Real-time scheduling?" "rtschedule" $rtschedule
}
setting_toggle "Automatically remove unneeded dependent packages?" \
"noautoremove" $(!$noautoremove) 1
puts -nonewline "
<tr>
<form class=auto id=logsize method=get action=$env(SCRIPT_NAME)>

View File

@ -263,6 +263,15 @@ foreach e $records {
if {$es < $le} continue
set perc [$e percent]
set showing 0
if {$perc > 0 && $perc < 100} { set showing 1 }
set txt [list [cgi_quote_html [$e get name]] "([\
clock format $es -format "%H:%M"] - [\
clock format $ee -format "%H:%M"])[\
expr {$showing ? " ($perc%)" : ""}]"]
if {$es < $stt} { set es $stt }
if {$ee > $ett} { set ee $ett }
@ -292,21 +301,6 @@ foreach e $records {
set recopts 1
if {[$e get series_crid] ne ""} { set recopts 2 }
set perc [$e percent]
set showing 0
if {$perc > 0 && $perc < 100} { set showing 1 }
set txt "[cgi_quote_html [$e get name]] <span>([\
clock format $es -format "%H:%M"] - [\
clock format $ee -format "%H:%M"])"
if {$showing} { append txt " ($perc%)" }
append txt "</span>"
set htxt "[cgi_quote_html [$e get name]] ([\
clock format $es -format "%H:%M"] - [\
clock format $ee -format "%H:%M"])"
if {$showing} { append hxt " ($perc%)" }
set lbg $bg
# Set backround if scheduled. 1 1-off, 2 series, 3 recorded, 4 skipped
switch -- [$e scheduled] {
@ -318,11 +312,11 @@ foreach e $records {
}
puts "<div class=\"xeprog $lbg\"
style=\"width: [expr $px - 4]px;\" title=\"$htxt\">
style=\"width: [expr $px - 4]px;\" title=\"[join $txt]\">
<a class=event href=# xs=[$e get service_id]
xe=[$e get event_id] sch=[$e get sched_type]
rec=$recopts>"
puts $txt
puts [format "%s <span>%s</span>" {*}$txt]
puts "</a>"
puts "</div>"
}

View File

@ -99,7 +99,7 @@ div.xeprog
float: left;
vertical-align: middle;
height: 25px;
padding: 4px 0 3px 2px;
padding: 4px 0 3px 0px;
margin: 3px 0 3px 2px;
border: 1px solid #ccc;
border-radius: 10px;

View File

@ -94,6 +94,13 @@ proc ::decrypt::dequeue {q ts} {
::auto::startclock
log " DECRYPT: $rfile" 0
if {$mode eq "dlna"} {
if {[$ts getkey $mode] eq ""} {
::auto::log "system key doesn't match, trying direct"
set mode direct
}
}
if {$mode eq "dlna"} {
log " DLNA: $url" 0
if {[catch {exec wget -O "$tmp/$bfile" $url} msg opts]} {
@ -104,24 +111,12 @@ proc ::decrypt::dequeue {q ts} {
if {$helper} { system dlnahelper -release }
} else {
log " Direct decryption" 0
set keys {}
if {![catch {set fd [open "/mod/boot/cryptokey"]}]} {
set bytes [$fd read 16]
$fd close
binary scan $bytes H* key
if {[string length $key] == 32} {
lappend keys $key
}
}
lappend keys [string range [system nugget cryptokey -key] 0 31]
lappend keys [system encryptionkey]
foreach key $keys {
::auto::log "Testing key ($key)" 2
if {[catch {
set ret [exec /mod/bin/stripts -q/ $key $rfile]
}]} continue
if {$ret eq "1"} break
set key [$ts getkey $mode]
if {$key eq ""} {
return {"FAILED" "No matching key for decryption"}
}
::auto::log "Using key ($key)" 2
if {[catch {exec /mod/bin/stripts -@ $key $rfile "$tmp/[\
file rootname $bfile]" } msg opts]} {

View File

@ -1,7 +1,7 @@
require system.class plugin
if {![exists -proc class]} { package require oo }
if {![exists -command class]} { package require oo }
class dir {}
class browse {}

View File

@ -1,5 +1,5 @@
if {![exists -proc class]} { package require oo }
if {![exists -command class]} { package require oo }
class clipboard {
path "/tmp/webif.cb"

View File

@ -1,7 +1,7 @@
source /mod/webif/lib/setup
if {![exists -proc class]} { package require oo }
if {![exists -proc sqlite3.open]} { package require sqlite3 }
if {![exists -command class]} { package require oo }
if {![exists -command sqlite3.open]} { package require sqlite3 }
require settings.class progressbar rsv.class mwildcard svc.class
@ -482,7 +482,7 @@ proc {epg dbfetch} {mode args} {
append q "and (e.start is null or
(e.start > $stt and e.start < $ett) or
(e.end > $stt and e.end < $ett) or
(e.start < $stt and e.end > $stt)
(e.start <= $stt and e.end >= $ett)
) "
}
-fav {

View File

@ -1,5 +1,5 @@
if {![exists -proc class]} { package require oo }
if {![exists -command class]} { package require oo }
class pkg {
name ""
@ -128,7 +128,7 @@ pkg method loadraw {} {
} else {
set data [exec /bin/opkg info $name]
}
foreach line [split $data "\n"] {
if {$tag ne "" && [string match { *} $line]} {
append raw($tag) $line
@ -237,7 +237,7 @@ proc {pkg fetchfile} {url} {
#puts "Web Header: $line"
set line [string trim [$f gets]]
}
# Save the body
set ret [$f read]
$f close

View File

@ -1,6 +1,6 @@
if {![exists -proc class]} { package require oo }
if {![exists -proc sqlite3.open]} { package require sqlite3 }
if {![exists -command class]} { package require oo }
if {![exists -command sqlite3.open]} { package require sqlite3 }
class queue {
id -1
@ -53,77 +53,127 @@ proc {queue dbhandle} {args} {
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,
file text,
action text,
args text,
start integer default 0,
status text default 'PENDING',
log text default '',
runtime integer,
retries integer default 0,
interrupts integer default 0,
submitted integer default 0,
last integer default 0
);
try {
set db [sqlite3.open /mod/etc/queue.db]
} on error {msg} {
stderr puts $msg
return 0
}
if {[catch {$db query { select count(*) from queue, config; }}]} {
catch {$db {drop table queue}}
catch {$db {drop table config}}
try {
$db query {
create table queue(
id integer primary key autoincrement,
file text,
action text,
args text,
start integer default 0,
status text default 'PENDING',
log text default '',
runtime integer,
retries integer default 0,
interrupts integer default 0,
submitted integer default 0,
last integer default 0
);
}
$db query {
create table config(
var text,
val text
);
}
$db query {
insert into config values('version', 3);
}
$db query {
create unique index file on queue(file, action);
}
} on error {msg opts} {
stderr puts $msg
catch {$db close}
return 0
}
$::queue::db query {
create table config(
var text,
val text
);
}
$::queue::db query {
insert into config values('version', 3);
}
$::queue::db query {
create unique index file on queue(file, action);
}
} else {
set ::queue::db [sqlite3.open /mod/etc/queue.db]
}
return $::queue::db
return [set ::queue::db $db]
}
proc {queue dbquery} {query args} {
set db [queue dbhandle]
try {
return [$db query $query {*}$args]
} on error {msg opts} {
return {}
}
}
proc {queue dbaction} {query args} {
set db [queue dbhandle]
try {
$db query $query {*}$args
return true
} on error {msg opts} {
return false
}
}
proc {queue dbqueryl} {query_list {txn_mode ""}} {
set db [queue dbhandle]
try {
if {$txn_mode ne ""} {
if {$txn_mode ni { immediate exclusive }} {
set txn_mode "deferred"
}
$db query "begin %s transaction" $txn_mode
}
foreach q $query_list {
$db query {*}$q
}
if {$txn_mode ne ""} {
$db query "commit transaction"
}
return true
} on error {msg opts} {
}
if {$txn_mode ne ""} {
catch { $db query "rollback transaction" }
}
return false
}
proc {queue startup} {{days 7}} {
if {$days == 0} { set days 7 }
set db [queue dbhandle]
$db query {
return [queue dbqueryl { { {
update queue
set status = 'INTERRUPTED',
log = 'Job will be retried automatically.',
retries = retries + 1,
interrupts = interrupts + 1
where status = 'RUNNING'
}
$db query {
} } { {
update queue
set status = 'FAILED',
log = 'Too many interrupts.'
where status = 'INTERRUPTED'
and interrupts >= 5
}
$db query {
} } { {
update queue
set status = 'PENDING'
where status = 'DEFER'
}
$db query {
} } { {
delete from queue
where status in ('COMPLETE', 'FAILED')
and submitted < %s
} [expr [clock seconds] - 86400 * $days]
} } ]
}
proc {queue fetch} {file action} {
set db [queue dbhandle]
foreach row [$db query {
foreach row [queue dbquery {
select * from queue
where file = '%s'
and action = '%s'
@ -134,23 +184,23 @@ proc {queue fetch} {file action} {
}
proc {queue insert} {args file action} {
set db [queue dbhandle]
set status "PENDING"
if {"-hold" in $args} { set status "HOLD" }
set file [queue key $file]
$db query {
if {[queue dbaction {
insert or ignore into queue(submitted, file, action, status)
values(%s, '%s', '%s', '%s')
} [clock seconds] $file $action $status
} [clock seconds] $file $action $status]} {
return [queue fetch $file $action]
return [queue fetch $file $action]
}
return 0
}
proc {queue delete} {file {action "*"}} {
set db [queue dbhandle]
set q "
delete from queue
@ -161,11 +211,10 @@ proc {queue delete} {file {action "*"}} {
append q " and action = '%s'"
}
$db query $q [queue key $file] $action
return [queue dbaction $q [queue key $file] $action]
}
proc {queue delete_by_id} {id} {
set db [queue dbhandle]
set q "
delete from queue
@ -173,11 +222,10 @@ proc {queue delete_by_id} {id} {
and status != 'RUNNING'
"
$db query $q $id
return [queue dbaction $q $id]
}
proc {queue resubmit} {id} {
set db [queue dbhandle]
set q "
update queue
@ -186,11 +234,10 @@ proc {queue resubmit} {id} {
and status in ('FAILED', 'HOLD', 'COMPLETE')
"
$db query $q $id
return [queue dbaction $q $id]
}
proc {queue hold} {id} {
set db [queue dbhandle]
set q "
update queue
@ -199,15 +246,13 @@ proc {queue hold} {id} {
and status not in ('RUNNING', 'COMPLETE')
"
$db query $q $id
return [queue dbaction $q $id]
}
proc {queue status} {file} {
if {$file eq "0"} { return "" }
set db [queue dbhandle]
set ret [$db query {
set ret [queue dbquery {
select group_concat(action)
from queue
where file = '%s'
@ -230,10 +275,9 @@ proc {queue check} {file {q "any"}} {
}
proc {queue all} {} {
set db [queue dbhandle]
set ret {}
foreach row [$db query {select * from queue order by id}] {
foreach row [queue dbquery {select * from queue order by id}] {
lappend ret [queue new $row]
}
return $ret
@ -243,7 +287,7 @@ proc {queue pending} {} {
set db [queue dbhandle]
set ret {}
foreach row [$db query {
foreach row [queue dbquery {
select * from queue
where status in ('PENDING', 'INTERRUPTED')
and start < %s
@ -259,23 +303,20 @@ proc {queue size} {} {
}
proc {queue version} {} {
set db [queue dbhandle]
set version 1
catch {
foreach row [$db query {
foreach row [queue dbquery {
select val from config
where var = 'version'
}] {
lassign $row x version
}
lassign $row x version
}
return $version
}
queue method update {_status {_log ""} {_retries 0} {_runtime 0}} {
set db [queue dbhandle]
$db query {
if {[queue dbaction {
update queue
set status = '%s',
log = '%s',
@ -283,22 +324,27 @@ queue method update {_status {_log ""} {_retries 0} {_runtime 0}} {
runtime = %s,
last = %s
where id = %s
} $_status $_log $_retries $_runtime [clock seconds] $id
} $_status $_log $_retries $_runtime [clock seconds] $id]} {
set status $_status
set log $_log
incr retries $_retries
set runtime $_runtime
set status $_status
set log $_log
incr retries $_retries
set runtime $_runtime
return true
}
return false
}
queue method set {var val} {
set db [queue dbhandle]
$db query {
if {[queue dbaction {
update queue
set %s = '%s'
where id = %s
} $var $val $id
set $var $val
} $var $val $id]} {
set $var $val
}
return $var
}
queue method submit {{_start 0}} {

View File

@ -1,8 +1,8 @@
source /mod/webif/lib/setup
if {![exists -proc class]} { package require oo }
if {![exists -proc sqlite3.open]} { package require sqlite3 }
if {![exists -proc binary]} { package require binary }
if {![exists -command class]} { package require oo }
if {![exists -command sqlite3.open]} { package require sqlite3 }
if {![exists -command binary]} { package require binary }
require settings.class system.class plugin svc.class
set binaryfields aulEventToRecordInfo
@ -970,6 +970,7 @@ proc {rsv construct} {event type} {
set now [clock seconds]
set progs [lmap i [\
epg dbfetch dump -scrid [$event get series_crid] \
-service [$event get service_id] \
-sort start] {
if {[set ecrid [$i get event_crid]] eq ""} continue

View File

@ -1,6 +1,6 @@
if {![exists -proc class]} { package require oo }
if {![exists -proc sqlite3.open]} { package require sqlite3 }
if {![exists -command class]} { package require oo }
if {![exists -command sqlite3.open]} { package require sqlite3 }
if {![file exists /mod/etc/webif.db]} {
set ::settingsdb [sqlite3.open /mod/etc/webif.db]
@ -52,6 +52,7 @@ class settings {
logkeep 2
logage 0
rtschedule 0
noautoremove 0
}
proc {settings _safer_query} { queryText args } {
@ -257,6 +258,10 @@ settings method rtschedule {{val -1}} {
return [$self _nval_setting rtschedule $val]
}
settings method noautoremove {{val -1}} {
return [$self _nval_setting noautoremove $val]
}
settings method sortorder {{val -1}} {
return [$self _nval_setting sortorder $val]
}

View File

@ -1,7 +1,7 @@
source /mod/webif/lib/setup
if {![exists -proc class]} { package require oo }
if {![exists -proc sqlite3.open]} { package require sqlite3 }
if {![exists -command class]} { package require oo }
if {![exists -command sqlite3.open]} { package require sqlite3 }
require system.class
class svc {

View File

@ -3,9 +3,9 @@ source /mod/webif/lib/setup
package require xconv
if {![exists -proc class]} { package require oo }
if {![exists -proc sqlite3.open]} { package require sqlite3 }
if {![exists -proc binary]} { package require binary }
if {![exists -command class]} { package require oo }
if {![exists -command sqlite3.open]} { package require sqlite3 }
if {![exists -command binary]} { package require binary }
class system {}
@ -316,7 +316,7 @@ proc {system dlnaurl} {file {urlbase "127.0.0.1"}} {
return $ret
}
proc {system dlnahelper} {file {urlbase ""}} {
proc {system dlnahelper} {file {urlbase "127.0.0.1"}} {
set dir /mnt/hd2/mod/.dlnahelper
require lock
@ -405,6 +405,22 @@ proc {system disktemp} {} {
return $($temp + 0)
}
proc {system tsrdir} {} {
switch [system model] {
HDR {
set tsrdir "/mnt/hd2/Tsr"
}
HD {
set tsrdir "/media/drive1/.tsr"
}
}
return $tsrdir
}
proc {system tsr} {} {
return [file join [system tsrdir] "0.ts"]
}
require pretty_size
proc {system diskspace} {{raw 0}} {
@ -419,13 +435,12 @@ proc {system diskspace} {{raw 0}} {
set perc $($used * 100 / $size)
set fperc $(100 - $perc)
set tsrdir [system tsrdir]
switch [system model] {
HDR {
set tsrdir "/mnt/hd2/Tsr"
set tsrok [file isdirectory $tsrdir]
}
HD {
set tsrdir "/media/drive1/.tsr"
set tsrok [file exists "$tsrdir/0.ts"]
}
}

View File

@ -1,7 +1,9 @@
if {![exists -proc class]} { package require oo }
if {![exists -proc pack]} { package require pack }
if {![exists -proc xconv]} { package require xconv }
if {![exists -command class]} { package require oo }
if {![exists -command pack]} { package require pack }
if {![exists -command xconv]} { package require xconv }
if {![exists -command binary]} { package require binary }
source /mod/webif/lib/setup
require system.class tvdb.class classdump
@ -296,21 +298,21 @@ ts method copy {dst} {
}
ts method settitle {newtitle} {
if {[string length newtitle] > 48} { return }
if {[string length $newtitle] > 48} { return }
exec /mod/bin/hmt "+settitle=${newtitle}" $file
set title $newtitle
}
ts method setsynopsis {newsynopsis} {
if {[string length newsynopsis] > 252} { return }
if {[string length $newsynopsis] > 252} { return }
exec /mod/bin/hmt "+setsynopsis=${newsynopsis}" $file
set synopsis $newsynopsis
}
ts method setguidance {newguidance} {
if {[string length newguidance] > 48} { return }
if {[string length $newguidance] > 74} { return }
if {$newguidance eq ""} {
exec /mod/bin/hmt "-guidance" $file
@ -537,7 +539,7 @@ proc {ts resetnew} {dir} {
#hexdump $bytes
#puts "Calculated: $watched/$tot"
pack bytes $tot -intle 32 0
pack bytes $tot -intle 32 0
pack bytes $watched -intle 32 32
#hexdump $bytes
@ -773,7 +775,7 @@ ts method episode_name {} {
incr flag
}
if {$flag} { $self storeepisode }
return $tvdb_data(name)
}
@ -815,7 +817,8 @@ ts method tsr {} {
}
ts method genrenib {} {
return $($genre >> 4)
if {[catch {set v $($genre >> 4)}]} { set v 0 }
return $v
}
ts method genre_info {} {
@ -838,3 +841,56 @@ proc {ts genrelist} {} {
return $glist
}
# return the key that will decrypt the file in the mode, or nothing
ts method getkey {mode} {
# mode: dlna (active key), direct
set rfile [file rootname $file]
set keys {}
# the active key
set key [string range [system nugget cryptokey -key] 0 31]
if {$key ne ""} {
lappend keys $key
}
if { $mode ne "dlna" } {
# also try other keys, such as this - same as active?
try {
set fd [open "/mod/boot/cryptokey"]
set bytes [$fd read 16]
binary scan $bytes H* key
if {[string length $key] == 32} {
ladd keys $key
}
} finally {
catch {$fd close}
}
# the native key
if {![catch {set key [system encryptionkey]}]} {
ladd keys $key
}
# support a file listing other keys in hex, one-per-line
# eg, for recordings imported from a broken box
try {
set fd [open "/mod/etc/keys" r]
foreach key [split [$fd read -nonewline] "\n"] {
ladd keys $key
}
} finally {
catch {$fd close}
}
}
foreach key $keys {
if {[catch {
set ret [exec /mod/bin/stripts -q/ $key $rfile]
}]} continue
if {$ret eq "1"} {
return $key
}
}
return
}

View File

@ -1,8 +1,8 @@
source /mod/webif/lib/setup
package require cgi
if {![exists -proc class]} { package require oo }
if {![exists -proc sqlite3.open]} { package require sqlite3 }
if {![exists -command class]} { package require oo }
if {![exists -command sqlite3.open]} { package require sqlite3 }
require system.class xml.class
set ::tvdb::apikey 1764335F804A5A91

View File

@ -20,3 +20,98 @@ proc midnight {} {{today ""}} {
return [clock scan "$today 00:00:00" -format "%Y %m %d %T"]
}
# Base-64 according to RFC 4648
# See https://wiki.tcl-lang.org/page/base64
if {![exists -command binary]} { package require binary }
# RFC 4648 section 4
set ::b64::map {
000000 A 000001 B 000010 C 000011 D 000100 E 000101 F
000110 G 000111 H 001000 I 001001 J 001010 K 001011 L
001100 M 001101 N 001110 O 001111 P 010000 Q 010001 R
010010 S 010011 T 010100 U 010101 V 010110 W 010111 X
011000 Y 011001 Z 011010 a 011011 b 011100 c 011101 d
011110 e 011111 f 100000 g 100001 h 100010 i 100011 j
100100 k 100101 l 100110 m 100111 n 101000 o 101001 p
101010 q 101011 r 101100 s 101101 t 101110 u 101111 v
110000 w 110001 x 110010 y 110011 z 110100 0 110101 1
110110 2 110111 3 111000 4 111001 5 111010 6 111011 7
111100 8 111101 9 111110 + 111111 /
}
set ::b64::unmap [join [lmap {a b} $::b64::map {list $b $a}]]
proc ::b64::encode {str} {
binary scan $str B* bits
switch [expr {[string length $bits]%6}] {
0 {set tail {}}
2 {append bits 0000; set tail ==}
4 {append bits 00; set tail =}
}
return [string cat [string map $::b64::map $bits] $tail]
}
proc ::b64::decode {str} {
set nstr [string trimright $str =]
set dstr [string map $::b64::unmap $nstr]
switch [expr [string length $str]-[string length $nstr]] {
0 {#nothing to do}
1 {set dstr [string range $dstr 0 {end-2}]}
2 {set dstr [string range $dstr 0 {end-4}]}
}
return [binary format B* $dstr]
}
# RFC 4648 section 5
proc ::b64::url_encode {str} {
tailcall string map {+ - / _ = ""} [::b64::encode $str]
}
proc ::b64::url_decode {str} {
tailcall ::b64::decode [string map {- + _ /} $str]
}
alias b64encode ::b64::encode
alias b64decode ::b64::decode
alias b64uencode ::b64::url_encode
alias b64udecode ::b64::url_decode
# ECMA-262 Annex B.2.1
proc ::js::_escape {str} {
return [join [lmap c [split $str ""] {
if {1 != [scan $c "%c" cc]} {
format "%s" $c
} elseif {$cc < 256} {
format "%%%02X" $cc
} else {
format "%%u%04X" $cc
}
}] ""]
}
proc ::js::_unescape {str} {
if {1 == [scan $str "%%%2x" cc] ||
1 == [scan $str "%%u%4x" cc]} {
return [format "%c" $cc]
} else {
return $str
}
}
proc ::js::escape {str} {
return [subst -nobackslashes -novariables \
[regsub -all -- {[^A-Za-z0-9@*_+-./]+} $str \
{[::js::_escape {&}]}]]
}
proc ::js::unescape {str} {
return [subst -nobackslashes -novariables \
[regsub -all -- {%(u[[:xdigit:]]{2})?[[:xdigit:]]{2}} $str \
{[::js::_unescape {&}]}]]
}
alias jsescape ::js::escape
alias jsunescape ::js::unescape

View File

@ -2,7 +2,7 @@
# From https://wiki.tcl-lang.org/page/Parsing+XML
# Keith Vetter 2004-03-01
if {![exists -proc class]} { package require oo }
if {![exists -command class]} { package require oo }
class xml {
xml ""