Compare commits

...

44 Commits

Author SHA1 Message Date
HummyPkg c7a91766af Fix bookmark script.js 2021-02-24 18:39:52 +00:00
HummyPkg d00f925e58 Update version 2021-02-24 18:14:44 +00:00
HummyPkg fc3b28e978 Add option to automatically remove unused dependency packages 2021-02-24 18:14:44 +00:00
prpr c4afa7ac60 Add Failed and Pending select buttons, reorder buttons 2021-02-24 15:13:35 +00:00
Bob Buxton 3c3b0af49f Move favicon.ico to prevent errors during install 2021-02-24 14:54:59 +00:00
prpr f206766191 Work around uclibc getaddrinfo() 2021-02-24 14:47:11 +00:00
prpr 67afb37f27 Fix crash when genre is null 2021-02-24 14:46:37 +00:00
prpr ad150143a8 Fix overflowing conflict warning 2021-02-24 14:44:55 +00:00
df 5d3b046c70 Improve status, adding more possible outputs
- check for copying vs playing: the same file.ext is open twice
 - check for playing DLNA: localhost:n->host:9000
 - on HDR, distinguish Playing a show vs streaming it over DLNA
 - distinguish between Watching, Watching (delayed) (timeshift),
   and Not Watching (eg Portal).
