forked from hummypkg/webif
Merge branch 'master' of https://git.hpkg.tv/hummypkg/webif
This commit is contained in:
commit
6c9a18fa14
|
@ -1,7 +1,7 @@
|
|||
Package: webif
|
||||
Priority: optional
|
||||
Section: web
|
||||
Version: 1.4.9-6
|
||||
Version: 1.4.9-7
|
||||
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
|
||||
|
|
|
@ -21,7 +21,6 @@ set limit $(1-$start)
|
|||
|
||||
puts "
|
||||
<script type=text/javascript>
|
||||
var initbookmarks = '[$ts bookmarks]';
|
||||
var len = [$ts duration 1];
|
||||
var file = '$erfile';
|
||||
var dir = '$dir';
|
||||
|
@ -29,24 +28,29 @@ var dir = '$dir';
|
|||
<fieldset class=cleft>
|
||||
<legend>Manage Bookmarks</legend>
|
||||
|
||||
<table class=keyval cellpadding=5>
|
||||
<table class=keyval>
|
||||
<tr><th>File:</th><td>$rfile</td></tr>
|
||||
<tr><th>Length:</th><td>[clock format $len -format %T]</td></tr>
|
||||
<tr><th>Size:</th><td>[pretty_size [$ts size]] ([$ts get definition])</td></tr>
|
||||
<tr><th>Bookmarks<br><span class=footnote>(enter in seconds)</span></th><td>
|
||||
<input id=bookmarks size=80 maxlength=255 init=\"[$ts bookmarks]\"
|
||||
value=\"\" />
|
||||
<input id=bookmarks size=80 maxlength=255 value=\"[$ts bookmarks]\" />
|
||||
<button id=update>Update</button>
|
||||
<br>
|
||||
<span id=bookmarkstime></span>
|
||||
</td></tr><tr><td align=right>
|
||||
</td></tr><tr><td class=cell-align-right>
|
||||
<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>
|
||||
<tr><td class=cell-align-right>
|
||||
<span class=left>Current: <span id=curbmk></span></span><br><br><br>
|
||||
"
|
||||
if {![$ts flag "ODEncrypted"]} {
|
||||
puts "
|
||||
<button id=genthumbs title=\"Generate Thumbnails\"
|
||||
class=left>Generate Thumbnails</button>
|
||||
"
|
||||
}
|
||||
puts "
|
||||
</td><td>
|
||||
<div id=thumbs class=hidden>
|
||||
<table><tr>
|
||||
|
@ -55,13 +59,13 @@ set times {}
|
|||
loop v $start $limit $incr {
|
||||
lappend times $v
|
||||
puts "
|
||||
<th style=\"text-align: center\"><span class=mark>
|
||||
<th class=mark><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 "<td><img class=bmp data-pos=$v alt=\"thumbnail @ $v s\"></td>"
|
||||
}
|
||||
puts "
|
||||
</tr></table>
|
||||
|
@ -77,5 +81,8 @@ if {[system pkginst nicesplice]} {
|
|||
puts "
|
||||
</div>
|
||||
<div id=results class=\"hidden blood\"></div>
|
||||
</fieldset>
|
||||
"
|
||||
|
||||
footer
|
||||
|
||||
|
|
|
@ -1,238 +1,225 @@
|
|||
var curval = 0;
|
||||
var $slider;
|
||||
var values;
|
||||
|
||||
/* using var len defined in inline script, index.jim */
|
||||
/* using var file defined in inline script, index.jim */
|
||||
/* using var dir defined in inline script, index.jim */
|
||||
function
|
||||
toTimeStr(tval)
|
||||
{
|
||||
return new Date(null, null, null, null, null, tval)
|
||||
.toTimeString().match(/\d{2}:\d{2}:\d{2}/)[0] + ' ';
|
||||
.toTimeString().match(/\d{2}:\d{2}:\d{2}/)[0];
|
||||
}
|
||||
|
||||
function
|
||||
valarray(valstr)
|
||||
{
|
||||
return valstr.trim().split(/ +/);
|
||||
}
|
||||
|
||||
function
|
||||
setvals()
|
||||
{
|
||||
var nvalues;
|
||||
values = valarray($('#bookmarks').val());
|
||||
if (values.length > 0 && values[0] != '')
|
||||
{
|
||||
refreshtimes();
|
||||
return;
|
||||
}
|
||||
nvalues = [];
|
||||
$.each(values, function(k, v) {
|
||||
if (v > len)
|
||||
v = len;
|
||||
if (v < 0)
|
||||
v = 0;
|
||||
nvalues.push(v);
|
||||
});
|
||||
values = nvalues;
|
||||
$('#bookmarks').val(values.join(' '));
|
||||
values = valarray($('#bookmarks').val());
|
||||
sortmarks();
|
||||
refreshtimes();
|
||||
}
|
||||
|
||||
function
|
||||
draw_slider()
|
||||
{
|
||||
if ($slider)
|
||||
$slider.slider('destroy');
|
||||
else
|
||||
$slider = $('#slider');
|
||||
setvals();
|
||||
if (!values.length || values[0] == '')
|
||||
{
|
||||
$slider = null;
|
||||
return;
|
||||
}
|
||||
$slider.slider({
|
||||
min: 0,
|
||||
max: len,
|
||||
step: 1,
|
||||
values: values,
|
||||
start: function(event, ui) {
|
||||
curval = ui.value;
|
||||
},
|
||||
stop: function(event, ui) {
|
||||
curval = ui.value;
|
||||
sortmarks();
|
||||
refreshtimes();
|
||||
},
|
||||
slide: function(event, ui) {
|
||||
var marks = '';
|
||||
for (var i = 0; i < ui.values.length; ++i)
|
||||
marks += ui.values[i] + ' ';
|
||||
$('#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 = '';
|
||||
if (!values.length || values[0] == '')
|
||||
{
|
||||
$.each(values, function(k, v) {
|
||||
t += toTimeStr(v);
|
||||
});
|
||||
$('#slider .ui-slider-handle').each(function(i) {
|
||||
$(this).attr('title', toTimeStr(values[i]));
|
||||
});
|
||||
}
|
||||
$('#bookmarkstime').text(t);
|
||||
}
|
||||
|
||||
function
|
||||
sortmarks()
|
||||
{
|
||||
values.sort(function(a, b){return a - b});
|
||||
$('#bookmarks').val(values.join(" "));
|
||||
return valstr.trim().split(/\s+/);
|
||||
}
|
||||
|
||||
$(function() {
|
||||
var curval = 0;
|
||||
var $slider;
|
||||
var values;
|
||||
|
||||
$('#bookmarks').val($('#bookmarks').attr('init'));
|
||||
draw_slider();
|
||||
$('#curbmk').html(toTimeStr(curval));
|
||||
function
|
||||
sortmarks()
|
||||
{
|
||||
values.sort(function(a, b){return a - b});
|
||||
$('#bookmarks').val(values.join(" "));
|
||||
}
|
||||
|
||||
$('#addbmark').button({icons: {primary: "ui-icon-plus"}, text: false})
|
||||
.on('click', function() {
|
||||
$('#bookmarks').val('0 ' + $('#bookmarks').val());
|
||||
curval = 0;
|
||||
update_slider();
|
||||
});
|
||||
|
||||
$('#delbmark').button({icons: {primary: "ui-icon-minus"}, text: false})
|
||||
.on('click', function() {
|
||||
var cur = $('#bookmarks').val();
|
||||
cur = cur.replace(
|
||||
new RegExp('(^| )' + curval + '( |$)', ''), ' ').trim();
|
||||
$('#bookmarks').val(cur);
|
||||
update_slider();
|
||||
});
|
||||
|
||||
$('#save').button({icons: {primary: "ui-icon-disk"}})
|
||||
.on('click', function() {
|
||||
$.post('save.jim', {
|
||||
file: file,
|
||||
bookmarks: $('#bookmarks').val()
|
||||
}, function(data) {
|
||||
$('#results').html(data)
|
||||
.slideDown('slow').delay(5000).slideUp('slow');
|
||||
});
|
||||
});
|
||||
|
||||
$('#back').button({icons: {primary: "ui-icon-arrowreturnthick-1-w"}})
|
||||
.on('click', function() {
|
||||
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() {
|
||||
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;
|
||||
function
|
||||
refreshtimes()
|
||||
{
|
||||
var t = '';
|
||||
if (values.length > 0 && values[0] != '')
|
||||
{
|
||||
$.each(values, function(k, v) {
|
||||
if (t != '') t += ', ';
|
||||
t += toTimeStr(v);
|
||||
});
|
||||
$('#slider .ui-slider-handle').each(function(i) {
|
||||
if (values[i]|0 > 0)
|
||||
$(this).attr('title', toTimeStr(values[i]))
|
||||
else $(this).attr('title', '');
|
||||
});
|
||||
$('#curbmk').html(toTimeStr(curval));
|
||||
$('#genthumbs').button('enable');
|
||||
}
|
||||
incr++;
|
||||
});
|
||||
else
|
||||
{
|
||||
$('#genthumbs').button('disable');
|
||||
$('#curbmk').html('');
|
||||
}
|
||||
$('#bookmarkstime').text(t);
|
||||
}
|
||||
|
||||
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));
|
||||
function
|
||||
setvals()
|
||||
{
|
||||
var nvalues;
|
||||
values = valarray($('#bookmarks').val());
|
||||
nvalues = new Set();
|
||||
$.each(values, function(k, v) {
|
||||
if (v > len)
|
||||
v = len;
|
||||
if (v < 0)
|
||||
v = 0;
|
||||
nvalues.add(v);
|
||||
});
|
||||
$('#genthumbs').button('option', 'icon', 'ui-icon-zoomin');
|
||||
values = Array.from(nvalues);
|
||||
sortmarks();
|
||||
}
|
||||
|
||||
function
|
||||
regenthumbs(curbmkstr)
|
||||
{
|
||||
$('#curbmk').html(curbmkstr);
|
||||
$('#thumbs').hide();
|
||||
$('#genthumbs')
|
||||
.button(curbmkstr ? 'enable': 'disable')
|
||||
.button('option', 'icon', 'ui-icon-zoomin');
|
||||
}
|
||||
|
||||
function
|
||||
draw_slider()
|
||||
{
|
||||
if ($slider)
|
||||
$slider.slider('destroy');
|
||||
else
|
||||
$slider = $('#slider');
|
||||
setvals();
|
||||
$slider.slider({
|
||||
min: 0,
|
||||
max: len,
|
||||
step: 1,
|
||||
disabled: values.length <= 0 || values[0] == '',
|
||||
values: values,
|
||||
start: function(event, ui) {
|
||||
curval = ui.value;
|
||||
},
|
||||
stop: function(event, ui) {
|
||||
curval = ui.value;
|
||||
sortmarks();
|
||||
refreshtimes();
|
||||
},
|
||||
slide: function(event, ui) {
|
||||
var marks = '';
|
||||
for (var i = 0; i < ui.values.length; ++i)
|
||||
marks += ui.values[i] + ' ';
|
||||
$('#bookmarks').val(marks.trim());
|
||||
setvals();
|
||||
}
|
||||
});
|
||||
refreshtimes();
|
||||
|
||||
/* 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;
|
||||
regenthumbs('');
|
||||
} else {
|
||||
if (nn >= values.length)
|
||||
nn = values.length - 1;
|
||||
if (nn >= 0) {
|
||||
regenthumbs(toTimeStr(curval = values[nn]));
|
||||
} else {
|
||||
curval = 0;
|
||||
regenthumbs('');
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$('#genthumbs').button({icons: {primary: "ui-icon-zoomin"}, disabled: true})
|
||||
.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('data-pos') | 0;
|
||||
} else {
|
||||
last = $(this).attr('data-pos') | 0;
|
||||
}
|
||||
incr++;
|
||||
$(this).attr('src', '/img/generating.png');
|
||||
});
|
||||
$('#thumbs').show();
|
||||
|
||||
incr = (last - start) / incr;
|
||||
|
||||
$.get('/browse/thumbnail/mkrange.jim', {
|
||||
'file': file,
|
||||
's': start+curval,
|
||||
'e': last+curval,
|
||||
'i': incr
|
||||
}, function() {
|
||||
$('img.bmp').each(function(i) {
|
||||
/* cast to "int" */
|
||||
var pos = $(this).attr('data-pos')|0;
|
||||
$(this).attr('src',
|
||||
'/browse/thumbnail/fetch.jim?' +
|
||||
'file=' + encodeURIComponent(file) +
|
||||
'&pos=' + (curval+pos).toFixed(1));
|
||||
});
|
||||
$('#genthumbs').button('option', 'icon', 'ui-icon-zoomin');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
draw_slider();
|
||||
|
||||
});
|
||||
$('#addbmark').button({icons: {primary: "ui-icon-plus"}, text: false})
|
||||
.on('click', function() {
|
||||
$('#bookmarks').val('0 ' + $('#bookmarks').val());
|
||||
curval = 0;
|
||||
draw_slider();
|
||||
});
|
||||
|
||||
$('#delbmark').button({icons: {primary: "ui-icon-minus"}, text: false})
|
||||
.on('click', function() {
|
||||
var cur = $('#bookmarks').val();
|
||||
cur = cur.replace(
|
||||
new RegExp('(^| )' + curval + '( |$)', ''), ' ').trim();
|
||||
$('#bookmarks').val(cur);
|
||||
draw_slider();
|
||||
});
|
||||
|
||||
$('#save').button({icons: {primary: "ui-icon-disk"}})
|
||||
.on('click', function() {
|
||||
$.post('save.jim', {
|
||||
file: file,
|
||||
bookmarks: $('#bookmarks').val()
|
||||
}, function(data) {
|
||||
$('#results').html(data)
|
||||
.slideDown('slow').delay(5000).slideUp('slow');
|
||||
});
|
||||
});
|
||||
|
||||
$('#back').button({icons: {primary: "ui-icon-arrowreturnthick-1-w"}})
|
||||
.on('click', function() {
|
||||
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', draw_slider);
|
||||
|
||||
$('#slider')
|
||||
.on('slidechange', function(evt, ui) {
|
||||
var tstr = toTimeStr(curval);
|
||||
if (tstr != $('#curbmk').html())
|
||||
regenthumbs(tstr);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -14,3 +14,20 @@
|
|||
margin-top: 5px;
|
||||
}
|
||||
|
||||
/* <table class=keyval ... cellpadding=5> */
|
||||
.keyval th, .keyval td
|
||||
{
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
/* <td align=right> */
|
||||
.cell-align-right
|
||||
{
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* <th style="text-align: center"> */
|
||||
th.mark
|
||||
{
|
||||
text-align: center;
|
||||
}
|
||||
|
|
|
@ -70,10 +70,6 @@ set newname "$shname-[clock seconds]"
|
|||
puts "Renaming file group to $newname"
|
||||
puts "<span class=hidden id=fileparams file=\"$dir/$newname.ts\"></span>"
|
||||
ts renamegroup "$dir/$shname.ts" $newname
|
||||
exec /mod/bin/hmt "+setfilename=$newname" "$dir/$newname.hmt"
|
||||
# New nicesplice shrinks whilst cropping.
|
||||
# No longer required - nicesplice now sets this flag.
|
||||
#exec /mod/bin/hmt "+shrunk" "$dir/$newname.hmt"
|
||||
|
||||
set croptime [expr [expr [clock milliseconds] - $cropstart] / 1000.0]
|
||||
puts "Time taken: $croptime"
|
||||
|
|
|
@ -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]}]} {
|
||||
|
|
|
@ -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 "<tr>
|
||||
<th>Flags</th>
|
||||
<td>[$ts get flags]</td>
|
||||
<td>[set flags [$ts get flags]]</td>
|
||||
</tr>
|
||||
"
|
||||
|
||||
|
@ -215,9 +219,6 @@ if {[$ts get bookmarks]} {
|
|||
"
|
||||
}
|
||||
|
||||
puts "
|
||||
</table>
|
||||
"
|
||||
puts "<div class=hidden id=file>$file</div>"
|
||||
puts {
|
||||
<script type=text/javascript>
|
||||
|
@ -256,12 +257,12 @@ $('img.rollimg').hover(
|
|||
|
||||
</script>
|
||||
}
|
||||
exit
|
||||
}
|
||||
|
||||
# Otherwise, for a general file.
|
||||
|
||||
puts "
|
||||
if {$type ne "ts"} {
|
||||
puts "
|
||||
<table class=keyval>
|
||||
<tr>
|
||||
<th>File</th>
|
||||
|
@ -269,20 +270,33 @@ puts "
|
|||
</tr><tr>
|
||||
<th>Size</th>
|
||||
<td>$sz</td>
|
||||
</tr><tr>
|
||||
</tr>"
|
||||
}
|
||||
|
||||
set hasffmpeg 0
|
||||
if {$type ne "ts" || ("ODEncrypted" ni $flags && $url eq "") } {
|
||||
puts "<tr>
|
||||
<th>Info</th>
|
||||
<td class=pre id=ffmpeg>
|
||||
<img src=/img/spin.gif><i>Loading...</i>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
"
|
||||
|
||||
set url "/browse/ffmpeg.jim?file=[cgi_quote_url $file]"
|
||||
puts { <script type="text/javascript"> }
|
||||
puts "var url = \"$url\";"
|
||||
puts {
|
||||
$('#ffmpeg').load(url);
|
||||
</script>
|
||||
</tr>"
|
||||
set hasffmpeg 1
|
||||
} elseif {$type eq "ts" && $url ne ""} {
|
||||
puts [format {
|
||||
<script type="text/javascript">
|
||||
$('#playDL').attr('href','%s').enable();
|
||||
</script> } $url]
|
||||
}
|
||||
puts "
|
||||
</table>
|
||||
"
|
||||
|
||||
if {$hasffmpeg} {
|
||||
set url "/browse/ffmpeg.jim?file=[cgi_quote_url $file]"
|
||||
puts [format {
|
||||
<script type="text/javascript">
|
||||
var url = "%s";
|
||||
$('#ffmpeg').load(url, function() { $('#play, #playDL').enable(); });
|
||||
</script> } $url]
|
||||
}
|
||||
|
|
|
@ -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 }
|
||||
|
|
|
@ -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 [file normalize $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}
|
||||
|
|
@ -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({
|
|||
'<img src="/img/spin.gif">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');
|
||||
});
|
||||
|
||||
|
@ -991,7 +1046,7 @@ $('#join').button({icons: {primary: "ui-icon-video"}})
|
|||
.click(function() {
|
||||
var files = new Array();
|
||||
var els = $('input.fsts:checked + a').each(function() {
|
||||
files.push($(this).attr('file'));
|
||||
files.push(encodeURIComponent($(this).attr('file')));
|
||||
});
|
||||
//console.log("%o", files);
|
||||
window.location.href = '/browse/join/join.jim?files=' +
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -362,7 +362,7 @@ $('button.manual_rsv').button({icons:{primary:"ui-icon-clock"}})
|
|||
|
||||
$('#mrform input.time').timepicker({
|
||||
showDuration: true,
|
||||
timeFormat: 'g:ia',
|
||||
timeFormat: 'H:i',
|
||||
step:5
|
||||
});
|
||||
|
||||
|
|
|
@ -13,16 +13,30 @@ if {[cgi_get act] eq "xtelnet"} {
|
|||
|
||||
if {[cgi_get act] eq "cryptokey"} {
|
||||
set val [cgi_get cryptokey ""]
|
||||
if {[string length "$val"] == 0} {
|
||||
set val [system encryptionkey]
|
||||
puts "Using native encryption key.<br>"
|
||||
set nkey [system encryptionkey]
|
||||
if {$val eq "" || [string equal -nocase $val $nkey]} {
|
||||
if {[system customencryptionkey] ne ""} {
|
||||
system customencryptionkey $nkey
|
||||
system nugget cryptokey -init
|
||||
puts "Using native encryption key."
|
||||
} else {
|
||||
puts "Native key unchanged."
|
||||
}
|
||||
set cryptokey ""
|
||||
} elseif {[string length $val] != 32} {
|
||||
puts "Encryption key is too short."
|
||||
exit
|
||||
puts "Encryption key must be 32 hexadecimal digits."
|
||||
} else {
|
||||
if {[string equal -nocase $val [system customencryptionkey]]} {
|
||||
puts "Custom key unchanged."
|
||||
} elseif {[set customkey [system customencryptionkey $val]] ne ""} {
|
||||
set cryptokey $customkey
|
||||
system nugget cryptokey -init
|
||||
puts "Installed new encryption key."
|
||||
} else {
|
||||
puts "Failed to install encryption key $val"
|
||||
}
|
||||
file write "/mod/boot/cryptokey" [binary format H* $val]
|
||||
system nugget cryptokey -init
|
||||
puts "Installed new encryption key."
|
||||
}
|
||||
puts "<br>"
|
||||
exit
|
||||
}
|
||||
|
||||
|
@ -33,15 +47,7 @@ set logsize [$settings logsize]
|
|||
set logkeep [$settings logkeep]
|
||||
set logage [$settings logage]
|
||||
|
||||
set cryptokey [system encryptionkey]
|
||||
if {![catch {set ck_fd [open "/mod/boot/cryptokey"]}]} {
|
||||
set ck_bytes [$ck_fd read 16]
|
||||
$ck_fd close
|
||||
binary scan $ck_bytes H* ck_key
|
||||
if {[string length $ck_key] == 32} {
|
||||
set cryptokey $ck_key
|
||||
}
|
||||
}
|
||||
set cryptokey [system customencryptionkey]
|
||||
|
||||
handle_int_update pkgdev $pkgdev "Development Package Display"
|
||||
handle_int_update rtschedule $rtschedule "Real-time scheduling"
|
||||
|
|
|
@ -60,7 +60,7 @@ puts "
|
|||
<table>
|
||||
<tr><th class=key>
|
||||
Native encryption key
|
||||
</th><td>[system encryptionkey]</td></tr>
|
||||
</th><td><span id=nativekey>[system encryptionkey]</span></td></tr>
|
||||
<tr>
|
||||
<form class=auto id=cryptokey method=post action=$env(SCRIPT_NAME)>
|
||||
<input type=hidden name=act value=cryptokey>
|
||||
|
@ -71,7 +71,26 @@ puts "
|
|||
<small><input value=set type=submit></small>
|
||||
<div id=cryptokey_output></div>
|
||||
</td>
|
||||
</form>
|
||||
</form>"
|
||||
# Script that clears the custom key input field when the native key
|
||||
# is restored by entering its full value (as shown in #nativekey).
|
||||
# We rely on magical knowledge that the form holding this <input> is
|
||||
# submitted with an Ajax call, and so we hook all successful Ajax calls,
|
||||
# but filter by the text returned (init.hook) to avoid unnecessary updates.
|
||||
puts {
|
||||
<script>
|
||||
$(document).ajaxSuccess(
|
||||
function(ev, jqXHR) {
|
||||
var ip;
|
||||
if ((jqXHR.responseText.indexOf("ative ") >= 0) &&
|
||||
($("#nativekey").html() == (ip = $("input[name=cryptokey]")).prop("value"))) {
|
||||
ip.prop("value", "");
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
}
|
||||
puts "
|
||||
</tr><tr>
|
||||
<td></td>
|
||||
<td class=blood>
|
||||
|
|
|
@ -2,77 +2,119 @@
|
|||
|
||||
source /mod/webif/lib/setup
|
||||
require system.class
|
||||
|
||||
if {[system model] eq "HDR"} {
|
||||
|
||||
require settings.class
|
||||
|
||||
set smartattrs {realloc pending offline spinretry}
|
||||
|
||||
set smartattribs(SMART_status) "Unknown"
|
||||
foreach sa $smartattrs {
|
||||
set smartattribs(SMART_$sa) 0
|
||||
set smartattribs(SMART_ack_$sa) 0
|
||||
}
|
||||
|
||||
foreach line [[settings] smartdata] {
|
||||
lassign $line x name x n x t
|
||||
if {$name eq "SMART_status"} {
|
||||
set smartattribs($name) $t
|
||||
} else {
|
||||
set smartattribs($name) $n
|
||||
proc {system disksmart} {} {
|
||||
set smartmsg ""
|
||||
|
||||
set smartattrs {realloc pending offline spinretry}
|
||||
|
||||
set smartattribs(SMART_status) "Unknown"
|
||||
foreach sa $smartattrs {
|
||||
set smartattribs(SMART_$sa) 0
|
||||
set smartattribs(SMART_ack_$sa) 0
|
||||
}
|
||||
}
|
||||
|
||||
# (SMART_ack_status 0 SMART_ack_pending 0 SMART_status PASSED SMART_pending 7 SMART_ack_realloc 0 SMART_ack_offline 0 SMART_realloc 0 SMART_offline 7)
|
||||
|
||||
set smartmsg ""
|
||||
if {$smartattribs(SMART_status) ne "PASSED"} {
|
||||
append smartmsg \
|
||||
"Disk overall health assessment is: $smartattribs(SMART_status)\n"
|
||||
}
|
||||
|
||||
foreach sa $smartattrs {
|
||||
if {$smartattribs(SMART_$sa) != $smartattribs(SMART_ack_$sa)} {
|
||||
append smartmsg \
|
||||
"Disk $sa sector count is: $smartattribs(SMART_$sa)"
|
||||
if {$smartattribs(SMART_ack_$sa) > 0} {
|
||||
append smartmsg " (was $smartattribs(SMART_ack_$sa))"
|
||||
|
||||
foreach line [[settings] smartdata] {
|
||||
lassign $line x name x n x t
|
||||
if {$name eq "SMART_status"} {
|
||||
set smartattribs($name) $t
|
||||
} else {
|
||||
set smartattribs($name) $n
|
||||
}
|
||||
append smartmsg "\n"
|
||||
}
|
||||
|
||||
# (SMART_ack_status 0 SMART_ack_pending 0 SMART_status PASSED SMART_pending 7 SMART_ack_realloc 0 SMART_ack_offline 0 SMART_realloc 0 SMART_offline 7)
|
||||
|
||||
if {$smartattribs(SMART_status) ne "PASSED"} {
|
||||
append smartmsg \
|
||||
"Disk overall health assessment is: $smartattribs(SMART_status)\n"
|
||||
}
|
||||
|
||||
foreach sa $smartattrs {
|
||||
if {$smartattribs(SMART_$sa) != $smartattribs(SMART_ack_$sa)} {
|
||||
append smartmsg \
|
||||
"Disk $sa sector count is: $smartattribs(SMART_$sa)"
|
||||
if {$smartattribs(SMART_ack_$sa) > 0} {
|
||||
append smartmsg " (was $smartattribs(SMART_ack_$sa))"
|
||||
}
|
||||
append smartmsg "\n"
|
||||
}
|
||||
}
|
||||
return $smartmsg
|
||||
}
|
||||
|
||||
if {$smartmsg ne ""} {
|
||||
proc {system diskro} {} {
|
||||
if {[system model] eq "HDR"} {
|
||||
set dev {/mnt/hd[1-3]}
|
||||
} else {
|
||||
set dev [system diskpart]
|
||||
}
|
||||
|
||||
# Python re: no POSIX character classes
|
||||
# Jim TCL regex: no \x character classes
|
||||
# Why not have both ...
|
||||
set s {[[:blank:]]}
|
||||
set a {[[:alnum:]]}
|
||||
set nc {[^,]}
|
||||
set roparts [lsearch -all -inline -regexp \
|
||||
[split [file read /proc/mounts] "\n\r"] \
|
||||
"${s}${dev}${s}+${a}+${s}*(${s}|${nc}+,)ro(,|$|${s})"]
|
||||
return [join [lmap line $roparts \
|
||||
{format "Filesystem %s on %s is read-only" [lindex $line 1] [lindex $line 0]}] "\n"]
|
||||
}
|
||||
|
||||
set smartmsg [system disksmart]
|
||||
set romsg [system diskro]
|
||||
|
||||
if {$smartmsg ne "" || $romsg ne ""} {
|
||||
if {![dict exists $env SCRIPT_NAME]} { set env(SCRIPT_NAME) "" }
|
||||
puts "
|
||||
<div id=smartwarning class=warningbox><center>
|
||||
puts {
|
||||
<div id=smartwarning class=warningbox style="width: 80%; left: 1%"><center>
|
||||
!! WARNING !!
|
||||
<br><br>
|
||||
There are potential hardware problems with the internal hard disk on
|
||||
this device.
|
||||
<br><br>
|
||||
<br><br>}
|
||||
set problems " "
|
||||
if {$smartmsg ne ""} {
|
||||
append problems "potential hardware"
|
||||
}
|
||||
if {$romsg ne ""} {
|
||||
if {[string index $problems end] ne " "} {
|
||||
append problems " and/or "
|
||||
}
|
||||
append problems "filesystem"
|
||||
}
|
||||
if {[string index $problems end] ne " "} {
|
||||
append problems " "
|
||||
}
|
||||
puts [format "
|
||||
There are %sproblems with the hard disk on
|
||||
this system.
|
||||
<br><br>" $problems]
|
||||
if {$smartmsg ne ""} {
|
||||
puts "
|
||||
[string map {"\n" "<br>"} $smartmsg]
|
||||
"
|
||||
<br>
|
||||
"
|
||||
}
|
||||
if {$romsg ne ""} {
|
||||
puts "
|
||||
[string map {"\n" "<br>"} $romsg]
|
||||
<br><br>
|
||||
"
|
||||
}
|
||||
if {$env(SCRIPT_NAME) ne "/diag/disk.jim"} {
|
||||
puts "
|
||||
<br>
|
||||
<a href=/diag/disk.jim>Go to disk diagnostics</a>
|
||||
"
|
||||
Go to <a href=/diag/disk.jim>Disk Diagnostics</a>
|
||||
"
|
||||
} else {
|
||||
puts "
|
||||
<br>
|
||||
Don't panic; for help, visit
|
||||
<a target=_blank
|
||||
href=http://wiki.hummy.tv/wiki/Disk_Problem>
|
||||
wiki.hummy.tv
|
||||
</a>
|
||||
"
|
||||
<br>
|
||||
Don't panic; for help, visit
|
||||
<a target=_blank href=\"http://wiki.hummy.tv/wiki/Disk_Problem\">wiki.hummy.tv</a>
|
||||
"
|
||||
}
|
||||
puts "
|
||||
</center></div>
|
||||
"
|
||||
}
|
||||
|
||||
"
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,10 @@ puts "<br>Loader Version: [system loaderver]"
|
|||
puts "<br>System ID: [system systemid]"
|
||||
puts "<br>Serial Number: [system serialno]"
|
||||
if {$mws::pagetag eq "Diagnostics"} {
|
||||
puts "<br>Encryption Key: [system encryptionkey]"
|
||||
puts "<br>Native Encryption Key: [system encryptionkey]"
|
||||
if {[set customkey [system customencryptionkey]] ne ""} {
|
||||
puts "<br>Custom Encryption Key: $customkey"
|
||||
}
|
||||
}
|
||||
puts "<br>Last Boot Reason: [system lastbootreason]"
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ if {[file exists /mod/tmp/notify.log]} {
|
|||
source /mod/webif/lib/setup
|
||||
|
||||
puts {
|
||||
<div id=sysnotify class=warningbox style="width: 90%"><center>
|
||||
<div id=sysnotify class=warningbox style="width: 90%;left: 1%"><center>
|
||||
!! WARNING !!
|
||||
<br><br>
|
||||
You have pending system notifications:
|
||||
|
|
|
@ -146,7 +146,7 @@ proc {queue dbqueryl} {query_list {txn_mode ""}} {
|
|||
|
||||
proc {queue startup} {{days 7}} {
|
||||
if {$days == 0} { set days 7 }
|
||||
return [queue dbqueryl { { {
|
||||
return [queue dbqueryl [list { {
|
||||
update queue
|
||||
set status = 'INTERRUPTED',
|
||||
log = 'Job will be retried automatically.',
|
||||
|
@ -163,12 +163,12 @@ proc {queue startup} {{days 7}} {
|
|||
update queue
|
||||
set status = 'PENDING'
|
||||
where status = 'DEFER'
|
||||
} } { {
|
||||
} } [list {
|
||||
delete from queue
|
||||
where status in ('COMPLETE', 'FAILED')
|
||||
and submitted < %s
|
||||
} [expr [clock seconds] - 86400 * $days]
|
||||
} } ]
|
||||
] ] ]
|
||||
}
|
||||
|
||||
proc {queue fetch} {file action} {
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -144,6 +144,13 @@ proc {system serialno} {} {{serial ""}} {
|
|||
string range $bytes 9 end]"
|
||||
return $serial
|
||||
}
|
||||
proc {system keybytestostring} {key_bytes} {
|
||||
binary scan $key_bytes H* key_str
|
||||
if {[string length $key_str] == 32} {
|
||||
return $key_str
|
||||
}
|
||||
return {}
|
||||
}
|
||||
|
||||
proc {system encryptionkey} {} {{key ""}} {
|
||||
if {$key ne ""} { return $key }
|
||||
|
@ -153,8 +160,46 @@ proc {system encryptionkey} {} {{key ""}} {
|
|||
$fd seek 0xcb800
|
||||
append bytes [$fd read 10]
|
||||
$fd close
|
||||
binary scan $bytes H* key
|
||||
return $key
|
||||
return [system keybytestostring $bytes]
|
||||
}
|
||||
|
||||
proc {system customencryptionkey} {{key ""}} {{keyfile "/mod/boot/cryptokey"}} {
|
||||
|
||||
set ck_fd {}
|
||||
try {
|
||||
if {$key eq ""} {
|
||||
set ck_fd [open $keyfile r]
|
||||
set ck_bytes [$ck_fd read 16]
|
||||
return [system keybytestostring $ck_bytes]
|
||||
} elseif {[string equal -nocase $key [system encryptionkey]]} {
|
||||
file delete -force $keyfile
|
||||
return $key
|
||||
} else {
|
||||
set ck_bytes [binary format H* $key]
|
||||
set test [system keybytestostring $ck_bytes]
|
||||
if {![string equal -nocase $test $key]} {
|
||||
throw 1 "Invalid custom key"
|
||||
}
|
||||
if {[file exists $keyfile]} {
|
||||
# attempt not to truncate on update until written
|
||||
set access r+
|
||||
} else {
|
||||
set access w
|
||||
}
|
||||
set ck_fd [open $keyfile $access]
|
||||
$ck_fd seek 0
|
||||
$ck_fd puts -nonewline $ck_bytes
|
||||
$ck_fd close
|
||||
set ck_fd {}
|
||||
return $key
|
||||
}
|
||||
} on error {msg opts} {
|
||||
return {}
|
||||
} finally {
|
||||
if {$ck_fd ne {}} {
|
||||
$ck_fd close
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
proc {system loaderver} {} {{ver ""}} {
|
||||
|
@ -270,7 +315,7 @@ proc {system dlnadb} {} {
|
|||
}
|
||||
|
||||
proc {system _dlnaurl} {file urlbase} {
|
||||
set mime "video/ts"
|
||||
set mime "video/mp2t"
|
||||
if {[catch {set db [sqlite3.open [system dlnadb]]}]} {
|
||||
return {}
|
||||
}
|
||||
|
@ -279,7 +324,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 {
|
||||
|
@ -298,7 +346,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 {}
|
||||
|
|
|
@ -863,16 +863,9 @@ ts method getkey {mode} {
|
|||
}
|
||||
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}
|
||||
set key [system customencryptionkey]
|
||||
if {$key ne ""} {
|
||||
ladd keys $key
|
||||
}
|
||||
|
||||
# the native key
|
||||
|
|
Loading…
Reference in New Issue