From e896ec5adcabb3708a82079262a378c4ad2e0335 Mon Sep 17 00:00:00 2001 From: df Date: Tue, 16 Feb 2021 00:49:28 +0000 Subject: [PATCH] Play file in browser or with external helper application Create a new `play.jim` in html/browse. The `/play` subtree is now obsolete and can be removed. --- webif/html/browse/file.jim | 43 +++++++++++++++---------- webif/html/browse/play.jim | 62 ++++++++++++++++++++++++++++++++++++ webif/html/browse/script.js | 63 +++++++++++++++++++++++++++---------- 3 files changed, 135 insertions(+), 33 deletions(-) create mode 100644 webif/html/browse/play.jim diff --git a/webif/html/browse/file.jim b/webif/html/browse/file.jim index e35e86d..a90ed3a 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 "" puts { } - exit } # Otherwise, for a general file. -puts " +if {$type ne "ts"} { + puts " @@ -269,20 +270,28 @@ puts " - +" + +set hasffmpeg 0 +if {$type ne "ts" || ("ODEncrypted" ni $flags && $url eq "") } { + puts " - -
File
Size $sz
Info Loading...
-" +" + set hasffmpeg 1 +} +puts " + + " -set url "/browse/ffmpeg.jim?file=[cgi_quote_url $file]" -puts { } - +} diff --git a/webif/html/browse/play.jim b/webif/html/browse/play.jim new file mode 100644 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 28ad4b1..b4ce507 100755 --- a/webif/html/browse/script.js +++ b/webif/html/browse/script.js @@ -781,12 +781,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({ @@ -800,16 +802,47 @@ var $dialog = $('#dialogue').dialog({ 'Retrieving data...'); } }); -function doplay() +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.location = hh.href; + } else { + window.location = '/browse/play.jim?' + + 'dir=' + encodeURIComponent(dir) + + '&base=' + encodeURI(window.location.href) + + '&duration=' + duration + + '&file=' + encodeURIComponent(file); + } + + $(it).dialog('close'); } // Bind dialogue open to filenames. @@ -828,11 +861,9 @@ $('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); + if (!(type == 'ts' && + (opt.attr('odencd') == 0 || opt.attr('dlna') == 1))) + $('#play').button('disable'); $dialog.dialog('open'); });