thrimbletrimmer: Add second page built for watching stream with a delay

This is for giffers, etc.

It shares the codecase but uses a flag to say whether to affect all the editor inputs.
pull/134/head
Mike Lang 5 years ago
parent 671079861a
commit 47ac1c7ff8

@ -41,9 +41,9 @@
</tr> </tr>
<tr> <tr>
<td><input id="StreamName" value="desertbus" /></td> <td><input id="StreamName" value="desertbus" /></td>
<td><input id="StreamStart" class="UTCTimeInput" value="" /> <td><input id="StreamStart" value="" />
<td><input id="StreamEnd" class="UTCTimeInput" value="" /> <td><input id="StreamEnd" value="" />
<td><input type="button" value="Load Playlist" onclick="loadPlaylist()" /></td> <td><input type="button" value="Load Playlist" onclick="loadPlaylist(true)" /></td>
</tr> </tr>
<tr> <tr>
<td></td> <td></td>
@ -93,8 +93,9 @@
</div> </div>
<input type="button" id="SubmitButton" value="Submit" onclick="thrimbletrimmerSubmit('EDITED')"/> <input type="button" id="SubmitButton" value="Submit" onclick="thrimbletrimmerSubmit('EDITED')"/>
<input type="button" id="DraftButton" value="Save Draft" onclick="thrimbletrimmerSubmit('UNEDITED')"/> <input type="button" id="DraftButton" value="Save Draft" onclick="thrimbletrimmerSubmit('UNEDITED')"/>
<input type="button" id="DownloadButton" value="Download" onclick="thrimbletrimmerDownload()"/> <input type="button" id="DownloadButton" value="Download" onclick="thrimbletrimmerDownload(true)"/>
<a href="/thrimbletrimmer/dashboard.html">Go To Dashboard</a> | <a href="/thrimbletrimmer/dashboard.html">Go To Dashboard</a> |
<a href="/thrimbletrimmer/stream.html">Go to Re-stream View</a> |
<a id="ManualLinkButton" href="JavaScript:toggleHiddenPane('ManualLinkPane');">Manual Link</a> | <a id="ManualLinkButton" href="JavaScript:toggleHiddenPane('ManualLinkPane');">Manual Link</a> |
<a id="ResetButton" href="JavaScript:thrimbletrimmerResetLink();">Reset Edits</a> <a id="ResetButton" href="JavaScript:thrimbletrimmerResetLink();">Reset Edits</a>
<a id="HelpButton" style="float:right;" href="JavaScript:toggleHiddenPane('HelpPane');">Help</a> <a id="HelpButton" style="float:right;" href="JavaScript:toggleHiddenPane('HelpPane');">Help</a>
@ -119,7 +120,7 @@
<script src="/thrimbletrimmer/scripts/keyboardShortcuts.js"></script> <script src="/thrimbletrimmer/scripts/keyboardShortcuts.js"></script>
<script src="/thrimbletrimmer/scripts/IO.js"></script> <script src="/thrimbletrimmer/scripts/IO.js"></script>
<script>pageSetup();</script> <script>pageSetup(true);</script>
<div class="g-signin2" data-onsuccess="onSignIn"></div> <div class="g-signin2" data-onsuccess="onSignIn"></div>
<a href="#" onclick="signOut();">Sign out</a> <a href="#" onclick="signOut();">Sign out</a>

