diff --git a/webif/html/browse/download.jim b/webif/html/browse/download.jim
index 41447e7..dcf113f 100755
--- a/webif/html/browse/download.jim
+++ b/webif/html/browse/download.jim
@@ -10,7 +10,7 @@ set urlbase [cgi_get base ""]
# Default to just downloading the raw file.
set url $file
-set mime "video/ts"
+set mime "video/mp2t"
if {[string match {*.ts} $file]} {
if {![catch {set ts [ts fetch $file]}]} {
diff --git a/webif/html/browse/file.jim b/webif/html/browse/file.jim
index e35e86d..17527bf 100755
--- a/webif/html/browse/file.jim
+++ b/webif/html/browse/file.jim
@@ -13,10 +13,14 @@ if {$file == 0} exit
set sz [pretty_size [file size $file]]
+set flags {}
+set url ""
+
+# assumption: the type is only ts if fetch has already been checked
if {$type eq "ts"} {
require epg.class ts.class
- set ts [ts fetch $file]
+ set ts [ts fetch $file 1]
# Causes other series information to be automatically populated
set epname [$ts episode_name]
@@ -199,7 +203,7 @@ eval_plugins browsetsfile
puts "
Flags |
- [$ts get flags] |
+ [set flags [$ts get flags]] |
"
@@ -215,9 +219,6 @@ if {[$ts get bookmarks]} {
"
}
-puts "
-
-"
puts "$file
"
puts {
}
- exit
}
# Otherwise, for a general file.
-puts "
+if {$type ne "ts"} {
+ puts "
File |
@@ -269,20 +270,33 @@ puts "
Size |
$sz |
-
+
"
+}
+
+set hasffmpeg 0
+if {$type ne "ts" || ("ODEncrypted" ni $flags && $url eq "") } {
+ puts "
Info |
Loading...
|
-
-
-"
-
-set url "/browse/ffmpeg.jim?file=[cgi_quote_url $file]"
-puts {
+"
+ set hasffmpeg 1
+} elseif {$type eq "ts" && $url ne ""} {
+ puts [format {
+ } $url]
}
+puts "
+
+ "
+if {$hasffmpeg} {
+ set url "/browse/ffmpeg.jim?file=[cgi_quote_url $file]"
+ puts [format {
+ } $url]
+}
diff --git a/webif/html/browse/index.jim b/webif/html/browse/index.jim
index be17858..587f67e 100755
--- a/webif/html/browse/index.jim
+++ b/webif/html/browse/index.jim
@@ -21,7 +21,7 @@ header
set nicesplice [system pkginst nicesplice]
set ignore {.nts .thm .hmi}
-set include {.ts .avi .mpg .mpeg .wmv .mkv .mp3 .mp4 .mov .hmt .m4v .m4a}
+set include {.ts .avi .mpg .mpeg .wmv .mkv .mp3 .mp4 .mov .hmt .m4v .m4a .webm}
if {![dict exists $env SCRIPT_NAME]} {
set env(SCRIPT_NAME) ""
@@ -139,6 +139,14 @@ proc entry {file} {{i 0}} {
set img Video_Failed
}
set omenu opt
+ if {[$ts get definition] eq ""} {
+ set type gen
+ set ts 0
+ set img Video_Other
+ set omenu oopt
+ } else {
+ set omenu opt
+ }
if {[file exists "${base}.thm"]} { set thmok 1 }
} elseif {$ext eq ".hmt"} {
if {[file exists "${base}.ts"]} { return }
@@ -207,8 +215,8 @@ proc entry {file} {{i 0}} {
# Indexed
set dlna 0
- if {$::dlnaok && $::model eq "HDR" && [llength [
- system dlnaurl [file normalize $file]]]} {
+ if {$::dlnaok && $::model eq "HDR" &&
+ [llength [system dlnaurl $file]]} {
icon "/img/dlna.png" "Indexed by DLNA Server"
set dlna 1
}
diff --git a/webif/html/browse/play.jim b/webif/html/browse/play.jim
new file mode 100755
index 0000000..3eb8dc3
--- /dev/null
+++ b/webif/html/browse/play.jim
@@ -0,0 +1,62 @@
+#!/mod/bin/jimsh
+
+package require cgi
+source /mod/webif/lib/setup
+require system.class
+require ts.class
+
+set file [cgi_get file]
+set urlbase [cgi_get base ""]
+set duration [cgi_get duration 1]
+set fmts [split [cgi_get fmts ""] ","]
+set vc [cgi_get vc ""]
+
+# Default to just downloading the raw file.
+set url $file
+
+# Prefer to use DLNA server ... (necessary if encrypted)
+set dlna [system dlnaurl $url $urlbase]
+if {[llength $dlna]} {
+ set url [lindex $dlna 0]
+} elseif {[regexp {^(https?://(.+:.*@)?[[:alnum:].]+(:[[:digit:]]+)?)/} $urlbase x y]} {
+ set url "$y$url"
+} else {
+ set url "http://[system ip]$url"
+}
+
+if {[file extension $file] in {.ts .TS}} {
+ if {![catch {set ts [ts fetch $file]}] && $ts != 0} {
+ set duration [$ts duration 1]
+ }
+}
+
+set file [file tail $file]
+set playlist [file tempfile "[env "TMPDIR" [env "TMP" "/tmp"]]/playXXXXXX"]
+set pl ""
+try {
+ set pl [open $playlist w]
+ $pl puts "#EXTM3U"
+ $pl puts "#EXTINF:$duration,$file"
+ $pl puts "#PLAYLIST:$file"
+ $pl puts $url
+} finally {
+ if {$pl ne ""} {
+ $pl close
+ }
+}
+
+httpheader "application/x-mpegurl" 0 [list \
+ "Content-Disposition" "attachment; filename=\"[file rootname $file].m3u\"" \
+ "Content-Length" "[file size $playlist]" \
+ ]
+set pl ""
+try {
+ set pl [open $playlist r]
+ $pl copyto stdout
+} finally {
+ if {$pl ne ""} {
+ $pl close
+ }
+}
+catch {file delete $playlist}
+
diff --git a/webif/html/browse/script.js b/webif/html/browse/script.js
index 5269fa0..11bb2cd 100755
--- a/webif/html/browse/script.js
+++ b/webif/html/browse/script.js
@@ -10,7 +10,7 @@ var plugins = {
dmenu_prepare: {}
};
-// pattern matches directory path prefix
+// pattern matches directory path prefix and suffix
var pathre = /.*\/|\.[^.]*$/g;
// IDs of size, img elements for folders use RFC4648 s5 encoding of name
@@ -787,12 +787,14 @@ $('img.doopt').contextMenu(
// Disable items which are not yet implemented.
$('#optmenu').disableContextMenuItems('#title');
-var $buttons = {
- "Close" : function() {$(this).dialog('close');}
-};
-var $buttonsp = $.extend(
- {"Play" : function() { doplay(); }},
- $buttons);
+var $buttons = [
+ { id: 'close',
+ text: 'Close',
+ click: function() {$(this).dialog('close');}},
+ { id: 'play',
+ text: 'Play',
+ click: function() { doplay(this); }}
+];
// Create reusable dialogue.
var $dialog = $('#dialogue').dialog({
@@ -806,16 +808,56 @@ var $dialog = $('#dialogue').dialog({
'Retrieving data...'); }
});
-function doplay()
+/* insert button-like Download link before Play */
+$('#play').before(function(i){
+ var dl = document.createElement('a');
+ dl.setAttribute('class', this.className);
+ dl.id = this.id + 'DL';
+ dl.innerHTML = 'Download';
+ return dl;
+});
+
+function doplay(it)
{
var file = $dialog.attr('file');
var type = $dialog.attr('type');
- disableall();
+ var duration = 0;
+ var fmts = "";
+ var vc = ""
+ var ff = $('#ffmpeg')[0];
+
+ if (ff) {
+ /* extract duration, container and video codec from ffmpeg output */
+ ff = ff.innerHTML;
+ var match = /Duration:\s+([0-9.:]+),/.exec(ff);
+ if (match && match[1])
+ duration = (new Date('1970-01-01T' + match[1] + 'Z')).getTime()/1000;
+ match = /Input #0,\s+([-A-Za-z0-9_,]+),\s/.exec(ff);
+ if (match && match[1]) fmts = match[1];
+ match = /Stream #.+\sVideo:\s+([-A-Za-z0-9_]+)\s/.exec(ff);
+ if (match && match[1]) vc = match[1];
+ }
- window.location = '/play/play.jim?' +
- 'dir=' + encodeURIComponent(dir) +
- '&file=' + encodeURIComponent(file);
+ fmts = /mp4|webm/.exec(fmts);
+ if (fmts && fmts[0])
+ vc = /h264|av1|vp9/.exec(vc);
+ else
+ vc = null;
+
+ if (vc && vc[0]) {
+ /* base on page address to handle client on external network, etc */
+ var hh = new URL(file, window.location.href);
+ window.open(hh.href, 'WebIf_Player');
+ } else {
+ window.location = '/browse/play.jim?' +
+ 'dir=' + encodeURIComponent(dir) +
+ '&base=' + encodeURI(window.location.hostname) +
+ '&duration=' + duration +
+ '&file=' + encodeURIComponent(file);
+ }
+
+ $(it).dialog('close');
}
// Bind dialogue open to filenames.
@@ -834,11 +876,24 @@ $('a.bf').click(function(e) {
$dialog.attr('file', file);
$dialog.attr('type', type);
- if (type == 'ts' &&
- (opt.attr('odencd') == 0 || opt.attr('dlna') == 1))
- $dialog.dialog("option", "buttons", $buttonsp);
- else
- $dialog.dialog("option", "buttons", $buttons);
+ $('#playDL').attr('download', file.replace(/.*\//, ''));
+
+ if (type == 'ts') {
+ if (opt.attr('odencd') != 0) {
+ /* encrypted: link to be enabled once populated */
+ $('#playDL').disable();
+ /* ... but if no DLNA never Play */
+ if (opt.attr('dlna') != 1) $('#play').disable();
+ } else {
+ /* link unencrypted file directly */
+ $('#playDL').attr('href', file);
+ }
+ } else {
+ /* generic: enable Play once media file is parsed */
+ $('#play').disable();
+ $('#playDL').attr('href', file);
+ }
+
$dialog.dialog('open');
});
diff --git a/webif/html/browse/style.css b/webif/html/browse/style.css
index d2e2fa3..93e63e4 100644
--- a/webif/html/browse/style.css
+++ b/webif/html/browse/style.css
@@ -35,3 +35,13 @@ input.uint8_t
width: 6ch;
}
+/* a link that looks like a button */
+button + a.ui-button
+{
+ margin-right: 0.4em;
+}
+.ui-button:link
+{
+ background-color: rgb(254, 206, 47) !important;
+}
+
diff --git a/webif/lib/setup b/webif/lib/setup
index 82f17a0..4ae354b 100644
--- a/webif/lib/setup
+++ b/webif/lib/setup
@@ -33,16 +33,24 @@ if {![exists -proc require]} {
exit
}
- proc httpheader {{type "text/html"} {cache 0} {extra ""}} {{done 0}} {
+ proc httpheader {{type "text/html"} {cache 0} {extra {}}} {{done 0}} {
if {$done} return
if {!$cache} {
- puts -nonewline "Content-Type: $type; charset=\"UTF-8\"; no-cache\r\n"
- puts -nonewline "Expires: -1\r\n"
- puts -nonewline "Connection: close\r\n"
- puts -nonewline "Pragma: no-cache\r\n"
- puts -nonewline "Cache-Control: no-cache\r\n"
+ set hdr [dict create \
+ "Content-Type" "$type; charset=\"UTF-8\"; no-cache" \
+ "Expires" "-1" \
+ "Connection" "close" \
+ "Pragma" "no-cache" \
+ "Cache-Control" "no-cache"]
} else {
- puts -nonewline "Content-Type: $type; charset=\"UTF-8\"\r\n"
+ set hdr [dict create "Content-Type" "$type; charset=\"UTF-8\""]
+ }
+ if {![catch {dict size $extra}]} {
+ set hdr [dict merge $hdr $extra]
+ set extra ""
+ }
+ dict for {k v} $hdr {
+ puts -nonewline "$k: $v\r\n"
}
if {$extra ne ""} { puts -nonewline "$extra" }
puts -nonewline "\r\n"
diff --git a/webif/lib/system.class b/webif/lib/system.class
index e0ffb9a..db3ce76 100644
--- a/webif/lib/system.class
+++ b/webif/lib/system.class
@@ -269,7 +269,11 @@ proc {system dlnadb} {} {
}
proc {system _dlnaurl} {file urlbase} {
- set mime "video/ts"
+ set mime "video/mp2t"
+ set nfile $file
+ if {![catch {set nfile [file normalize $file]}]} {
+ set file $nfile
+ }
if {[catch {set db [sqlite3.open [system dlnadb]]}]} {
return {}
}
@@ -278,7 +282,10 @@ proc {system _dlnaurl} {file urlbase} {
from tblresource join tblmedia using (mediaid)
where localurl = '%s'} $file]
if {[llength $muri]} {
- lassign [lindex $muri 0] x mime x xuri
+ lassign [lindex $muri 0] x maybemime x xuri
+ if {$maybemime ne "video/ts"} {
+ set mime $maybemime
+ }
} else {
# Try for partially linked entry
set muri [$db query {
@@ -297,7 +304,7 @@ proc {system _dlnaurl} {file urlbase} {
return [list $url $mime]
}
-proc {system dlnaurl} {file {urlbase ""}} {
+proc {system dlnaurl} {file {urlbase "127.0.0.1"}} {
if {$urlbase eq ""} { set urlbase [system ip] }
set retries 5
set ret {}
diff --git a/webif/lib/ts.class b/webif/lib/ts.class
index 6eb0b51..d4de7ff 100644
--- a/webif/lib/ts.class
+++ b/webif/lib/ts.class
@@ -331,7 +331,7 @@ ts method setgenre {newgenre} {
}
ts method dlnaloc {{urlbase ""}} {
- return [system dlnaurl [file normalize $file] $urlbase]
+ return [system dlnaurl $file $urlbase]
}
ts method cleanbmp {} {