From 971841d73b65d1754276a124887ec3168b0cd863 Mon Sep 17 00:00:00 2001 From: Mike Lang Date: Sun, 27 Oct 2019 02:25:18 -0700 Subject: [PATCH 01/14] thrimbletrimmer: Move last bit of code into IO.js since everything else is there anyway. --- thrimbletrimmer/index.html | 25 ------------------------- thrimbletrimmer/scripts/IO.js | 26 ++++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/thrimbletrimmer/index.html b/thrimbletrimmer/index.html index eceb298..b64b52d 100644 --- a/thrimbletrimmer/index.html +++ b/thrimbletrimmer/index.html @@ -120,31 +120,6 @@ -
Sign out diff --git a/thrimbletrimmer/scripts/IO.js b/thrimbletrimmer/scripts/IO.js index 16225e9..8a6c70f 100644 --- a/thrimbletrimmer/scripts/IO.js +++ b/thrimbletrimmer/scripts/IO.js @@ -90,6 +90,32 @@ setStreamRange = function() { document.getElementById("StreamEnd").value = bustimeToTimestamp(document.getElementById("BusTimeEnd").value); } +toggleHiddenPane = function(paneID) { + var pane = document.getElementById(paneID); + pane.style.display = (pane.style.display === "none") ? "block":"none"; +} + +toggleUltrawide = function() { + var body = document.getElementsByTagName("Body")[0]; + body.classList.contains("ultrawide") ? body.classList.remove("ultrawide"):body.classList.add("ultrawide"); +} + +toggleTimeInput = function(toggleInput) { + if(toggleInput == "UTC") { + setStreamRange(); + document.getElementById("BusTimeStart").style.display = "none"; + document.getElementById("BusTimeEnd").style.display = "none"; + document.getElementById("StreamStart").style.display = ""; + document.getElementById("StreamEnd").style.display = ""; + } else { + setBustimeRange(); + document.getElementById("StreamStart").style.display = "none"; + document.getElementById("StreamEnd").style.display = "none"; + document.getElementById("BusTimeStart").style.display = ""; + document.getElementById("BusTimeEnd").style.display = ""; + } +} + // For a given select input element id, add the given list of options. // If selected is given, it should be the name of an option to select. // Otherwise the first one is used. From 316504899a0d1643241b4a47539db146ba9c5bca Mon Sep 17 00:00:00 2001 From: Mike Lang Date: Sun, 27 Oct 2019 02:25:47 -0700 Subject: [PATCH 02/14] thrimbletrimmer: Fix a bug on initial load loadPlaylist was happening before bustime was set, resulting in the wrong times being loaded. --- thrimbletrimmer/scripts/IO.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/thrimbletrimmer/scripts/IO.js b/thrimbletrimmer/scripts/IO.js index 8a6c70f..e448edd 100644 --- a/thrimbletrimmer/scripts/IO.js +++ b/thrimbletrimmer/scripts/IO.js @@ -58,9 +58,10 @@ pageSetup = function() { document.getElementById("StreamStart").value = new Date(new Date().getTime() - 1000*60*10).toISOString().substring(0,19); document.getElementById("StreamEnd").value = new Date().toISOString().substring(0,19); setBustimeRange(); + + loadPlaylist(); }); - loadPlaylist(); } }; From 8accc1338e2c7c229e0fa56c4dcfdcd2cf90289a Mon Sep 17 00:00:00 2001 From: Mike Lang Date: Sun, 27 Oct 2019 03:24:03 -0700 Subject: [PATCH 03/14] thrimbletrimmer: Refactor how time formatting is handled Instead of having two input fields and switching between them, we just have one and re-write the value on switch. We also handle invalid or empty dates a LOT better, and clean up some other things around query strings. --- thrimbletrimmer/index.html | 4 +- thrimbletrimmer/scripts/IO.js | 112 +++++++++++++++++++++------------- 2 files changed, 70 insertions(+), 46 deletions(-) diff --git a/thrimbletrimmer/index.html b/thrimbletrimmer/index.html index b64b52d..cb6a9eb 100644 --- a/thrimbletrimmer/index.html +++ b/thrimbletrimmer/index.html @@ -41,8 +41,8 @@ - - + + diff --git a/thrimbletrimmer/scripts/IO.js b/thrimbletrimmer/scripts/IO.js index e448edd..626e90d 100644 --- a/thrimbletrimmer/scripts/IO.js +++ b/thrimbletrimmer/scripts/IO.js @@ -1,4 +1,5 @@ var desertBusStart = new Date("1970-01-01T00:00:00Z"); +var timeFormat = 'BUSTIME'; pageSetup = function() { //Get values from ThrimShim @@ -15,10 +16,7 @@ pageSetup = function() { document.getElementById("StreamName").value = data.video_channel; document.getElementById("hiddenSubmissionID").value = data.id; - // set stream start/end, then copy to bustime inputs - document.getElementById("StreamStart").value = data.event_start; - document.getElementById("StreamEnd").value = data.event_end; - setBustimeRange(); + setTimeRange(fromTimestamp(data.event_start), fromTimestamp(data.event_end)); // title and description both default to row description document.getElementById("VideoTitle").value = data.video_title ? data.video_title : data.description; document.getElementById("VideoDescription").value = data.video_description ? data.video_description : data.description; @@ -54,10 +52,10 @@ pageSetup = function() { document.getElementById("StreamName").value = data.video_channel; setOptions('uploadLocation', data.upload_locations); - // Default time range to the last 10min. This is useful for giffers, immediate replay, etc. - document.getElementById("StreamStart").value = new Date(new Date().getTime() - 1000*60*10).toISOString().substring(0,19); - document.getElementById("StreamEnd").value = new Date().toISOString().substring(0,19); - setBustimeRange(); + // Default time range to the last 10min. This is useful for immediate replay, etc. + end = new Date(); + start = new Date(end.getTime() - 1000*60*10); + setTimeRange(start, end); loadPlaylist(); }); @@ -65,12 +63,13 @@ pageSetup = function() { } }; -timestampToBustime = function(ts) { - date = new Date(ts + "Z"); +// Time-formatting functions + +toBustime = function(date) { return (date < desertBusStart ? "-":"") + videojs.formatTime(Math.abs((date - desertBusStart)/1000), 600.01).padStart(7, "0:"); }; -bustimeToTimestamp = function(bustime) { +fromBustime = function(bustime) { direction = 1; if(bustime.startsWith("-")) { bustime = bustime.slice(1); @@ -78,17 +77,45 @@ bustimeToTimestamp = function(bustime) { } parts = bustime.split(':') bustime_ms = (parseInt(parts[0]) + parts[1]/60 + parts[2]/3600) * 1000 * 60 * 60; - return new Date(desertBusStart.getTime() + direction * bustime_ms).toISOString().substring(0, 19); + return new Date(desertBusStart.getTime() + direction * bustime_ms); }; -setBustimeRange = function() { - document.getElementById("BusTimeStart").value = timestampToBustime(document.getElementById("StreamStart").value); - document.getElementById("BusTimeEnd").value = timestampToBustime(document.getElementById("StreamEnd").value); -}; +toTimestamp = function(date) { + return date.toISOString().substring(0, 19); +} -setStreamRange = function() { - document.getElementById("StreamStart").value = bustimeToTimestamp(document.getElementById("BusTimeStart").value); - document.getElementById("StreamEnd").value = bustimeToTimestamp(document.getElementById("BusTimeEnd").value); +fromTimestamp = function(ts) { + return new Date(ts + "Z"); +} + +// Set the stream start/end range from a pair of Dates using the current format +// If given null, sets to blank. +setTimeRange = function(start, end) { + toFunc = { + UTC: toTimestamp, + BUSTIME: toBustime, + }[timeFormat]; + document.getElementById("StreamStart").value = (start) ? toFunc(start) : ""; + document.getElementById("StreamEnd").value = (end) ? toFunc(end) : ""; +} + +// Get the current start/end range as Dates using the current format +// Returns an object containing 'start' and 'end' fields. +// If either is empty / invalid, returns null. +getTimeRange = function() { + fromFunc = { + UTC: fromTimestamp, + BUSTIME: fromBustime, + }[timeFormat]; + convert = function(value) { + if (!value) { return null; } + date = fromFunc(value); + return (isNaN(date)) ? null : date; + }; + return { + start: convert(document.getElementById("StreamStart").value), + end: convert(document.getElementById("StreamEnd").value), + }; } toggleHiddenPane = function(paneID) { @@ -102,19 +129,10 @@ toggleUltrawide = function() { } toggleTimeInput = function(toggleInput) { - if(toggleInput == "UTC") { - setStreamRange(); - document.getElementById("BusTimeStart").style.display = "none"; - document.getElementById("BusTimeEnd").style.display = "none"; - document.getElementById("StreamStart").style.display = ""; - document.getElementById("StreamEnd").style.display = ""; - } else { - setBustimeRange(); - document.getElementById("StreamStart").style.display = "none"; - document.getElementById("StreamEnd").style.display = "none"; - document.getElementById("BusTimeStart").style.display = ""; - document.getElementById("BusTimeEnd").style.display = ""; - } + // Get times using current format, then change format, then write them back + range = getTimeRange(); + timeFormat = toggleInput; + setTimeRange(range.start, range.end); } // For a given select input element id, add the given list of options. @@ -129,19 +147,23 @@ setOptions = function(element, options, selected) { }); } +buildQuery = function(params) { + return Object.keys(params).filter(key => params[key] !== null).map(key => + encodeURIComponent(key) + '=' + encodeURIComponent(params[key]) + ).join('&'); +} + loadPlaylist = function(startTrim, endTrim, defaultQuality) { var playlist = "/playlist/" + document.getElementById("StreamName").value + ".m3u8"; - // If we're using bustime, update stream start/end from it first - if(document.getElementById("BusTimeToggleBus").checked) { - setStreamRange(); - } - - var streamStart = document.getElementById("StreamStart").value ? "start="+document.getElementById("StreamStart").value:null; - var streamEnd = document.getElementById("StreamEnd").value ? "end="+document.getElementById("StreamEnd").value:null; - var queryString = (streamStart || streamEnd) ? "?" + [streamStart, streamEnd].filter((a) => !!a).join("&"):""; + var range = getTimeRange(); + var queryString = buildQuery({ + // if not null, format as timestamp + start: range.start && toTimestamp(range.start), + end: range.end && toTimestamp(range.end), + }); - setupPlayer(playlist + queryString, startTrim, endTrim); + setupPlayer(playlist + '?' + queryString, startTrim, endTrim); //Get quality levels for advanced properties. document.getElementById('qualityLevel').innerHTML = ""; @@ -215,9 +237,11 @@ thrimbletrimmerDownload = function() { var targetURL = "/cut/" + document.getElementById("StreamName").value + "/"+document.getElementById('qualityLevel').options[document.getElementById('qualityLevel').options.selectedIndex].value+".ts" + - "?start=" + downloadStart + - "&end=" + downloadEnd + - "&allow_holes=" + String(document.getElementById('AllowHoles').checked); + "?" + buildQuery({ + start: downloadStart, + end: downloadEnd, + allow_holes: String(document.getElementById('AllowHoles').checked), + }); console.log(targetURL); document.getElementById('outputFile').src = targetURL; } From 671079861ad3094a139772ad9737c706bb2d0712 Mon Sep 17 00:00:00 2001 From: Mike Lang Date: Sun, 27 Oct 2019 03:34:42 -0700 Subject: [PATCH 04/14] thrimbletrimmer: Fix lack of usage of var throughout code Chalk this one up to not knowing the language. You need to declare variables as var otherwise they're implicitly globals. This leads to many bugs where if a function runs twice at once it'll do weird things. --- thrimbletrimmer/scripts/IO.js | 28 +++++++++++++------------- thrimbletrimmer/scripts/playerSetup.js | 3 +-- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/thrimbletrimmer/scripts/IO.js b/thrimbletrimmer/scripts/IO.js index 626e90d..95184f0 100644 --- a/thrimbletrimmer/scripts/IO.js +++ b/thrimbletrimmer/scripts/IO.js @@ -53,8 +53,8 @@ pageSetup = function() { setOptions('uploadLocation', data.upload_locations); // Default time range to the last 10min. This is useful for immediate replay, etc. - end = new Date(); - start = new Date(end.getTime() - 1000*60*10); + var end = new Date(); + var start = new Date(end.getTime() - 1000*60*10); setTimeRange(start, end); loadPlaylist(); @@ -70,13 +70,13 @@ toBustime = function(date) { }; fromBustime = function(bustime) { - direction = 1; + var direction = 1; if(bustime.startsWith("-")) { bustime = bustime.slice(1); direction = -1; } - parts = bustime.split(':') - bustime_ms = (parseInt(parts[0]) + parts[1]/60 + parts[2]/3600) * 1000 * 60 * 60; + var parts = bustime.split(':') + var bustime_ms = (parseInt(parts[0]) + parts[1]/60 + parts[2]/3600) * 1000 * 60 * 60; return new Date(desertBusStart.getTime() + direction * bustime_ms); }; @@ -91,7 +91,7 @@ fromTimestamp = function(ts) { // Set the stream start/end range from a pair of Dates using the current format // If given null, sets to blank. setTimeRange = function(start, end) { - toFunc = { + var toFunc = { UTC: toTimestamp, BUSTIME: toBustime, }[timeFormat]; @@ -103,13 +103,13 @@ setTimeRange = function(start, end) { // Returns an object containing 'start' and 'end' fields. // If either is empty / invalid, returns null. getTimeRange = function() { - fromFunc = { + var fromFunc = { UTC: fromTimestamp, BUSTIME: fromBustime, }[timeFormat]; convert = function(value) { if (!value) { return null; } - date = fromFunc(value); + var date = fromFunc(value); return (isNaN(date)) ? null : date; }; return { @@ -130,7 +130,7 @@ toggleUltrawide = function() { toggleTimeInput = function(toggleInput) { // Get times using current format, then change format, then write them back - range = getTimeRange(); + var range = getTimeRange(); timeFormat = toggleInput; setTimeRange(range.start, range.end); } @@ -214,7 +214,7 @@ thrimbletrimmerSubmit = function(state) { }) .then(response => response.text().then(text => { if (!response.ok) { - error = response.statusText + ": " + text; + var error = response.statusText + ": " + text; console.log(error); alert(error); } else if (state == 'EDITED') { @@ -250,7 +250,7 @@ thrimbletrimmerDownload = function() { thrimbletrimmerManualLink = function() { document.getElementById("ManualButton").disabled = true; var rowId = /id=(.*)(?:&|$)/.exec(document.location.search)[1]; - body = {link: document.getElementById("ManualLink").value}; + var body = {link: document.getElementById("ManualLink").value}; if (!!user) { body.token = user.getAuthResponse().id_token; } @@ -264,7 +264,7 @@ thrimbletrimmerManualLink = function() { }) .then(response => response.text().then(text => { if (!response.ok) { - error = response.statusText + ": " + text; + var error = response.statusText + ": " + text; console.log(error); alert(error); document.getElementById("ManualButton").disabled = false; @@ -287,7 +287,7 @@ thrimbletrimmerResetLink = function() { return; } document.getElementById("ResetButton").disabled = true; - body = {} + var body = {} if (!!user) { body.token = user.getAuthResponse().id_token; } @@ -301,7 +301,7 @@ thrimbletrimmerResetLink = function() { }) .then(response => response.text().then(text => { if (!response.ok) { - error = response.statusText + ": " + text; + var error = response.statusText + ": " + text; console.log(error); alert(error); document.getElementById("ResetButton").disabled = false; diff --git a/thrimbletrimmer/scripts/playerSetup.js b/thrimbletrimmer/scripts/playerSetup.js index 77f2c86..64662f6 100644 --- a/thrimbletrimmer/scripts/playerSetup.js +++ b/thrimbletrimmer/scripts/playerSetup.js @@ -39,7 +39,7 @@ function setupPlayer(source, startTrim, endTrim) { this.vhs.playlists.on('loadedmetadata', function() { // setTimeout(function() { player.play(); }, 1000); player.hasStarted(true); //So it displays all the controls. - stream_start = player.vhs.playlists.master.playlists.filter(playlist => typeof playlist.discontinuityStarts !== "undefined")[0].dateTimeObject; + var stream_start = player.vhs.playlists.master.playlists.filter(playlist => typeof playlist.discontinuityStarts !== "undefined")[0].dateTimeObject; startTrim = startTrim ? (new Date(startTrim+"Z")-stream_start)/1000:0; endTrim = endTrim ? (new Date(endTrim+"Z")-stream_start)/1000:player.duration(); var trimmingControls = player.trimmingControls({ startTrim:startTrim, endTrim:endTrim }); @@ -56,7 +56,6 @@ function setupPlayer(source, startTrim, endTrim) { }) }); var hlsQS = player.hlsQualitySelector(); - //var trimmingControls = player.trimmingControls({ startTrim:(startTrim ? startTrim:0), endTrim:(endTrim ? endTrim:player.duration()) }); } mapDiscontinuities = function() { From 47ac1c7ff87e10614ef3d5a48c015442a5dae2b8 Mon Sep 17 00:00:00 2001 From: Mike Lang Date: Sun, 27 Oct 2019 04:48:38 -0700 Subject: [PATCH 05/14] 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. --- thrimbletrimmer/index.html | 11 +-- thrimbletrimmer/scripts/IO.js | 115 +++++++++++++------------ thrimbletrimmer/scripts/playerSetup.js | 12 +-- thrimbletrimmer/stream.html | 77 +++++++++++++++++ 4 files changed, 152 insertions(+), 63 deletions(-) create mode 100644 thrimbletrimmer/stream.html diff --git a/thrimbletrimmer/index.html b/thrimbletrimmer/index.html index cb6a9eb..2700bc2 100644 --- a/thrimbletrimmer/index.html +++ b/thrimbletrimmer/index.html @@ -41,9 +41,9 @@ - - - + + + @@ -93,8 +93,9 @@ - + Go To Dashboard | + Go to Re-stream View | Manual Link | Reset Edits Help @@ -119,7 +120,7 @@ - +
Sign out diff --git a/thrimbletrimmer/scripts/IO.js b/thrimbletrimmer/scripts/IO.js index 95184f0..d0e4aa9 100644 --- a/thrimbletrimmer/scripts/IO.js +++ b/thrimbletrimmer/scripts/IO.js @@ -1,9 +1,9 @@ var desertBusStart = new Date("1970-01-01T00:00:00Z"); var timeFormat = 'BUSTIME'; -pageSetup = function() { +pageSetup = function(isEditor) { //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]; fetch("/thrimshim/"+rowId).then(data => data.json()).then(function (data) { if (!data) { @@ -39,25 +39,26 @@ pageSetup = function() { 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 { - document.getElementById('SubmitButton').disabled = true; + if (isEditor) { document.getElementById('SubmitButton').disabled = true; } fetch("/thrimshim/defaults").then(data => data.json()).then(function (data) { 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; - 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. - var end = new Date(); - var start = new Date(end.getTime() - 1000*60*10); - setTimeRange(start, end); + // Default time range from to the last 10min to live. This is useful for immediate replay, etc. + var start = new Date(new Date().getTime() - 1000*60*10); + setTimeRange(start, null); - 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) { var pane = document.getElementById(paneID); pane.style.display = (pane.style.display === "none") ? "block":"none"; @@ -153,31 +163,27 @@ buildQuery = function(params) { ).join('&'); } -loadPlaylist = function(startTrim, endTrim, defaultQuality) { +loadPlaylist = function(isEditor, startTrim, endTrim, defaultQuality) { var playlist = "/playlist/" + document.getElementById("StreamName").value + ".m3u8"; - var range = getTimeRange(); - var queryString = buildQuery({ - // if not null, format as timestamp - start: range.start && toTimestamp(range.start), - end: range.end && toTimestamp(range.end), + var range = getTimeRangeAsTimestamp(); + var queryString = buildQuery(range); + + setupPlayer(isEditor, playlist + '?' + queryString, startTrim, endTrim); + + //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) { @@ -226,25 +232,28 @@ thrimbletrimmerSubmit = function(state) { })); }; -thrimbletrimmerDownload = function() { - if(player.trimmingControls().options.startTrim >= player.trimmingControls().options.endTrim) { - alert("End Time must be greater than Start Time"); - } else { - var discontinuities = mapDiscontinuities(); - - var downloadStart = getRealTimeForPlayerTime(discontinuities, player.trimmingControls().options.startTrim); - var downloadEnd = getRealTimeForPlayerTime(discontinuities, player.trimmingControls().options.endTrim); - - var targetURL = "/cut/" + document.getElementById("StreamName").value + - "/"+document.getElementById('qualityLevel').options[document.getElementById('qualityLevel').options.selectedIndex].value+".ts" + - "?" + buildQuery({ - start: downloadStart, - end: downloadEnd, - allow_holes: String(document.getElementById('AllowHoles').checked), - }); - console.log(targetURL); - document.getElementById('outputFile').src = targetURL; - } +thrimbletrimmerDownload = function(isEditor) { + var range = getTimeRangeAsTimestamp(); + if (isEditor) { + if(player.trimmingControls().options.startTrim >= player.trimmingControls().options.endTrim) { + alert("End Time must be greater than Start Time"); + return; + } + var discontinuities = mapDiscontinuities(); + range.start = getRealTimeForPlayerTime(discontinuities, player.trimmingControls().options.startTrim); + range.end = getRealTimeForPlayerTime(discontinuities, player.trimmingControls().options.endTrim); + } + + var targetURL = "/cut/" + document.getElementById("StreamName").value + + "/"+document.getElementById('qualityLevel').options[document.getElementById('qualityLevel').options.selectedIndex].value+".ts" + + "?" + buildQuery({ + start: range.start, + end: range.end, + // 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() { diff --git a/thrimbletrimmer/scripts/playerSetup.js b/thrimbletrimmer/scripts/playerSetup.js index 64662f6..d8c827e 100644 --- a/thrimbletrimmer/scripts/playerSetup.js +++ b/thrimbletrimmer/scripts/playerSetup.js @@ -1,6 +1,6 @@ var player = null; -function setupPlayer(source, startTrim, endTrim) { +function setupPlayer(isEditor, source, startTrim, endTrim) { document.getElementById("my-player").style.display = ""; //Make poster of DB logo in correct aspect ratio, to control initial size of fluid container. var options = { @@ -39,10 +39,12 @@ function setupPlayer(source, startTrim, endTrim) { this.vhs.playlists.on('loadedmetadata', function() { // setTimeout(function() { player.play(); }, 1000); 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; - startTrim = startTrim ? (new Date(startTrim+"Z")-stream_start)/1000:0; - endTrim = endTrim ? (new Date(endTrim+"Z")-stream_start)/1000:player.duration(); - var trimmingControls = player.trimmingControls({ startTrim:startTrim, endTrim:endTrim }); + if (isEditor) { + var stream_start = player.vhs.playlists.master.playlists.filter(playlist => typeof playlist.discontinuityStarts !== "undefined")[0].dateTimeObject; + startTrim = startTrim ? (new Date(startTrim+"Z")-stream_start)/1000:0; + endTrim = endTrim ? (new Date(endTrim+"Z")-stream_start)/1000:player.duration(); + var trimmingControls = player.trimmingControls({ startTrim:startTrim, endTrim:endTrim }); + } }); // How about an event listener? diff --git a/thrimbletrimmer/stream.html b/thrimbletrimmer/stream.html new file mode 100644 index 0000000..acd790c --- /dev/null +++ b/thrimbletrimmer/stream.html @@ -0,0 +1,77 @@ + + + + + + VST Re-stream + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
StreamStart TimeEnd Time (blank for live)
+ +
+ UTC + Bustime +
+ +
+ +
+ +
+ Download Quality: + + Go To Dashboard | + Go To Editor | + Help + Ultrawide +
+ +
+ + + + + + + + + + From b4310b0024747beadca278aea0b0c65ed4f82852 Mon Sep 17 00:00:00 2001 From: Mike Lang Date: Sun, 27 Oct 2019 04:50:59 -0700 Subject: [PATCH 06/14] restreamer: Allow blank start/end for cut So it acts the same as generating a playlist. --- restreamer/restreamer/main.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/restreamer/restreamer/main.py b/restreamer/restreamer/main.py index c6859ed..78fdce9 100644 --- a/restreamer/restreamer/main.py +++ b/restreamer/restreamer/main.py @@ -239,8 +239,16 @@ def cut(channel, quality): A fast cut is much faster but minor artifacting may be present near the start and end. A fast cut is encoded as MPEG-TS, a full as mp4. """ - start = dateutil.parse_utc_only(request.args['start']) - end = dateutil.parse_utc_only(request.args['end']) + start = dateutil.parse_utc_only(request.args['start']) if 'start' in request.args else None + end = dateutil.parse_utc_only(request.args['end']) if 'end' in request.args else None + if start is None or end is None: + # If start or end are not given, use the earliest/latest time available + first, last = time_range_for_quality(channel, quality) + if start is None: + start = first + if end is None: + end = last + if end <= start: return "End must be after start", 400 From d4c897460129cc59e98635ebfde9cfc705c98860 Mon Sep 17 00:00:00 2001 From: Mike Lang Date: Sun, 27 Oct 2019 06:29:43 -0700 Subject: [PATCH 07/14] thrimbletrimmer: Some video controls tweaks Allow fullscreen Hide disabled picture-in-picture control Autoplay --- thrimbletrimmer/scripts/playerSetup.js | 4 ++-- thrimbletrimmer/styles/style.css | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/thrimbletrimmer/scripts/playerSetup.js b/thrimbletrimmer/scripts/playerSetup.js index d8c827e..41850d3 100644 --- a/thrimbletrimmer/scripts/playerSetup.js +++ b/thrimbletrimmer/scripts/playerSetup.js @@ -8,13 +8,13 @@ function setupPlayer(isEditor, source, startTrim, endTrim) { liveui: true, //fluid:true, controls:true, - autoplay:false, + autoplay:true, width:1280, height:420, playbackRates: [0.5, 1, 1.25, 1.5, 2], inactivityTimeout: 0, controlBar: { - fullscreenToggle: false, + fullscreenToggle: true, volumePanel: { inline: false } diff --git a/thrimbletrimmer/styles/style.css b/thrimbletrimmer/styles/style.css index d93a0ae..6720550 100644 --- a/thrimbletrimmer/styles/style.css +++ b/thrimbletrimmer/styles/style.css @@ -24,6 +24,10 @@ body.ultrawide .my-player-dimensions { width:100% !important; } .vjs-menu-button-popup .vjs-menu { bottom:-3px; } +.video-js .vjs-picture-in-picture-control { + display: none; +} + #EditorDetailsPane { margin-top:100px; From ff43e186f6d8bd9dabd66f9467d51e997bfe496b Mon Sep 17 00:00:00 2001 From: Mike Lang Date: Sun, 27 Oct 2019 05:30:04 -0700 Subject: [PATCH 08/14] thrimbletrimmer: Support "time ago" as a third time format This is especially useful for the re-streaming page, and is default there. --- thrimbletrimmer/index.html | 3 ++- thrimbletrimmer/scripts/IO.js | 32 ++++++++++++++++++++++++++++---- thrimbletrimmer/stream.html | 5 +++-- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/thrimbletrimmer/index.html b/thrimbletrimmer/index.html index 2700bc2..e7cde66 100644 --- a/thrimbletrimmer/index.html +++ b/thrimbletrimmer/index.html @@ -41,7 +41,7 @@ - + @@ -51,6 +51,7 @@ UTC Bustime + Time Ago Advanced Submit Options diff --git a/thrimbletrimmer/scripts/IO.js b/thrimbletrimmer/scripts/IO.js index d0e4aa9..8abad34 100644 --- a/thrimbletrimmer/scripts/IO.js +++ b/thrimbletrimmer/scripts/IO.js @@ -1,7 +1,8 @@ var desertBusStart = new Date("1970-01-01T00:00:00Z"); -var timeFormat = 'BUSTIME'; +var timeFormat = 'AGO'; pageSetup = function(isEditor) { + //Get values from ThrimShim if(isEditor && /id=/.test(document.location.search)) { var rowId = /id=(.*)(?:&|$)/.exec(document.location.search)[1]; @@ -16,6 +17,8 @@ pageSetup = function(isEditor) { document.getElementById("StreamName").value = data.video_channel; document.getElementById("hiddenSubmissionID").value = data.id; + // for editor, switch to bustime since that's the default + timeFormat = 'BUSTIME'; setTimeRange(fromTimestamp(data.event_start), fromTimestamp(data.event_end)); // title and description both default to row description document.getElementById("VideoTitle").value = data.video_title ? data.video_title : data.description; @@ -54,9 +57,12 @@ pageSetup = function(isEditor) { setOptions('uploadLocation', data.upload_locations); } - // Default time range from to the last 10min to live. This is useful for immediate replay, etc. - var start = new Date(new Date().getTime() - 1000*60*10); - setTimeRange(start, null); + // Default time format changes depending on mode. + // But in both cases the default input value is 10min ago / "", + // it's just for editor we convert it before the user sees. + if (isEditor) { + toggleTimeInput('BUSTIME'); + } loadPlaylist(isEditor); }); @@ -89,12 +95,29 @@ fromTimestamp = function(ts) { return new Date(ts + "Z"); } +toAgo = function(date) { + now = new Date() + return (date < now ? "":"-") + videojs.formatTime(Math.abs((date - now)/1000), 600.01).padStart(7, "0:"); +} + +fromAgo = function(ago) { + var direction = 1; + if(ago.startsWith("-")) { + bustime = ago.slice(1); + direction = -1; + } + var parts = ago.split(':') + var ago_ms = (parseInt(parts[0]) + parts[1]/60 + parts[2]/3600) * 1000 * 60 * 60; + return new Date(new Date().getTime() - direction * ago_ms); +} + // Set the stream start/end range from a pair of Dates using the current format // If given null, sets to blank. setTimeRange = function(start, end) { var toFunc = { UTC: toTimestamp, BUSTIME: toBustime, + AGO: toAgo, }[timeFormat]; document.getElementById("StreamStart").value = (start) ? toFunc(start) : ""; document.getElementById("StreamEnd").value = (end) ? toFunc(end) : ""; @@ -107,6 +130,7 @@ getTimeRange = function() { var fromFunc = { UTC: fromTimestamp, BUSTIME: fromBustime, + AGO: fromAgo, }[timeFormat]; convert = function(value) { if (!value) { return null; } diff --git a/thrimbletrimmer/stream.html b/thrimbletrimmer/stream.html index acd790c..06c196c 100644 --- a/thrimbletrimmer/stream.html +++ b/thrimbletrimmer/stream.html @@ -28,7 +28,7 @@ - + @@ -37,7 +37,8 @@ UTC - Bustime + Bustime + Time Ago From 5d5358019aa8f60f476629ebe512756cd7f3de20 Mon Sep 17 00:00:00 2001 From: Mike Lang Date: Sun, 27 Oct 2019 06:32:57 -0700 Subject: [PATCH 09/14] thrimbletrimmer: Improve bustime/ago parsing Allow partial entries like 5:00 instead of 0:05:00. --- thrimbletrimmer/scripts/IO.js | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/thrimbletrimmer/scripts/IO.js b/thrimbletrimmer/scripts/IO.js index 8abad34..1c33593 100644 --- a/thrimbletrimmer/scripts/IO.js +++ b/thrimbletrimmer/scripts/IO.js @@ -72,19 +72,23 @@ pageSetup = function(isEditor) { // Time-formatting functions +parseDuration = function(duration) { + var direction = 1; + if(duration.startsWith("-")) { + duration = duration.slice(1); + direction = -1; + } + var parts = duration.split(':'); + parts.reverse(); + return (parseInt(parts[2] || "0") + (parts[1] || "0")/60 + parts[0]/3600) * 60 * 60 * direction; +} + toBustime = function(date) { return (date < desertBusStart ? "-":"") + videojs.formatTime(Math.abs((date - desertBusStart)/1000), 600.01).padStart(7, "0:"); }; fromBustime = function(bustime) { - var direction = 1; - if(bustime.startsWith("-")) { - bustime = bustime.slice(1); - direction = -1; - } - var parts = bustime.split(':') - var bustime_ms = (parseInt(parts[0]) + parts[1]/60 + parts[2]/3600) * 1000 * 60 * 60; - return new Date(desertBusStart.getTime() + direction * bustime_ms); + return new Date(desertBusStart.getTime() + 1000 * parseDuration(bustime)); }; toTimestamp = function(date) { @@ -101,14 +105,7 @@ toAgo = function(date) { } fromAgo = function(ago) { - var direction = 1; - if(ago.startsWith("-")) { - bustime = ago.slice(1); - direction = -1; - } - var parts = ago.split(':') - var ago_ms = (parseInt(parts[0]) + parts[1]/60 + parts[2]/3600) * 1000 * 60 * 60; - return new Date(new Date().getTime() - direction * ago_ms); + return new Date(new Date().getTime() - 1000 * parseDuration(ago)); } // Set the stream start/end range from a pair of Dates using the current format @@ -132,7 +129,7 @@ getTimeRange = function() { BUSTIME: fromBustime, AGO: fromAgo, }[timeFormat]; - convert = function(value) { + var convert = function(value) { if (!value) { return null; } var date = fromFunc(value); return (isNaN(date)) ? null : date; From 7edc6ac1496e5ebd68106fe6b8af72095a77ad46 Mon Sep 17 00:00:00 2001 From: Mike Lang Date: Sun, 27 Oct 2019 06:46:39 -0700 Subject: [PATCH 10/14] thrimbletrimmer: Some tweaks to the streaming page --- thrimbletrimmer/stream.html | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/thrimbletrimmer/stream.html b/thrimbletrimmer/stream.html index 06c196c..c486f9a 100644 --- a/thrimbletrimmer/stream.html +++ b/thrimbletrimmer/stream.html @@ -49,11 +49,16 @@ -
+
+
+ When no end time is set, the stream will continue to play as it arrives.
+ Trying to watch live will result in buffering, as those segments haven't been captured yet.
+ If you watch for a long time, it may become difficult to navigate on the video bar because there's too long a time loaded. + To fix this, re-load the video in the desired time range (default: the last 10 minutes) by clicking Load Playlist.
Download Quality: Go To Dashboard | - Go To Editor | + Go To Editor Help Ultrawide
From a6ee746e6be81cdea701eeab19ae28c3513f496d Mon Sep 17 00:00:00 2001 From: Mike Lang Date: Sun, 27 Oct 2019 12:30:18 -0700 Subject: [PATCH 11/14] thrimbletrimmer: disable autoplay --- thrimbletrimmer/scripts/playerSetup.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/thrimbletrimmer/scripts/playerSetup.js b/thrimbletrimmer/scripts/playerSetup.js index 41850d3..c21416c 100644 --- a/thrimbletrimmer/scripts/playerSetup.js +++ b/thrimbletrimmer/scripts/playerSetup.js @@ -8,7 +8,7 @@ function setupPlayer(isEditor, source, startTrim, endTrim) { liveui: true, //fluid:true, controls:true, - autoplay:true, + autoplay:false, width:1280, height:420, playbackRates: [0.5, 1, 1.25, 1.5, 2], From 26f91a02eaafd16a87b23282e9627d732ac30bd4 Mon Sep 17 00:00:00 2001 From: Mike Lang Date: Thu, 31 Oct 2019 18:14:02 -0700 Subject: [PATCH 12/14] thrimbletrimmer: Parse durations as HH[:MM[:SS]] instead of [[HH:]MM:]SS ie. 1:00 is 1 hour, not 1 minute. This is consistent with our use of bustime everywhere else. --- thrimbletrimmer/scripts/IO.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/thrimbletrimmer/scripts/IO.js b/thrimbletrimmer/scripts/IO.js index 1c33593..561051a 100644 --- a/thrimbletrimmer/scripts/IO.js +++ b/thrimbletrimmer/scripts/IO.js @@ -79,8 +79,7 @@ parseDuration = function(duration) { direction = -1; } var parts = duration.split(':'); - parts.reverse(); - return (parseInt(parts[2] || "0") + (parts[1] || "0")/60 + parts[0]/3600) * 60 * 60 * direction; + return (parseInt(parts[0]) + (parts[1] || "0")/60 + (parts[2] || "0")/3600) * 60 * 60 * direction; } toBustime = function(date) { From a68684c24cca27f62b20a3a77891908b2f260906 Mon Sep 17 00:00:00 2001 From: Mike Lang Date: Thu, 31 Oct 2019 18:16:30 -0700 Subject: [PATCH 13/14] thrimbletrimmer: Fix use of tabs again --- thrimbletrimmer/index.html | 4 +- thrimbletrimmer/scripts/IO.js | 182 ++++++++++++------------- thrimbletrimmer/scripts/playerSetup.js | 12 +- thrimbletrimmer/stream.html | 16 +-- thrimbletrimmer/styles/style.css | 2 +- 5 files changed, 108 insertions(+), 108 deletions(-) diff --git a/thrimbletrimmer/index.html b/thrimbletrimmer/index.html index e7cde66..159db15 100644 --- a/thrimbletrimmer/index.html +++ b/thrimbletrimmer/index.html @@ -51,7 +51,7 @@ UTC Bustime - Time Ago + Time Ago Advanced Submit Options @@ -96,7 +96,7 @@ Go To Dashboard | - Go to Re-stream View | + Go to Re-stream View | Manual Link | Reset Edits Help diff --git a/thrimbletrimmer/scripts/IO.js b/thrimbletrimmer/scripts/IO.js index 561051a..188b668 100644 --- a/thrimbletrimmer/scripts/IO.js +++ b/thrimbletrimmer/scripts/IO.js @@ -17,8 +17,8 @@ pageSetup = function(isEditor) { document.getElementById("StreamName").value = data.video_channel; document.getElementById("hiddenSubmissionID").value = data.id; - // for editor, switch to bustime since that's the default - timeFormat = 'BUSTIME'; + // for editor, switch to bustime since that's the default + timeFormat = 'BUSTIME'; setTimeRange(fromTimestamp(data.event_start), fromTimestamp(data.event_end)); // title and description both default to row description document.getElementById("VideoTitle").value = data.video_title ? data.video_title : data.description; @@ -51,20 +51,20 @@ pageSetup = function(isEditor) { fetch("/thrimshim/defaults").then(data => data.json()).then(function (data) { desertBusStart = new Date(data.bustime_start); document.getElementById("StreamName").value = data.video_channel; - 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 format changes depending on mode. - // But in both cases the default input value is 10min ago / "", - // it's just for editor we convert it before the user sees. - if (isEditor) { - toggleTimeInput('BUSTIME'); - } - - loadPlaylist(isEditor); + 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 format changes depending on mode. + // But in both cases the default input value is 10min ago / "", + // it's just for editor we convert it before the user sees. + if (isEditor) { + toggleTimeInput('BUSTIME'); + } + + loadPlaylist(isEditor); }); } @@ -91,15 +91,15 @@ fromBustime = function(bustime) { }; toTimestamp = function(date) { - return date.toISOString().substring(0, 19); + return date.toISOString().substring(0, 19); } fromTimestamp = function(ts) { - return new Date(ts + "Z"); + return new Date(ts + "Z"); } toAgo = function(date) { - now = new Date() + now = new Date() return (date < now ? "":"-") + videojs.formatTime(Math.abs((date - now)/1000), 600.01).padStart(7, "0:"); } @@ -110,11 +110,11 @@ fromAgo = function(ago) { // Set the stream start/end range from a pair of Dates using the current format // If given null, sets to blank. setTimeRange = function(start, end) { - var toFunc = { - UTC: toTimestamp, - BUSTIME: toBustime, - AGO: toAgo, - }[timeFormat]; + var toFunc = { + UTC: toTimestamp, + BUSTIME: toBustime, + AGO: toAgo, + }[timeFormat]; document.getElementById("StreamStart").value = (start) ? toFunc(start) : ""; document.getElementById("StreamEnd").value = (end) ? toFunc(end) : ""; } @@ -123,46 +123,46 @@ setTimeRange = function(start, end) { // Returns an object containing 'start' and 'end' fields. // If either is empty / invalid, returns null. getTimeRange = function() { - var fromFunc = { - UTC: fromTimestamp, - BUSTIME: fromBustime, - AGO: fromAgo, - }[timeFormat]; - var convert = function(value) { - if (!value) { return null; } - var date = fromFunc(value); - return (isNaN(date)) ? null : date; - }; - return { - start: convert(document.getElementById("StreamStart").value), - end: convert(document.getElementById("StreamEnd").value), - }; + var fromFunc = { + UTC: fromTimestamp, + BUSTIME: fromBustime, + AGO: fromAgo, + }[timeFormat]; + var convert = function(value) { + if (!value) { return null; } + var date = fromFunc(value); + return (isNaN(date)) ? null : date; + }; + return { + start: convert(document.getElementById("StreamStart").value), + end: convert(document.getElementById("StreamEnd").value), + }; } getTimeRangeAsTimestamp = function() { - var range = getTimeRange(); - return { - // if not null, format as timestamp - start: range.start && toTimestamp(range.start), - end: range.end && toTimestamp(range.end), - }; + 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) { - var pane = document.getElementById(paneID); - pane.style.display = (pane.style.display === "none") ? "block":"none"; + var pane = document.getElementById(paneID); + pane.style.display = (pane.style.display === "none") ? "block":"none"; } toggleUltrawide = function() { - var body = document.getElementsByTagName("Body")[0]; - body.classList.contains("ultrawide") ? body.classList.remove("ultrawide"):body.classList.add("ultrawide"); + var body = document.getElementsByTagName("Body")[0]; + body.classList.contains("ultrawide") ? body.classList.remove("ultrawide"):body.classList.add("ultrawide"); } toggleTimeInput = function(toggleInput) { - // Get times using current format, then change format, then write them back - var range = getTimeRange(); - timeFormat = toggleInput; - setTimeRange(range.start, range.end); + // Get times using current format, then change format, then write them back + var range = getTimeRange(); + timeFormat = toggleInput; + setTimeRange(range.start, range.end); } // For a given select input element id, add the given list of options. @@ -178,32 +178,32 @@ setOptions = function(element, options, selected) { } buildQuery = function(params) { - return Object.keys(params).filter(key => params[key] !== null).map(key => - encodeURIComponent(key) + '=' + encodeURIComponent(params[key]) - ).join('&'); + return Object.keys(params).filter(key => params[key] !== null).map(key => + encodeURIComponent(key) + '=' + encodeURIComponent(params[key]) + ).join('&'); } loadPlaylist = function(isEditor, startTrim, endTrim, defaultQuality) { var playlist = "/playlist/" + document.getElementById("StreamName").value + ".m3u8"; - var range = getTimeRangeAsTimestamp(); - var queryString = buildQuery(range); + var range = getTimeRangeAsTimestamp(); + var queryString = buildQuery(range); setupPlayer(isEditor, playlist + '?' + queryString, startTrim, endTrim); - //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"; - } - }); + //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"; + } + }); }; thrimbletrimmerSubmit = function(state) { @@ -253,27 +253,27 @@ thrimbletrimmerSubmit = function(state) { }; thrimbletrimmerDownload = function(isEditor) { - var range = getTimeRangeAsTimestamp(); - if (isEditor) { - if(player.trimmingControls().options.startTrim >= player.trimmingControls().options.endTrim) { - alert("End Time must be greater than Start Time"); - return; - } - var discontinuities = mapDiscontinuities(); - range.start = getRealTimeForPlayerTime(discontinuities, player.trimmingControls().options.startTrim); - range.end = getRealTimeForPlayerTime(discontinuities, player.trimmingControls().options.endTrim); - } - - var targetURL = "/cut/" + document.getElementById("StreamName").value + - "/"+document.getElementById('qualityLevel').options[document.getElementById('qualityLevel').options.selectedIndex].value+".ts" + - "?" + buildQuery({ - start: range.start, - end: range.end, - // 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; + var range = getTimeRangeAsTimestamp(); + if (isEditor) { + if(player.trimmingControls().options.startTrim >= player.trimmingControls().options.endTrim) { + alert("End Time must be greater than Start Time"); + return; + } + var discontinuities = mapDiscontinuities(); + range.start = getRealTimeForPlayerTime(discontinuities, player.trimmingControls().options.startTrim); + range.end = getRealTimeForPlayerTime(discontinuities, player.trimmingControls().options.endTrim); + } + + var targetURL = "/cut/" + document.getElementById("StreamName").value + + "/"+document.getElementById('qualityLevel').options[document.getElementById('qualityLevel').options.selectedIndex].value+".ts" + + "?" + buildQuery({ + start: range.start, + end: range.end, + // 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() { diff --git a/thrimbletrimmer/scripts/playerSetup.js b/thrimbletrimmer/scripts/playerSetup.js index c21416c..35776f2 100644 --- a/thrimbletrimmer/scripts/playerSetup.js +++ b/thrimbletrimmer/scripts/playerSetup.js @@ -39,12 +39,12 @@ function setupPlayer(isEditor, source, startTrim, endTrim) { this.vhs.playlists.on('loadedmetadata', function() { // setTimeout(function() { player.play(); }, 1000); player.hasStarted(true); //So it displays all the controls. - if (isEditor) { - var stream_start = player.vhs.playlists.master.playlists.filter(playlist => typeof playlist.discontinuityStarts !== "undefined")[0].dateTimeObject; - startTrim = startTrim ? (new Date(startTrim+"Z")-stream_start)/1000:0; - endTrim = endTrim ? (new Date(endTrim+"Z")-stream_start)/1000:player.duration(); - var trimmingControls = player.trimmingControls({ startTrim:startTrim, endTrim:endTrim }); - } + if (isEditor) { + var stream_start = player.vhs.playlists.master.playlists.filter(playlist => typeof playlist.discontinuityStarts !== "undefined")[0].dateTimeObject; + startTrim = startTrim ? (new Date(startTrim+"Z")-stream_start)/1000:0; + endTrim = endTrim ? (new Date(endTrim+"Z")-stream_start)/1000:player.duration(); + var trimmingControls = player.trimmingControls({ startTrim:startTrim, endTrim:endTrim }); + } }); // How about an event listener? diff --git a/thrimbletrimmer/stream.html b/thrimbletrimmer/stream.html index c486f9a..152490a 100644 --- a/thrimbletrimmer/stream.html +++ b/thrimbletrimmer/stream.html @@ -38,7 +38,7 @@ UTC Bustime - Time Ago + Time Ago @@ -50,13 +50,13 @@
-
- When no end time is set, the stream will continue to play as it arrives.
- Trying to watch live will result in buffering, as those segments haven't been captured yet.
- If you watch for a long time, it may become difficult to navigate on the video bar because there's too long a time loaded. - To fix this, re-load the video in the desired time range (default: the last 10 minutes) by clicking Load Playlist.
- Download Quality: - +
+ When no end time is set, the stream will continue to play as it arrives.
+ Trying to watch live will result in buffering, as those segments haven't been captured yet.
+ If you watch for a long time, it may become difficult to navigate on the video bar because there's too long a time loaded. + To fix this, re-load the video in the desired time range (default: the last 10 minutes) by clicking Load Playlist.
+ Download Quality: + Go To Dashboard | Go To Editor Help diff --git a/thrimbletrimmer/styles/style.css b/thrimbletrimmer/styles/style.css index 6720550..520748c 100644 --- a/thrimbletrimmer/styles/style.css +++ b/thrimbletrimmer/styles/style.css @@ -25,7 +25,7 @@ body.ultrawide .my-player-dimensions { width:100% !important; } bottom:-3px; } .video-js .vjs-picture-in-picture-control { - display: none; + display: none; } From bdbfd37c51d16a20b417b2da96628cc8057ad073 Mon Sep 17 00:00:00 2001 From: Mike Lang Date: Thu, 31 Oct 2019 18:21:35 -0700 Subject: [PATCH 14/14] thrimbletrimmer: Pad start and end times --- thrimbletrimmer/scripts/IO.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/thrimbletrimmer/scripts/IO.js b/thrimbletrimmer/scripts/IO.js index 188b668..6427c72 100644 --- a/thrimbletrimmer/scripts/IO.js +++ b/thrimbletrimmer/scripts/IO.js @@ -19,7 +19,12 @@ pageSetup = function(isEditor) { document.getElementById("hiddenSubmissionID").value = data.id; // for editor, switch to bustime since that's the default timeFormat = 'BUSTIME'; - setTimeRange(fromTimestamp(data.event_start), fromTimestamp(data.event_end)); + // Apply padding - start 1min early, finish 2min late because these times are generally + // rounded down to the minute, so if something ends at "00:10" it might actually end + // at 00:10:59 so we should pad to 00:12:00. + var start = (data.event_start) ? new Date(fromTimestamp(data.event_start).getTime() - 60*1000) : null; + var end = (data.event_end) ? new Date(fromTimestamp(data.event_end).getTime() + 2*60*1000) : null; + setTimeRange(start, end); // title and description both default to row description document.getElementById("VideoTitle").value = data.video_title ? data.video_title : data.description; document.getElementById("VideoDescription").value = data.video_description ? data.video_description : data.description;