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 Package: webif
Priority: optional Priority: optional
Section: web Section: web
Version: 1.4.8-11 Version: 1.4.9-1
Architecture: mipsel Architecture: mipsel
Maintainer: af123@hpkg.tv 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 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]] [system tuners]]
if {[llength $conflicts]} { if {[llength $conflicts]} {
puts { 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. This event conflicts with the following items in your scheduled recording list.
<ul> <ul>
} }

View File

@ -2,7 +2,7 @@
package require cgi package require cgi
source /mod/webif/lib/setup source /mod/webif/lib/setup
require pkg.class system.class require pkg.class system.class settings.class
cgi_input cgi_input
#cgi_dump #cgi_dump
@ -61,6 +61,11 @@ if {$cmd eq "dependinfo"} {
} }
if {$cmd eq "upgrade"} { opkg update } if {$cmd eq "upgrade"} { opkg update }
if {$cmd eq "remove" && [[settings] noautoremove] ne "1"} {
append cmd " --autoremove"
}
opkg "$cmd $cmdargs" opkg "$cmd $cmdargs"
if {$cmd eq "update" || $cmd eq "upgrade"} { 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 set runmode cli
if {[string match {*jim} $argv0]} { set runmode cgi } if {[string match {*jim} $argv0]} { set runmode cgi }
set schedtime 1200 set schedtime 1200
switch $runmode { switch $runmode {
cgi { cgi {
set type [cgi_get type "full"] set type [cgi_get type "full"]
@ -15,8 +15,7 @@ switch $runmode {
} }
cli { cli {
set type "full" set type "full"
if {"-X" in $argv} { set schedtime 7200 } if {[lsearch -nocase $argv "-x"] >= 0} { set schedtime 7200 }
if {"-x" in $argv} { set schedtime 7200 }
} }
} }
@ -61,11 +60,11 @@ proc register_statusop {op name icon} {
eval_plugins status 1 eval_plugins status 1
proc get_data {} { proc get_data {} {
global pid exts global pid exts stream tsr tsrcnt
set ret {} set ret {}
if {[catch {set data \ 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" debug "Error: $msg"
set ret {} set ret {}
} else { } else {
@ -73,35 +72,64 @@ proc get_data {} {
foreach line [split $data "\n"] { foreach line [split $data "\n"] {
set typ [string index $line 0] set typ [string index $line 0]
switch $typ { switch $typ {
a {
set access [string index $line 1]
}
s { s {
set size [string range $line 1 end] set size [string range $line 1 end]
} }
n { n {
if {[string first Video/ $line] == -1 && \ # strip initial n and trailing " (...)" if
[string first /media/ $line] == -1} { # 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 continue
} }
regsub -- { \([^\)]+\)$} $line "" line
set ext [file extension $line] if {[string first Video/ $line] >= 0 ||
if {$ext ni $exts} continue [string first /media/ $line] >= 0} {
set file [subst -nocommands -novariables \ if {$ext ni $exts} {
[string range $line 1 end]] continue
# Skip HD-Fox TSR buffer }
if {$file eq "/media/drive1/.tsr/0.ts"} { } 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 continue
} }
# Handle chase play (same file open twice # Handle chase play (same file open twice
# and recently written) # and recently written)
if {[dict exists $ret $file] && \ if {[dict exists $ret $file] &&
$ext eq ".ts"} { $ext eq ".ts"} {
set age [expr [clock seconds] - \ set age [expr [clock seconds] \
[file mtime $file]] - [file mtime $file]]
if {$age < 60} { if {$age < 60} {
set ret($file) -1 set access [lindex \
[dict get $ret $file] 1]
set ret($file) [list -1 $access]
} }
} else { } else {
debug "$file = $size" debug "$file = $size,$access"
set ret($file) $size set ret($file) [list $size $access]
} }
} }
} }
@ -109,11 +137,9 @@ proc get_data {} {
} }
foreach file [dict keys $::ops] { foreach file [dict keys $::ops] {
if {![dict exists $ret $file]} { if {![dict exists $ret $file]} {
if {[file exists $file]} { set sz 0
set ret($file) [file size $file] if {[file exists $file]} { set sz [file size $file] }
} else { set ret($file) [list $sz u]
set ret($file) 0
}
} }
} }
return $ret return $ret
@ -139,9 +165,12 @@ proc add_output {icon mode name} {
set play 0 set play 0
set rec 0 set rec 0
set stream 0
set output {} set output {}
set ops {} set ops {}
set model [system model] set model [system model]
set tsr [file rootname [system tsr]]
set tsrcnt 0
foreach opfile [glob -nocomplain -directory /tmp -tails -- ".bgop.*"] { foreach opfile [glob -nocomplain -directory /tmp -tails -- ".bgop.*"] {
set op [string range $opfile 6 end] set op [string range $opfile 6 end]
@ -179,8 +208,9 @@ if {[llength $data]} {
debug " NDATA: ($ndata)" debug " NDATA: ($ndata)"
set rr 0 set rr 0
} }
set bnames [lsort [lmap x [array names data] { file tail $x }]]
foreach file [array names data] { foreach file [array names data] {
set bname [file rootname [file tail $file]] set bname [file tail $file]
set name [string map { set name [string map {
"/mnt/hd2/My Video/" "" "/mnt/hd2/My Video/" ""
@ -189,17 +219,22 @@ if {[llength $data]} {
".ts" "" ".ts" ""
} $file] } $file]
if {$data($file) == -1} { if {[lindex $data($file) 0] == -1} {
set mode chase set mode chase
} elseif {$rr} { } elseif {$rr} {
if {$file in $recs} { if {$file in $recs} {
set mode rec set mode rec
} elseif {[llength [\
lsearch -all $bnames $bname]] == 2} {
# two different files having same file.ext open
set mode copy
} else { } else {
set mode play set mode play
} }
} else { } else {
if {![dict exists $ndata $file]} continue if {![dict exists $ndata $file]} continue
if {$ndata($file) > $data($file)} { if {[lindex $ndata($file) 0] > \
[lindex $data($file) 0]} {
set mode rec set mode rec
} else { } else {
set mode play set mode play
@ -231,8 +266,20 @@ if {[llength $data]} {
} }
play { play {
incr play incr play
set mode "Playing" if {$play > $stream} {
set icon "745_1_10_Video_2Live.png" 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 { default {
if {[dict exists $statusops $mode]} { if {[dict exists $statusops $mode]} {
@ -272,23 +319,33 @@ if {![system instandby] && $play < 1} {
if {[llength $epgs] == 1} { if {[llength $epgs] == 1} {
lassign $epgs epg lassign $epgs epg
set prog "- [$epg get name] (" set prog "- [$epg get name] ("
append prog "[clock format [$epg get start] -format %H:%M] - " append prog "[clock format [\
append prog "[clock format $([$epg get start] + [$epg get duration]) -format %H:%M]" $epg get start] -format %H:%M] - "
append prog "[clock format $([$epg get start] \
+ [$epg get duration]) -format %H:%M]"
append prog ") \[[$epg percent]%\]" append prog ") \[[$epg percent]%\]"
} }
if {$runmode eq "cgi"} { # 0 => no TSR; >=2 => TSR
set s " if {$tsrcnt == 0 || $tsrcnt == 2} {
<span class=\"va stitem\"> set s "Watching"
[epg channelicon $name 30 \ } elseif {$tsrcnt == 3} {
{vertical-align: middle; padding: 0 4px 0 2px}] set s "Watching (delayed)"
<span>Watching <i>$lcn: $name $prog</i></span>
"
append s "</span>"
lappend output $s
} else { } else {
set s "Watching $lcn: $name $prog" debug "tsrcnt=$tsrcnt"
lappend output $s 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 # Upcoming recordings
set events [rsv list tbl_reservation \ 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] "] and nsttime > [clock seconds] "]
foreach event $events { foreach event $events {
if {$runmode eq "cgi"} { 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 { puts {
</ul> </ul>
@ -131,20 +133,51 @@ puts {
</th> </th>
<td> <td>
<input type=text name="rename_title" id="rename_title" <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"> class="text ui-widget-content ui-corner-all">
</td> </td>
</tr> </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> <tr style="display: none" class=tstype>
<th> <th>
<label for="rename_synopsis" style="padding-top: 0.5em"> <label for="rename_synopsis" style="padding-top: 0.5em">
<b>New Synopsis</b> <b>New Synopsis</b>
</label> </label>
</th> </th>
<td> <td colspan=3>
<textarea name="rename_synopsis" id="rename_synopsis" <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> class="text ui-widget-content ui-corner-all"></textarea>
</td> </td>
</tr> </tr>

View File

@ -2,7 +2,7 @@
package require cgi package require cgi
source /mod/webif/lib/setup source /mod/webif/lib/setup
require ts.class pretty_size require ts.class system.class pretty_size
jscss script.js style.css jscss script.js style.css
jqplugin touchpunch jqplugin touchpunch
@ -15,6 +15,10 @@ set erfile [string map {' \\'} $rfile]
set len [$ts duration 1] set len [$ts duration 1]
set start -1
set incr 1
set limit $(1-$start)
puts " puts "
<script type=text/javascript> <script type=text/javascript>
var initbookmarks = '[$ts bookmarks]'; var initbookmarks = '[$ts bookmarks]';
@ -39,10 +43,38 @@ var dir = '$dir';
<button class=left id=addbmark>Add Bookmark</button> <button class=left id=addbmark>Add Bookmark</button>
<button class=left id=delbmark>Remove Bookmark</button> <button class=left id=delbmark>Remove Bookmark</button>
</td><td><div id=slider></div></td></tr> </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> </table>
<div id=buttons> <div id=buttons>
<button id=save>Save Bookmarks</button> <button id=save>Save Bookmarks</button>
<button id=back>Back to Media Browser</button> <button id=back>Back to Media Browser</button>
"
if {[system pkginst nicesplice]} {
puts "<button id=crop>Go to Crop</button>"
}
puts "
</div> </div>
<div id=results class=\"hidden blood\"></div> <div id=results class=\"hidden blood\"></div>
" "

View File

@ -1,11 +1,26 @@
var curval = 0; var curval = 0;
var $slider; 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 function
setvals() setvals()
{ {
values = $.trim($('#bookmarks').val()).split(/ +/); var nvalues;
if (!values.length || values[0] == '') values = valarray($('#bookmarks').val());
if (values.length > 0 && values[0] != '')
{ {
refreshtimes(); refreshtimes();
return; return;
@ -20,6 +35,7 @@ setvals()
}); });
values = nvalues; values = nvalues;
$('#bookmarks').val(values.join(' ')); $('#bookmarks').val(values.join(' '));
values = valarray($('#bookmarks').val());
sortmarks(); sortmarks();
refreshtimes(); refreshtimes();
} }
@ -32,7 +48,6 @@ draw_slider()
else else
$slider = $('#slider'); $slider = $('#slider');
setvals(); setvals();
values = $.trim($('#bookmarks').val()).split(/ +/);
if (!values.length || values[0] == '') if (!values.length || values[0] == '')
{ {
$slider = null; $slider = null;
@ -55,55 +70,95 @@ draw_slider()
var marks = ''; var marks = '';
for (var i = 0; i < ui.values.length; ++i) for (var i = 0; i < ui.values.length; ++i)
marks += ui.values[i] + ' '; marks += ui.values[i] + ' ';
$('#bookmarks').val($.trim(marks)); $('#bookmarks').val(marks.trim());
setvals(); 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 function
refreshtimes() refreshtimes()
{ {
var t = ''; var t = '';
values = $.trim($('#bookmarks').val()).split(/ +/);
if (!values.length || values[0] == '') if (!values.length || values[0] == '')
{ {
$('#bookmarkstime').text(t); $.each(values, function(k, v) {
return; 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); $('#bookmarkstime').text(t);
} }
function function
sortmarks() sortmarks()
{ {
var a = $.trim($('#bookmarks').val()).split(/ +/); values.sort(function(a, b){return a - b});
a.sort(function(a, b){return a-b}); $('#bookmarks').val(values.join(" "));
$('#bookmarks').val(a.join(" "));
} }
$(function() { $(function() {
$('#bookmarks').val($('#bookmarks').attr('init')); $('#bookmarks').val($('#bookmarks').attr('init'));
draw_slider(); draw_slider();
$('#curbmk').html(toTimeStr(curval));
$('#addbmark').button({icons: {primary: "ui-icon-plus"}, text: false}) $('#addbmark').button({icons: {primary: "ui-icon-plus"}, text: false})
.on('click', function() { .on('click', function() {
$('#bookmarks').val('0 ' + $('#bookmarks').val()); $('#bookmarks').val('0 ' + $('#bookmarks').val());
draw_slider(); curval = 0;
update_slider();
}); });
$('#delbmark').button({icons: {primary: "ui-icon-minus"}, text: false}) $('#delbmark').button({icons: {primary: "ui-icon-minus"}, text: false})
.on('click', function() { .on('click', function() {
var cur = $('#bookmarks').val(); var cur = $('#bookmarks').val();
cur = $.trim(cur.replace( cur = cur.replace(
new RegExp('(^| )' + curval + '( |$)', ''), ' ')); new RegExp('(^| )' + curval + '( |$)', ''), ' ').trim();
$('#bookmarks').val(cur); $('#bookmarks').val(cur);
draw_slider(); update_slider();
}); });
$('#save').button({icons: {primary: "ui-icon-disk"}}) $('#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); 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() $('#update').button()
.on('click', function() { .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 dir [file dirname $rfile]
set len [$ts duration 1] set len [$ts duration 1]
set planwidth 500
puts " puts "
<fieldset> <fieldset>
@ -29,12 +30,17 @@ puts [join [lmap i [$ts bookmarks 1] {
clock format $i -format "%T" 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\">" puts "<div style=\"position: relative; top: -10px\">"
proc div {type left right} { proc div {type left right} {
set width $($right - $left) 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\"> puts "<div class=$type style=\"left: ${left}px; width: ${width}px\">
$type</div>" $type</div>"
} }
@ -64,8 +70,8 @@ foreach b $bookmarks {
incr cur $l incr cur $l
append newbookmarks "[expr $cur + 3] " append newbookmarks "[expr $cur + 3] "
set left $($start * 500 / $len) set left $($start * $planwidth / $len)
set right $($end * 500 / $len) set right $($end * $planwidth / $len)
div cut $last $($left - 1) div cut $last $($left - 1)
div keep $left $($right - 1) div keep $left $($right - 1)
@ -78,11 +84,11 @@ foreach b $bookmarks {
if {$start > 0} { if {$start > 0} {
# Still in a keep section... # Still in a keep section...
incr keeping $($len - $start) incr keeping $($len - $start)
set left $($start * 500 / $len) set left $($start * $planwidth / $len)
div cut $last $($left - 1) div cut $last $($left - 1)
div keep $left 500 div keep $left $planwidth
} else { } else {
div cut $last 500 div cut $last $planwidth
} }
if {$cur > $keeping - 8 && $keeping - 8 > 0} { if {$cur > $keeping - 8 && $keeping - 8 > 0} {
@ -115,7 +121,7 @@ puts [join [lmap i $newbookmarks {
puts " )</td></tr>" puts " )</td></tr>"
puts " puts "
<tr><th>Time:</th> <tr id=esttime><th>Time:</th>
<td>Cropping will take around [clock format $esttime -format "%T"]</td></tr> <td>Cropping will take around [clock format $esttime -format "%T"]</td></tr>
</table> </table>
@ -130,9 +136,9 @@ puts "
<td><button id=invert invert=$invert>Invert selection</button></td> <td><button id=invert invert=$invert>Invert selection</button></td>
<td><button id=cropit>Perform crop operation</button></td> <td><button id=cropit>Perform crop operation</button></td>
<td> <td>
Save new bookmarks? <label id=saveitlabel for=saveit>Save new bookmarks?</label>
<input id=saveit type=checkbox name=saveit checked> <input id=saveit type=checkbox name=saveit checked>
<label id=saveitlabel for=saveit>&nbsp;</label> &nbsp;
</td> </td>
</tr></table> </tr></table>
</div> </div>

View File

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

View File

@ -11,3 +11,8 @@ div.sliderlabel
line-height: 40px; 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 "\"title\" : \"[jescape [$ts get title]]\","
puts "\"synopsis\" : \"[jescape [$ts get synopsis]]\"," puts "\"synopsis\" : \"[jescape [$ts get synopsis]]\","
puts "\"guidance\" : \"[jescape [$ts get guidance]]\"," 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 "}" puts "}"

View File

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

View File

@ -30,8 +30,7 @@ if {[file isdirectory $file]} {
set new "\025$new" set new "\025$new"
} }
if {$new ne $old} { if {$new ne $old} {
if {$attr eq "guidance" || if {$attr eq guidance || $new ne ""} {
[string length $new] > 0} {
$ts set$attr $new $ts set$attr $new
} }
} }
@ -39,6 +38,45 @@ if {[file isdirectory $file]} {
puts "$attr: $msg" 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 } if {"$dir/$newfile.ts" ne "$file"} { ts renamegroup $file $newfile }
} else { } else {

View File

@ -105,14 +105,22 @@ function epginfo_callback(data, status, xhr)
$('#rename_synopsis').val(data.synopsis); $('#rename_synopsis').val(data.synopsis);
$('#rename_guidance').val(data.guidance); $('#rename_guidance').val(data.guidance);
$('#rename_genre').val(data.genre); $('#rename_genre').val(data.genre);
$('#rename_seriesnum').val(data.seriesnum);
$('#rename_episodenum').val(data.episodenum);
$('#rename_episodetot').val(data.episodetot);
$('tr.tstype').show('slow'); $('tr.tstype').show('slow');
} }
function insert_folder_size(folder, size) 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); //console.log("Folder: (%s) = (%s)", folder, size);
if (size.search(/\d$/) == -1) if (size.search(/\d$/) == -1)
size += 'iB'; size += 'iB';

View File

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

View File

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

View File

@ -46,12 +46,16 @@ There are no tasks in the queue.
</tbody> </tbody>
</table> </table>
<div class=buttonbar> <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=qdelete act=delete class="submit needssel">Delete</button>
<button id=qresubmit act=resubmit class="submit needssel">Re-submit</button> <button id=qresubmit act=resubmit class="submit needssel">Re-submit</button>
<button id=qhold act=hold class="submit needssel">Hold</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> <button class=refresh id=refresh>Refresh</button>
<span class=isloading><img src=/img/spin.gif></span> <span class=isloading><img src=/img/spin.gif></span>
</div> </div>

View File

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

View File

@ -9,6 +9,11 @@ lassign [system diskspace 1] size used perc free fperc tsrbuf tsrused
set tsrreserve $($tsrbuf - $tsrused) set tsrreserve $($tsrbuf - $tsrused)
# Adjust values to account for the TSR reserve # Adjust values to account for the TSR reserve
set free $($free - $tsrreserve) 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 used $($size - $free)
set dbs 0 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 pkgdev [$settings pkgdev]
set rtschedule [$settings rtschedule] set rtschedule [$settings rtschedule]
set noautoremove [$settings noautoremove]
set logsize [$settings logsize] set logsize [$settings logsize]
set logkeep [$settings logkeep] set logkeep [$settings logkeep]
set logage [$settings logage] 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 pkgdev $pkgdev "Development Package Display"
handle_int_update rtschedule $rtschedule "Real-time scheduling" 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 logsize $logsize "Log rotation size"
handle_int_update logkeep $logkeep "Logs to keep" handle_int_update logkeep $logkeep "Logs to keep"
handle_int_update logage $logage "Rotated log max age" 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 "Real-time scheduling?" "rtschedule" $rtschedule
} }
setting_toggle "Automatically remove unneeded dependent packages?" \
"noautoremove" $(!$noautoremove) 1
puts -nonewline " puts -nonewline "
<tr> <tr>
<form class=auto id=logsize method=get action=$env(SCRIPT_NAME)> <form class=auto id=logsize method=get action=$env(SCRIPT_NAME)>

View File

@ -263,6 +263,15 @@ foreach e $records {
if {$es < $le} continue 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 {$es < $stt} { set es $stt }
if {$ee > $ett} { set ee $ett } if {$ee > $ett} { set ee $ett }
@ -292,21 +301,6 @@ foreach e $records {
set recopts 1 set recopts 1
if {[$e get series_crid] ne ""} { set recopts 2 } 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 lbg $bg
# Set backround if scheduled. 1 1-off, 2 series, 3 recorded, 4 skipped # Set backround if scheduled. 1 1-off, 2 series, 3 recorded, 4 skipped
switch -- [$e scheduled] { switch -- [$e scheduled] {
@ -318,11 +312,11 @@ foreach e $records {
} }
puts "<div class=\"xeprog $lbg\" 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] <a class=event href=# xs=[$e get service_id]
xe=[$e get event_id] sch=[$e get sched_type] xe=[$e get event_id] sch=[$e get sched_type]
rec=$recopts>" rec=$recopts>"
puts $txt puts [format "%s <span>%s</span>" {*}$txt]
puts "</a>" puts "</a>"
puts "</div>" puts "</div>"
} }

View File

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

View File

@ -94,6 +94,13 @@ proc ::decrypt::dequeue {q ts} {
::auto::startclock ::auto::startclock
log " DECRYPT: $rfile" 0 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"} { if {$mode eq "dlna"} {
log " DLNA: $url" 0 log " DLNA: $url" 0
if {[catch {exec wget -O "$tmp/$bfile" $url} msg opts]} { if {[catch {exec wget -O "$tmp/$bfile" $url} msg opts]} {
@ -104,24 +111,12 @@ proc ::decrypt::dequeue {q ts} {
if {$helper} { system dlnahelper -release } if {$helper} { system dlnahelper -release }
} else { } else {
log " Direct decryption" 0 log " Direct decryption" 0
set keys {}
if {![catch {set fd [open "/mod/boot/cryptokey"]}]} { set key [$ts getkey $mode]
set bytes [$fd read 16] if {$key eq ""} {
$fd close return {"FAILED" "No matching key for decryption"}
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
} }
::auto::log "Using key ($key)" 2 ::auto::log "Using key ($key)" 2
if {[catch {exec /mod/bin/stripts -@ $key $rfile "$tmp/[\ if {[catch {exec /mod/bin/stripts -@ $key $rfile "$tmp/[\
file rootname $bfile]" } msg opts]} { file rootname $bfile]" } msg opts]} {

Binary file not shown.

View File

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

View File

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

View File

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

View File

@ -1,5 +1,5 @@
if {![exists -proc class]} { package require oo } if {![exists -command class]} { package require oo }
class pkg { class pkg {
name "" name ""
@ -128,7 +128,7 @@ pkg method loadraw {} {
} else { } else {
set data [exec /bin/opkg info $name] set data [exec /bin/opkg info $name]
} }
foreach line [split $data "\n"] { foreach line [split $data "\n"] {
if {$tag ne "" && [string match { *} $line]} { if {$tag ne "" && [string match { *} $line]} {
append raw($tag) $line append raw($tag) $line
@ -225,7 +225,7 @@ proc {pkg loaddiagmeta} {} {
} }
proc {pkg fetchfile} {url} { 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 "GET /hdrfoxt2/$url HTTP/1.1\r\n"
$f puts -nonewline "Host: hpkg.tv\r\n" $f puts -nonewline "Host: hpkg.tv\r\n"
$f puts -nonewline "Connection: close\r\n" $f puts -nonewline "Connection: close\r\n"
@ -237,7 +237,7 @@ proc {pkg fetchfile} {url} {
#puts "Web Header: $line" #puts "Web Header: $line"
set line [string trim [$f gets]] set line [string trim [$f gets]]
} }
# Save the body # Save the body
set ret [$f read] set ret [$f read]
$f close $f close

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -18,6 +18,11 @@ foreach {sample expected} {
{(S8, Ep2)} {S8E2/0} {(S8, Ep2)} {S8E2/0}
{(S4 Ep22/24)} {S4E22/24} {(S4 Ep22/24)} {S4E22/24}
{23/27.} {S0E23/27} {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}"] set ts [ts new "synopsis {$sample}"]
$ts episode_name $ts episode_name

View File

@ -1,7 +1,9 @@
if {![exists -proc class]} { package require oo } if {![exists -command class]} { package require oo }
if {![exists -proc pack]} { package require pack } if {![exists -command pack]} { package require pack }
if {![exists -proc xconv]} { package require xconv } if {![exists -command xconv]} { package require xconv }
if {![exists -command binary]} { package require binary }
source /mod/webif/lib/setup source /mod/webif/lib/setup
require system.class tvdb.class classdump require system.class tvdb.class classdump
@ -296,21 +298,21 @@ ts method copy {dst} {
} }
ts method settitle {newtitle} { ts method settitle {newtitle} {
if {[string length newtitle] > 48} { return } if {[string length $newtitle] > 48} { return }
exec /mod/bin/hmt "+settitle=${newtitle}" $file exec /mod/bin/hmt "+settitle=${newtitle}" $file
set title $newtitle set title $newtitle
} }
ts method setsynopsis {newsynopsis} { ts method setsynopsis {newsynopsis} {
if {[string length newsynopsis] > 252} { return } if {[string length $newsynopsis] > 252} { return }
exec /mod/bin/hmt "+setsynopsis=${newsynopsis}" $file exec /mod/bin/hmt "+setsynopsis=${newsynopsis}" $file
set synopsis $newsynopsis set synopsis $newsynopsis
} }
ts method setguidance {newguidance} { ts method setguidance {newguidance} {
if {[string length newguidance] > 48} { return } if {[string length $newguidance] > 74} { return }
if {$newguidance eq ""} { if {$newguidance eq ""} {
exec /mod/bin/hmt "-guidance" $file exec /mod/bin/hmt "-guidance" $file
@ -537,7 +539,7 @@ proc {ts resetnew} {dir} {
#hexdump $bytes #hexdump $bytes
#puts "Calculated: $watched/$tot" #puts "Calculated: $watched/$tot"
pack bytes $tot -intle 32 0 pack bytes $tot -intle 32 0
pack bytes $watched -intle 32 32 pack bytes $watched -intle 32 32
#hexdump $bytes #hexdump $bytes
@ -697,6 +699,14 @@ ts method extract_numbers {} {
regexp -nocase -- {S\.*(\d+),?\s*Ep\.?\s*(\d+)(/(\d+))?} $synopsis \ regexp -nocase -- {S\.*(\d+),?\s*Ep\.?\s*(\d+)(/(\d+))?} $synopsis \
x seriesnum episodenum x episodetot 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} { foreach v {seriesnum episodenum episodetot} {
if {[set $v] eq ""} { if {[set $v] eq ""} {
set $v 0 set $v 0
@ -765,7 +775,7 @@ ts method episode_name {} {
incr flag incr flag
} }
if {$flag} { $self storeepisode } if {$flag} { $self storeepisode }
return $tvdb_data(name) return $tvdb_data(name)
} }
@ -807,7 +817,8 @@ ts method tsr {} {
} }
ts method genrenib {} { ts method genrenib {} {
return $($genre >> 4) if {[catch {set v $($genre >> 4)}]} { set v 0 }
return $v
} }
ts method genre_info {} { ts method genre_info {} {
@ -830,3 +841,56 @@ proc {ts genrelist} {} {
return $glist 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 source /mod/webif/lib/setup
package require cgi package require cgi
if {![exists -proc class]} { package require oo } if {![exists -command class]} { package require oo }
if {![exists -proc sqlite3.open]} { package require sqlite3 } if {![exists -command sqlite3.open]} { package require sqlite3 }
require system.class xml.class require system.class xml.class
set ::tvdb::apikey 1764335F804A5A91 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"] 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 # From https://wiki.tcl-lang.org/page/Parsing+XML
# Keith Vetter 2004-03-01 # Keith Vetter 2004-03-01
if {![exists -proc class]} { package require oo } if {![exists -command class]} { package require oo }
class xml { class xml {
xml "" xml ""