2021-02-24 13:58:46 +00:00
df 18bed926b3 Support setting the seriesnum, episodenum, episodetot attributes in "rename" 2021-02-24 13:39:35 +00:00
df 1c868ae201 Add thumbnail viewer to Manage Bookmarks 2021-02-24 13:33:35 +00:00
HummyPkg 4820ade1f5 Fix problems pointed out by tclCheck and frink 2021-02-24 13:21:19 +00:00
Bob Buxton bc2e6c1a85 Restrict matching epsiodes search to same channel 2021-02-24 13:15:06 +00:00
df 6f45884f94 Add test for matching key for DLNA; fallback to direct; fail if no key matches 2021-02-24 13:13:01 +00:00
af123 a1cf871a84 Merge pull request 'Correctly manage maximum lengths of certain HMT fields' (#30) from df/webif:df-hmtfieldlength-patch into master
Reviewed-on: #30
2021-02-24 13:04:14 +00:00
df 7834dae075 Error protect database access; re-create corrupt queue DB. 2021-02-24 12:55:52 +00:00
af123 15cba14cc3 Merge pull request 'df-dlnahelper-patch' (#23) from df/webif:df-dlnahelper-patch into master
Reviewed-on: #23
2021-02-24 12:48:31 +00:00
af123 3f74654ea2 Merge pull request 'df-queuetablewidth-patch' (#24) from df/webif:df-queuetablewidth-patch into master
Reviewed-on: #24
2021-02-24 12:46:50 +00:00
df f16399ec2f exists -proc -> exists -command
`exists -command` subsumes `exists -proc`

This test is generally checking whether the command exists, rather than some proc that is overriding it.

Currently `class` is a proc but this may not always be so.
2021-02-24 12:45:30 +00:00
df 0060e47db5 Remove unwanted padding before programme divs in EPG to avoid cumulative positioning error. 2021-02-24 12:40:45 +00:00
df 8bdb1233e8 Display raw programme times, not clipped to the display period. 2021-02-24 12:40:45 +00:00
df 2642b190b0 Fix typo and < vs <= in `dbfetch -trange` option: avoids missing channels in EPG. 2021-02-24 12:40:44 +00:00
df 8975cbd71d Also use non-breaking spaces in file name display 2021-02-24 12:38:39 +00:00
df 32ac3c8421 Fix quoting of replacement text, avoiding "unmatched ]" 2021-02-24 12:38:39 +00:00
df f5180dc144 Improve listing of directories with special characters, especially spaces. 2021-02-24 12:38:39 +00:00
df dac3ea8698 Remove unnecessary exec
Jim supports the pwd command since at least 6461e8bf6d, so no need to exec it.
2021-02-24 12:38:38 +00:00
df 4ae8ea85f7 Ensure cut plan segments are aligned left 2021-02-24 12:24:33 +00:00
df 47495e7b8d Avoid negative CSS widths 2021-02-24 12:24:33 +00:00
df 73d25247f0 Check that bookmark save succeeded
If not, enable the old "Save new bookmarks" button.

Also
* add icons for buttons
* simplify invert URL handling.
2021-02-24 12:24:32 +00:00
df f7c37e83ae Allow minimum width for cut plan
Also
* add ID for estimated time row
* make the <label> for the Save Bookmarks checkbox actually be its label.
2021-02-24 12:15:33 +00:00
df cf407f9a80 Correct the maximum length enforced for guidance text (74 vs 48) 2021-02-22 19:31:20 +00:00
df d98217b679 Merge branch 'master' into df-hmtfieldlength-patch 2021-02-22 16:35:49 +00:00
HummyPkg 269f844f43 Add to episode parsing tests 2021-01-18 23:10:16 +00:00
HummyPkg 488961c600 Update version 2021-01-18 23:00:37 +00:00
HummyPkg a5f0734201 Update tvdb XML parsing utility 2021-01-18 22:59:58 +00:00
af123 94849c51e7 Merge pull request 'Avoid displaying negative free space' (#28) from df/webif:df-freespace-patch into master
Reviewed-on: #28
2021-01-14 21:04:15 +00:00
af123 907d9d8dcf Merge pull request 'Understand Part/Pt. as a synonym for episode' (#31) from df/webif:df-partasepisode-patch into master
Reviewed-on: #31
2021-01-14 21:03:22 +00:00
df 6641b6f458 Understand Part/Pt. as a synonym for episode 2021-01-01 22:33:14 +00:00
df 98ef6a876f Add missing $ for certain variable references
Missing $s invalidated attempts to check the length of title, synopsis, guidance.
2020-12-31 15:22:42 +00:00
df d05f841bb4 Reduce (or apply) maximum lengths for title and synopsis, allowing for character set prefix byte 2020-12-31 15:18:03 +00:00
df 4da3bb0209 Banish extraneous ) 2020-12-31 12:13:52 +00:00
df 0ad1491634 Avoid displaying negative free space 2020-12-11 11:18:58 +00:00
df da32aa0a72 Set maximum width for File column
Add title attribute to display possibly truncated File as tooltip.

Will this work well for mobile/touchscreen use?
2020-11-14 13:31:08 +00:00
df f6117a4ec0 Make 127.0.0.1 the default host for `system dlnahelper`
In all the cases where `system dlnahelper` is called, no host/IP part is specified, and those cases are creating a URL that only needs to be accessible from the same machine, where the loopback address should be the default.

Should fix eg https://hummy.tv/forum/threads/detectads-not-always-succesful.9936/post-147241.
2020-11-14 13:21:26 +00:00
41 changed files with 812 additions and 256 deletions

View File

@ -1,7 +1,7 @@
Package: webif
Priority: optional
Section: web
Version: 1.4.8-11
Version: 1.4.9-1
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

@ -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
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
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]
}
}
}

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 += new Date(null, null, null, null, null, v)
.toTimeString().match(/\d{2}:\d{2}:\d{2}/)[0] + ' ';
t += toTimeStr(v);
});
$('#slider .ui-slider-handle').each(function(i) {
$(this).attr('title', toTimeStr(values[i]));
});
}
$('#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();
@ -73,9 +74,9 @@ $('#cropit').button().click(function() {
});
});
$('#invert').button().on('click', function() {
window.location = 'crop.jim?file=' +
escapestring($('#params').attr('file')) +
$('#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]]
@ -174,7 +177,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>
"
@ -362,7 +365,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

@ -105,14 +105,22 @@ 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');
// ID of size element is ID + RFC4648 s5 encoding of folder name
folder = "ID" +
btoa(escape(folder))
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
//console.log("Folder: (%s) = (%s)", folder, size);
if (size.search(/\d$/) == -1)
size += 'iB';

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

@ -9,6 +9,11 @@ lassign [system diskspace 1] size used perc free fperc tsrbuf tsrused
set tsrreserve $($tsrbuf - $tsrused)
# Adjust values to account for the TSR reserve
set free $($free - $tsrreserve)
# In case the reserve has been over-committed
if {$free < 0} {
# avoid displaying negative free, or used > available
set free 0
}
set used $($size - $free)
set dbs 0

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]} {

Binary file not shown.

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 ""
@ -225,7 +225,7 @@ proc {pkg loaddiagmeta} {} {
}
proc {pkg fetchfile} {url} {
set f [socket stream hpkg.tv:80]
set f [socket stream hpkg.tv:http]
$f puts -nonewline "GET /hdrfoxt2/$url HTTP/1.1\r\n"
$f puts -nonewline "Host: hpkg.tv\r\n"
$f puts -nonewline "Connection: close\r\n"

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,9 +53,17 @@ 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 {
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,
@ -71,59 +79,101 @@ proc {queue dbhandle} {args} {
last integer default 0
);
}
$::queue::db query {
$db query {
create table config(
var text,
val text
);
}
$::queue::db query {
$db query {
insert into config values('version', 3);
}
$::queue::db query {
$db query {
create unique index file on queue(file, action);
}
} else {
set ::queue::db [sqlite3.open /mod/etc/queue.db]
} on error {msg opts} {
stderr puts $msg
catch {$db close}
return 0
}
}
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 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
}
}
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,23 +324,28 @@ 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
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
} $var $val $id]} {
set $var $val
}
return $var
}
queue method submit {{_start 0}} {
if {$_start} { $self set start $_start }

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 {}
@ -309,7 +309,7 @@ proc {system dlnaurl} {file {urlbase ""}} {
return $ret
}
proc {system dlnahelper} {file {urlbase ""}} {
proc {system dlnahelper} {file {urlbase "127.0.0.1"}} {
set dir /mnt/hd2/mod/.dlnahelper
require lock
@ -398,6 +398,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}} {
@ -412,13 +428,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

@ -18,6 +18,11 @@ foreach {sample expected} {
{(S8, Ep2)} {S8E2/0}
{(S4 Ep22/24)} {S4E22/24}
{23/27.} {S0E23/27}
{Part 5/10} {S0E5/10}
{Pt. 5/10} {S0E5/10}
{Part 5 of 10} {S0E5/10}
{Pt. 5 of10} {S0E5/10}
{Pt5} {S0E5/0}
} {
set ts [ts new "synopsis {$sample}"]
$ts episode_name

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
@ -697,6 +699,14 @@ ts method extract_numbers {} {
regexp -nocase -- {S\.*(\d+),?\s*Ep\.?\s*(\d+)(/(\d+))?} $synopsis \
x seriesnum episodenum x episodetot
# (Part 5/10)
# (Pt. 5/10)
# (Part 5 of 10)
# (Pt. 5 of 10)
# (Pt5)
regexp -nocase -- {P(art|t\.?)\s*(\d+)\s*(of|/)?\s*(\d+)?} $synopsis \
x x episodenum x episodetot
foreach v {seriesnum episodenum episodetot} {
if {[set $v] eq ""} {
set $v 0
@ -807,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 {} {
@ -830,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 ""