Compare commits

...

82 Commits

Author SHA1 Message Date
HummyPkg ee4c121a54 Update to 1.4.9-6 2021-04-10 09:53:33 +01:00
HummyPkg 8f340c9a3b Update to 1.4.9-5 2021-04-10 09:53:13 +01:00
af123 67504198ec Merge pull request 'Ensure , is escaped in ::js::escape' (#45) from df/webif:df-listdirs-patch-v2 into master
Reviewed-on: hummypkg/webif#45
2021-04-10 08:52:31 +00:00
df ba0f505e34 Ensure , is escaped in ::js::escape 2021-04-10 01:05:19 +01:00
af123 33e2f705c3 Merge pull request 'df-seriesnum-patchv2' (#44) from df/webif:df-seriesnum-patch into master
Reviewed-on: hummypkg/webif#44
2021-03-22 21:57:07 +00:00
df a26526b047 Fix unquoted string; add genre check; errors to stderr 2021-03-21 00:14:35 +00:00
HummyPkg 04e4fd1083 Update to 1.4.9-4 2021-03-20 19:33:27 +00:00
af123 6e3b5114be Merge pull request 'df-decryptq-testkey-patchv2' (#43) from df/webif:df-decryptq-testkey-patch into master
Reviewed-on: hummypkg/webif#43
2021-03-20 19:31:28 +00:00
df 6c40da165d Improve error trapping, actually make it work 2021-03-20 01:22:48 +00:00
df 346ed469c8 Make use of unique element IDs for img consistent 2021-03-04 19:31:09 +00:00
HummyPkg 029b115628 Revert "Work around uclibc getaddrinfo()"
This reverts commit f206766191.
2021-02-26 23:04:57 +00:00
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: hummypkg/webif#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: hummypkg/webif#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: hummypkg/webif#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: hummypkg/webif#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: hummypkg/webif#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
HummyPkg 2e471129b8 Release 1.4.8-11 2020-12-13 23:24:12 +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
af123 8021455a94 Merge pull request 'df-lockedsettings-patch' (#18) from df/webif:df-lockedsettings-patch into master
Reviewed-on: hummypkg/webif#18
2020-11-14 11:16:55 +00:00
af123 c995f2232e Merge pull request 'prpr-patch-fix-thumbnail' (#25) from prpr/webif:prpr-patch-fix-thumbnail into master
Reviewed-on: hummypkg/webif#25
2020-11-14 11:12:14 +00:00
prpr 6dc47f2b96 Merge branch 'master' into prpr-patch-fix-thumbnail 2020-11-14 01:29:38 +00:00
prpr af74503b99 Fix the ****ing formatting in this stupid editor 2020-11-14 01:25:46 +00:00
prpr 58ecd41952 Fix thumbnail generation 2020-11-14 01:17:07 +00:00
df e579c8dd24 Merge branch 'master' into df-lockedsettings-patch 2020-10-23 11:45:30 +00:00
df 7c600be77e Retry access in case the settings database is locked 2020-10-20 18:34:19 +00:00
af123 e3f7a2b738 Merge pull request 'prpr-patch-rename-utf8' (#20) from prpr/webif:prpr-patch-rename-utf8 into master
Reviewed-on: hummypkg/webif#20
2020-10-19 22:02:38 +00:00
prpr a90f49b324 Prevent raw utf8 display
https://hummy.tv/forum/threads/webif-web-interface-1-4-x.7712/post-135917
2020-10-19 16:05:12 +00:00
df 3e9ecc8a7c Change to 0.5s, doubling for 4 tries 2020-10-19 11:44:53 +00:00
df 7bb66de5f2 Raise the "database locked" error from caller context 2020-10-18 19:19:26 +00:00
df 9b64128c92 Retry access in case the settings database is locked 2020-10-18 15:48:07 +00:00
df 6822c833be Retry access in case the settings database is locked
Create `settings::_safer_query` class proc to allow 5 tries with 1s delay; use it for `_nval_setting` and `_tval_setting` methods
2020-10-18 14:53:23 +00:00
df cefe60c722 Merge pull request 'Resync master' (#5) from hummypkg/webif:master into master
Reviewed-on: #5
2020-10-18 14:06:40 +00:00
prpr ee885a173c Merge pull request 'master' (#1) from hummypkg/webif:master into master
Reviewed-on: prpr/webif#1
2020-10-16 21:05:30 +00:00
HummyPkg d7c15163e1 Update release version 2020-10-16 14:28:17 +01:00
af123 879c458256 Merge pull request 'df-auto-deq-patch' (#14) from df/webif:df-auto-deq-patch into master
Reviewed-on: hummypkg/webif#14
2020-10-16 13:27:15 +00:00
df 1a25e2a3f1 Fix potential format error with queue item containing %
If an item is in the queue whose file name contains a %, the following error occurs, causing the item never to be dequeued:
```in procedure '::auto::dumpq' called at file "/mod/webif/lib/auto/deq", line 167
at file "/mod/webif/lib/auto/deq", line 118
/mod/webif/lib/auto/deq:118: Error: not enough arguments for all format specifiers```
The file name needs to be passed to `format` as a parameter with format `%s` rather than embedding it in the format string, or else ```log "[format ...][$q get file]"```
2020-10-16 14:26:30 +01:00
af123 006a04683a Merge pull request 'df-autolast-future-patch' (#13) from df/webif:df-autolast-future-patch into master
Reviewed-on: hummypkg/webif#13
2020-10-16 13:25:41 +00:00
df 3623a26a08 Correct autolast in the future
Fixing issue in <https://hummy.tv/forum/threads/recursive-auto-shrink-auto-decrypt-no-longer-working.9399/post-134718>.
2020-10-16 14:25:15 +01:00
af123 c428a367a1 Merge pull request 'Use service ids to map to mux names' (#12) from prpr/webif:master into master
Reviewed-on: hummypkg/webif#12
2020-10-16 13:18:00 +00:00
af123 480108f3a2 Merge pull request 'Schedule all epsiodes of series' (#11) from MymsMan/webif:SeriesSched into master
Reviewed-on: hummypkg/webif#11
2020-10-16 13:16:25 +00:00
Bob Buxton 2884a82dbf Schedule all epsiodes of series 2020-10-16 14:16:15 +01:00
af123 ac4b392db8 Merge pull request 'Rotate auto.log to auto_<timestamp>.log when it excedes settings logsize' (#16) from MymsMan/webif:Rotate_auto.log into master
Reviewed-on: hummypkg/webif#16
2020-10-16 13:14:11 +00:00
Bob Buxton c3d360fa63 Rotate auto.log to auto_<timestamp>.log when it excedes settings logsize 2020-10-16 14:13:16 +01:00
prpr 3f199f32ab Update 'webif/html/diag/mux.jim' 2020-07-14 00:29:02 +00:00
45 changed files with 921 additions and 303 deletions

View File

@ -1,7 +1,7 @@
Package: webif
Priority: optional
Section: web
Version: 1.4.8-9
Version: 1.4.9-6
Architecture: mipsel
Maintainer: af123@hpkg.tv
Depends: tcpfix,webif-channelicons(>=1.1.27),lighttpd(>=1.4.39-1),jim(>=0.79),jim-pack(>=0.79),jim-oo(>=0.77),jim-sqlite3(>=0.77),jim-cgi(>=0.7-2),jim-binary(>=0.76),service-control(>=2.3),busybox(>=1.20.2-1),lsof(>=4.87),epg(>=1.2.8),hmt(>=2.0.10),ssmtp,cron-daemon(>=1.18.3-3),at(>=3.1.18),anacron,trm(>=1.1),openssl-command,nicesplice,id3v2,file,rsvsync(>=1.1.13),webif-charts(>=1.2-1),stripts(>=1.4.2),tmenu(>=1.21-2),ffmpeg(>=2.8),id3v2,multienv(>=1.6),tcpping(>=1.1),e2fsprogs,wireless-tools(>=29-1),dbupdate,recmon(>=2.0.7),hwctl,nugget(>=0.98),sqlite3(>=3.15.1),jim-xconv,zip(>=3.0-1),wget

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -58,6 +58,10 @@ proc icon {img {hover ""} {extra ""} {class "va"}} {
puts ">"
}
proc nbsp {str} {
return [string map {" " &nbsp;} $str]
}
proc directory {file bfile tbfile} {
puts "<div class=\"va relative\">"
set img "/images/711_1_09_Media_Folder.png"
@ -69,7 +73,7 @@ proc directory {file bfile tbfile} {
puts "<a class=dbf
href=\"$::env(SCRIPT_NAME)?dir=[cgi_quote_url $file]\"
file=\"[cgi_quote_html $file]\">"
puts "$bfile</a><span class=filesize id=\"$tbfile\">
puts "[nbsp $bfile]</a><span class=filesize id=\"ID$tbfile\">
</span>"
lassign [dir iconset $file] icons attrs
@ -106,13 +110,12 @@ proc entry {file} {{i 0}} {
global dircount filecount dinuse
set bfile [file tail $file]
regsub -all " +" $bfile "" tbfile
if {[string index $bfile 0] == "\025"} {
set bfile [string range $bfile 1 end]
}
if {[file isdirectory "$file"]} {
incr dircount
directory $file $bfile $tbfile
directory $file $bfile [b64uencode [jsescape $bfile]]
return
}
set ext [string tolower [file extension $file]]
@ -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

@ -26,16 +26,59 @@ if {[file isdirectory $file]} {
set new [string map {"\n" ""} [
string trim [cgi_get "rename_$attr"]]]
set old [$ts get $attr]
if {$attr eq "title" || $attr eq "synopsis"} {
set new "\025$new"
} elseif {$attr eq "genre"} {
set new [ts genre $new]
}
if {$new ne $old} {
if {$attr eq "guidance" ||
[string length $new] > 0} {
if {$attr eq "guidance" || $new ne ""} {
$ts set$attr $new
}
}
} msg]} {
puts "$attr: $msg"
stderr 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]} {
stderr puts "$attr: $msg"
}
}
if {$epdatanew ne {}} {
if {[catch {$ts storeepisode $epdatanew} msg]} {
puts "ts::storeepisode: $msg"
}
}
if {"$dir/$newfile.ts" ne "$file"} { ts renamegroup $file $newfile }
} else {

View File

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

View File

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

View File

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

View File

@ -19,6 +19,19 @@ proc f2c {frequency} {
return [expr int($ch)]
}
proc svc2mux {svcid mux} {
return [switch $($svcid / 4096) {
1 { format "PSB1/BBC A" }
2 { format "PSB2/D3&4" }
4 { format "PSB3/BBC B" }
3 { format "COM4/SDN" }
5 { format "COM5/ARQ A" }
6 { format "COM6/ARQ B" }
10 { format "COM7/ARQ C" }
default { format $mux }
}]
}
puts "
<div class=va>
<img class=va src=/img/aerials.png height=50>
@ -61,7 +74,7 @@ foreach tw [$db query {
puts "<td>[system strip $netName]</td>"
set channels [$db query {
select usLcn, szSvcName, szPrvName, aucDefaultAuthority
select usLcn, szSvcName, usSvcId, szPrvName, aucDefaultAuthority
from TBL_SVC left join TBL_PRV using (prvIdx)
where tsIdx = %s
order by usLcn
@ -72,14 +85,15 @@ foreach tw [$db query {
} else {
set mux "Unknown"
}
if {[llength $channels] != 0} {
set chan [lindex $channels 0]
lassign $chan x lcn x name x svcid
set mux [svc2mux $svcid $mux]
}
set ehs 0
foreach chan $channels {
lassign $chan x lcn x name
set name [system strip $name]
lassign $chan x lcn
if {$lcn >= 800} { incr ehs }
if {[dict exists $::muxdb $name]} {
set mux $::muxdb($name)
}
}
puts "<td>$mux</td>"
if {$eSystem == 0} {
@ -106,7 +120,7 @@ foreach tw [$db query {
</tr>"
altrow reset
foreach chan $channels {
lassign $chan x lcn x name x prv x auth
lassign $chan x lcn x name x svcid x prv x auth
set name [system strip $name]
set prv [system strip $prv]
altrow

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

@ -115,8 +115,8 @@ proc ::auto::dumpq {qq} {
if {[$q get action] in $::auto::plugins} {
set pri $::auto::plugins([$q get action])
}
log [format " C: %4d %5d %8s - [$q get file]" \
[$q get id] $pri [$q get action]] 2
log [format " C: %4d %5d %8s - %s" \
[$q get id] $pri [$q get action] [$q get file]] 2
}
}

View File

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

View File

@ -73,7 +73,10 @@ if {!$::auto::force} {
set timesincelast $(([clock seconds] - [$::auto::settings autolast]) \
/ 60)
if {$timesincelast < $autofreq} {
if {$timesincelast < 0} {
# time machine issue: correct it
$::auto::settings autolast 0
} elseif {$timesincelast < $autofreq} {
::auto::log "Aborting, not yet time to run." 2
::auto::log " elapsed (minutes): $timesincelast (<$autofreq)" 2
exit

View File

@ -5,12 +5,13 @@ set ::auto::logprefix ""
set ::auto::loglevel 1
proc ::auto::loginit {} {
variable settings
set logsize [$settings logsize]
# Rotate log file if large enough.
if {[file exists $::auto::logfile] &&
[file size $::auto::logfile] > 2097152} {
file copy -force $::auto::logfile "/mod/tmp/auto_old.log"
file delete $::auto::logfile
[file size $::auto::logfile] > $logsize} {
set tstamp [clock format [clock seconds] -format {%Y%m%d%H%M%S}]
file rename -force $::auto::logfile "/mod/tmp/auto.$tstamp.log"
}
# Open log file

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 ""
@ -128,7 +128,7 @@ pkg method loadraw {} {
} else {
set data [exec /bin/opkg info $name]
}
foreach line [split $data "\n"] {
if {$tag ne "" && [string match { *} $line]} {
append raw($tag) $line
@ -237,7 +237,7 @@ proc {pkg fetchfile} {url} {
#puts "Web Header: $line"
set line [string trim [$f gets]]
}
# Save the body
set ret [$f read]
$f close

View File

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

View File

@ -1,8 +1,8 @@
source /mod/webif/lib/setup
if {![exists -proc class]} { package require oo }
if {![exists -proc sqlite3.open]} { package require sqlite3 }
if {![exists -proc binary]} { package require binary }
if {![exists -command class]} { package require oo }
if {![exists -command sqlite3.open]} { package require sqlite3 }
if {![exists -command binary]} { package require binary }
require settings.class system.class plugin svc.class
set binaryfields aulEventToRecordInfo
@ -967,19 +967,30 @@ proc {rsv construct} {event type} {
set args(szFPBRecPath) "$args(szevtname)"
set events {}
set seen {}
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
if {$ecrid in $seen} continue
lappend seen $ecrid
if {[$i get start] < [$event get start]} {
if {[$i end] < $now} {
set args(usLastRecordedEvtId) [$i get event_id]
continue
}
if {$ecrid in $seen} continue
lappend seen $ecrid
lappend events [rsv mkaul $i]
list "1$::ccrid$ecrid"
}]
# set 1st event to record
binary scan [string range [lindex $events 0] 0 15] \
iiii service_id start end event_id
#puts "$service_id $start [clock format $end] $event_id"
set args(hsvc) $service_id
set args(nsttime) $start
set args(usevtid) $event_id
set args(nduration) $($end-$start)
set args(szEventToRecord) "[join $progs "|"]|"
set args(aulEventToRecordInfo) [join $events ""]
}

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,29 @@ class settings {
logkeep 2
logage 0
rtschedule 0
noautoremove 0
}
proc {settings _safer_query} { queryText args } {
global settingsdb
# allow 4 tries from 0.5s delay, doubling, to get access
for {set lockCnt 4; set delay 0.5} {true} {sleep $delay; set delay $(2*$delay)} {
try {
return [$settingsdb query $queryText {*}$args]
} on error {msg opts} {
if {[string first "database is locked" $msg] >= 0} {
if {[incr lockCnt -1] > 0} {
continue
} else {
# raise error from caller
set msg "Persistently unable to access Settings: database locked"
incr opts(-level)
}
}
return {*}$opts $msg
}
}
}
settings method hostname {{name ""}} {
@ -104,11 +127,10 @@ settings method smtp_server {{server ""}} {
}
settings method _nval_setting {name {val -1}} {
global settingsdb
if {$val == -1} {
# Get
set res [$settingsdb query "
set res [settings _safer_query "
select nval from settings
where name = '$name'
"]
@ -118,7 +140,7 @@ settings method _nval_setting {name {val -1}} {
return 0
} else {
# Set
$settingsdb query "
settings _safer_query "
replace into settings(name,nval)
values('$name', $val)
"
@ -127,11 +149,10 @@ settings method _nval_setting {name {val -1}} {
}
settings method _tval_setting {name {val -1} {def 0}} {
global settingsdb
if {$val eq "-1"} {
# Get
set res [$settingsdb query "
set res [settings _safer_query "
select tval from settings
where name = '$name'
"]
@ -141,7 +162,7 @@ settings method _tval_setting {name {val -1} {def 0}} {
return $def
} else {
# Set
$settingsdb query "
settings _safer_query "
replace into settings(name,tval)
values('$name', '%s')
" $val
@ -237,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
@ -320,10 +322,18 @@ ts method setguidance {newguidance} {
set guidance $newguidance
}
ts method setgenre {newgenre} {
if {$newgenre <= 15} {
set newgenre $($newgenre << 4)
proc {ts genre} {genre} {
if {![string is integer $genre] || $genre < 0} {
set genre 0
}
if {$genre <= 15} {
set genre $($genre << 4)
}
return $genre
}
ts method setgenre {newgenre} {
set newgenre [ts genre $newgenre]
exec /mod/bin/hmt "+setgenre=-${newgenre}" $file
set genre $newgenre
}
@ -354,13 +364,14 @@ ts method mkbmps {{offset 0}} {
ts method mkbmp {{offset 0} {ext ""}} {
set bfile [file rootname $file]
set bmpfile "$bfile$ext.bmp"
set cmd [list /mod/bin/ffmpeg -loglevel fatal -ss $offset -i $file \
-frames 1 -pix_fmt argb -vf vflip -s 140x78 "$bfile$ext.bmp"]
if {[catch { exec {*}$cmd } msg]} {
puts "ERROR: $msg"
return 0
-frames 1 -pix_fmt argb -vf vflip -s 140x78 -y $bmpfile]
catch { exec {*}$cmd }
if {![catch { file stat $bmpfile stbmp }]} {
if {[dict get $stbmp size] != 0} { return 1 }
}
return 1
return 0
}
ts method mkthm {{offset 0}} {
@ -536,7 +547,7 @@ proc {ts resetnew} {dir} {
#hexdump $bytes
#puts "Calculated: $watched/$tot"
pack bytes $tot -intle 32 0
pack bytes $tot -intle 32 0
pack bytes $watched -intle 32 32
#hexdump $bytes
@ -696,6 +707,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
@ -764,7 +783,7 @@ ts method episode_name {} {
incr flag
}
if {$flag} { $self storeepisode }
return $tvdb_data(name)
}
@ -806,7 +825,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 {} {
@ -829,3 +849,58 @@ 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
}
} on error {} {
} 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
}
} on error {} {
} 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 ""