@ -1,9 +1,9 @@
var desertBusStart = new Date("1970-01-01T00:00:00Z"); var desertBusStart = new Date("1970-01-01T00:00:00Z");
var timeFormat = 'BUSTIME'; var timeFormat = 'BUSTIME';
pageSetup = function() { pageSetup = function(isEditor) {
//Get values from ThrimShim //Get values from ThrimShim
if(/id=/.test(document.location.search)) { if(isEditor && /id=/.test(document.location.search)) {
var rowId = /id=(.*)(?:&|$)/.exec(document.location.search)[1]; var rowId = /id=(.*)(?:&|$)/.exec(document.location.search)[1];
fetch("/thrimshim/"+rowId).then(data => data.json()).then(function (data) { fetch("/thrimshim/"+rowId).then(data => data.json()).then(function (data) {
if (!data) { if (!data) {
@ -39,25 +39,26 @@ pageSetup = function() {
document.getElementById('wubloaderAdvancedInputTable').style.display = "block"; document.getElementById('wubloaderAdvancedInputTable').style.display = "block";
} }
loadPlaylist(data.video_start, data.video_end, data.video_quality); loadPlaylist(isEditor, data.video_start, data.video_end, data.video_quality);
}); });
} }
else { else {
document.getElementById('SubmitButton').disabled = true; if (isEditor) { document.getElementById('SubmitButton').disabled = true; }
fetch("/thrimshim/defaults").then(data => data.json()).then(function (data) { fetch("/thrimshim/defaults").then(data => data.json()).then(function (data) {
desertBusStart = new Date(data.bustime_start); desertBusStart = new Date(data.bustime_start);
document.getElementById("VideoTitlePrefix").value = data.title_prefix;
document.getElementById("VideoTitle").setAttribute("maxlength", data.title_max_length);
document.getElementById("StreamName").value = data.video_channel; document.getElementById("StreamName").value = data.video_channel;
setOptions('uploadLocation', data.upload_locations); if (isEditor) {
document.getElementById("VideoTitlePrefix").value = data.title_prefix;
document.getElementById("VideoTitle").setAttribute("maxlength", data.title_max_length);
setOptions('uploadLocation', data.upload_locations);
}
// Default time range to the last 10min. This is useful for immediate replay, etc. // Default time range from to the last 10min to live. This is useful for immediate replay, etc.
var end = new Date(); var start = new Date(new Date().getTime() - 1000*60*10);
var start = new Date(end.getTime() - 1000*60*10); setTimeRange(start, null);
setTimeRange(start, end);
loadPlaylist(); loadPlaylist(isEditor);
}); });
} }
@ -118,6 +119,15 @@ getTimeRange = function() {
}; };
} }
getTimeRangeAsTimestamp = function() {
var range = getTimeRange();
return {
// if not null, format as timestamp
start: range.start && toTimestamp(range.start),
end: range.end && toTimestamp(range.end),
};
}
toggleHiddenPane = function(paneID) { toggleHiddenPane = function(paneID) {
var pane = document.getElementById(paneID); var pane = document.getElementById(paneID);
pane.style.display = (pane.style.display === "none") ? "block":"none"; pane.style.display = (pane.style.display === "none") ? "block":"none";
@ -153,31 +163,27 @@ buildQuery = function(params) {
).join('&'); ).join('&');
} }
loadPlaylist = function(startTrim, endTrim, defaultQuality) { loadPlaylist = function(isEditor, startTrim, endTrim, defaultQuality) {
var playlist = "/playlist/" + document.getElementById("StreamName").value + ".m3u8"; var playlist = "/playlist/" + document.getElementById("StreamName").value + ".m3u8";
var range = getTimeRange(); var range = getTimeRangeAsTimestamp();
var queryString = buildQuery({ var queryString = buildQuery(range);
// if not null, format as timestamp
start: range.start && toTimestamp(range.start), setupPlayer(isEditor, playlist + '?' + queryString, startTrim, endTrim);
end: range.end && toTimestamp(range.end),
//Get quality levels for advanced properties / download
document.getElementById('qualityLevel').innerHTML = "";
fetch('/files/' + document.getElementById('StreamName').value).then(data => data.json()).then(function (data) {
if (!data.length) {
console.log("Could not retrieve quality levels");
return;
}
var qualityLevels = data.sort().reverse();
setOptions('qualityLevel', qualityLevels, defaultQuality);
if (!!defaultQuality && qualityLevels.length > 0 && defaultQuality != qualityLevels[0]) {
document.getElementById('wubloaderAdvancedInputTable').style.display = "block";
}
}); });
setupPlayer(playlist + '?' + queryString, startTrim, endTrim);
//Get quality levels for advanced properties.
document.getElementById('qualityLevel').innerHTML = "";
fetch('/files/' + document.getElementById('StreamName').value).then(data => data.json()).then(function (data) {
if (!data.length) {
console.log("Could not retrieve quality levels");
return;
}
var qualityLevels = data.sort().reverse();
setOptions('qualityLevel', qualityLevels, defaultQuality);
if (!!defaultQuality && qualityLevels.length > 0 && defaultQuality != qualityLevels[0]) {
document.getElementById('wubloaderAdvancedInputTable').style.display = "block";
}
});
}; };
thrimbletrimmerSubmit = function(state) { thrimbletrimmerSubmit = function(state) {
@ -226,25 +232,28 @@ thrimbletrimmerSubmit = function(state) {
})); }));
}; };
thrimbletrimmerDownload = function() { thrimbletrimmerDownload = function(isEditor) {
if(player.trimmingControls().options.startTrim >= player.trimmingControls().options.endTrim) { var range = getTimeRangeAsTimestamp();
alert("End Time must be greater than Start Time"); if (isEditor) {
} else { if(player.trimmingControls().options.startTrim >= player.trimmingControls().options.endTrim) {
var discontinuities = mapDiscontinuities(); alert("End Time must be greater than Start Time");
return;
var downloadStart = getRealTimeForPlayerTime(discontinuities, player.trimmingControls().options.startTrim); }
var downloadEnd = getRealTimeForPlayerTime(discontinuities, player.trimmingControls().options.endTrim); var discontinuities = mapDiscontinuities();
range.start = getRealTimeForPlayerTime(discontinuities, player.trimmingControls().options.startTrim);
var targetURL = "/cut/" + document.getElementById("StreamName").value + range.end = getRealTimeForPlayerTime(discontinuities, player.trimmingControls().options.endTrim);
"/"+document.getElementById('qualityLevel').options[document.getElementById('qualityLevel').options.selectedIndex].value+".ts" + }
"?" + buildQuery({
start: downloadStart, var targetURL = "/cut/" + document.getElementById("StreamName").value +
end: downloadEnd, "/"+document.getElementById('qualityLevel').options[document.getElementById('qualityLevel').options.selectedIndex].value+".ts" +
allow_holes: String(document.getElementById('AllowHoles').checked), "?" + buildQuery({
}); start: range.start,
console.log(targetURL); end: range.end,
document.getElementById('outputFile').src = targetURL; // Always allow holes in non-editor, accidentially including holes isn't important
} allow_holes: (isEditor) ? String(document.getElementById('AllowHoles').checked) : "true",
});
console.log(targetURL);
document.getElementById('outputFile').src = targetURL;
}; };
thrimbletrimmerManualLink = function() { thrimbletrimmerManualLink = function() {

@ -1,6 +1,6 @@
var player = null; var player = null;
function setupPlayer(source, startTrim, endTrim) { function setupPlayer(isEditor, source, startTrim, endTrim) {
document.getElementById("my-player").style.display = ""; document.getElementById("my-player").style.display = "";
//Make poster of DB logo in correct aspect ratio, to control initial size of fluid container. //Make poster of DB logo in correct aspect ratio, to control initial size of fluid container.
var options = { var options = {
@ -39,10 +39,12 @@ function setupPlayer(source, startTrim, endTrim) {
this.vhs.playlists.on('loadedmetadata', function() { this.vhs.playlists.on('loadedmetadata', function() {
// setTimeout(function() { player.play(); }, 1000); // setTimeout(function() { player.play(); }, 1000);
player.hasStarted(true); //So it displays all the controls. player.hasStarted(true); //So it displays all the controls.
var stream_start = player.vhs.playlists.master.playlists.filter(playlist => typeof playlist.discontinuityStarts !== "undefined")[0].dateTimeObject; if (isEditor) {
startTrim = startTrim ? (new Date(startTrim+"Z")-stream_start)/1000:0; var stream_start = player.vhs.playlists.master.playlists.filter(playlist => typeof playlist.discontinuityStarts !== "undefined")[0].dateTimeObject;
endTrim = endTrim ? (new Date(endTrim+"Z")-stream_start)/1000:player.duration(); startTrim = startTrim ? (new Date(startTrim+"Z")-stream_start)/1000:0;
var trimmingControls = player.trimmingControls({ startTrim:startTrim, endTrim:endTrim }); endTrim = endTrim ? (new Date(endTrim+"Z")-stream_start)/1000:player.duration();
var trimmingControls = player.trimmingControls({ startTrim:startTrim, endTrim:endTrim });
}
}); });
// How about an event listener? // How about an event listener?

@ -0,0 +1,77 @@
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>VST Re-stream</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="/thrimbletrimmer/plugins/video.js/dist/video-js.min.css" rel="stylesheet">
<link href="/thrimbletrimmer/plugins/videojs-hls-quality-selector/dist/videojs-hls-quality-selector.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<script src="/thrimbletrimmer/plugins/video.js/dist/video.min.js"></script>
<script src="/thrimbletrimmer/plugins/videojs-contrib-quality-levels/dist/videojs-contrib-quality-levels.min.js"></script>
<script src="/thrimbletrimmer/plugins/videojs-hls-quality-selector/dist/videojs-hls-quality-selector.min.js"></script>
<link href="/thrimbletrimmer/styles/style.css" rel="stylesheet">
</head>
<body>
<div style="max-width:1280px;margin:auto;padding-top:25px;">
<table id="wubloaderInputTable">
<tr>
<th>Stream</th>
<th>Start Time</th>
<th>End Time (blank for live)</th>
<th></th>
</tr>
<tr>
<td><input id="StreamName" value="desertbus" /></td>
<td><input id="StreamStart" value="" />
<td><input id="StreamEnd" value="" />
<td><input type="button" value="Load Playlist" onclick="loadPlaylist()" /></td>
</tr>
<tr>
<td></td>
<td></td>
<td>
<input type="radio" id="BusTimeToggleUTC" name="BusTimeToggle" value="UTC" onclick="toggleTimeInput(this.value)"> UTC
<input type="radio" id="BusTimeToggleBus" name="BusTimeToggle" value="BUSTIME" onclick="toggleTimeInput(this.value)" checked="checked"> Bustime
</td>
</tr>
</table>
<div id="EditorContainer">
<video id="my-player" class="video-js" controls preload="auto" style="display:none">
<p class="vjs-no-js">To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="http://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a></p>
</video>
</div>
<div id="EditorDetailsPane">
Download Quality: <select id="qualityLevel"></select>
<input type="button" id="DownloadButton" value="Download this time range" onclick="thrimbletrimmerDownload()"/>
<a href="/thrimbletrimmer/dashboard.html">Go To Dashboard</a> |
<a href="/thrimbletrimmer/dashboard.html">Go To Editor</a> |
<a id="HelpButton" style="float:right;" href="JavaScript:toggleHiddenPane('HelpPane');">Help</a>
<a id="UltrawideButton" style="float:right;margin-right:10px;" href="JavaScript:toggleUltrawide();">Ultrawide</a>
</div>
<div id="HelpPane" style="display:none;">
<ul>
<li>J/K/L - Back 10 seconds, Play/Pause, Advance 10 seconds</li>
<li>LeftArrow/RightArrow - Back 5 seconds, Advance 5 seconds</li>
<li>,/. - Back 0.1 seconds, Advance 0.1 seconds</li>
<li>0-9 - Jump to 0% - 90% through the video.</li>
</ul>
</div>
</div>
<iframe id="outputFile" style="display:none;"></iframe>
<script src="/thrimbletrimmer/scripts/playerSetup.js"></script>
<script src="/thrimbletrimmer/scripts/keyboardShortcuts.js"></script>
<script src="/thrimbletrimmer/scripts/IO.js"></script>
<script>pageSetup();</script>
</body>
</html>
Loading…
Cancel
Save