@ -1,8 +1,10 @@
var desertBusStart = new Date ( "1970-01-01T00:00:00Z" ) ;
var desertBusStart = new Date ( "1970-01-01T00:00:00Z" ) ;
var timeFormat = 'AGO' ;
pageSetup = function ( isEditor ) {
pageSetup = function ( ) {
//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 ) {
@ -15,10 +17,14 @@ pageSetup = function() {
document . getElementById ( "StreamName" ) . value = data . video _channel ;
document . getElementById ( "StreamName" ) . value = data . video _channel ;
document . getElementById ( "hiddenSubmissionID" ) . value = data . id ;
document . getElementById ( "hiddenSubmissionID" ) . value = data . id ;
// set stream start/end, then copy to bustime inputs
// for editor, switch to bustime since that's the default
document . getElementById ( "StreamStart" ) . value = data . event _start ;
timeFormat = 'BUSTIME' ;
document . getElementById ( "StreamEnd" ) . value = data . event _end ;
// Apply padding - start 1min early, finish 2min late because these times are generally
setBustimeRange ( ) ;
// 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
// title and description both default to row description
document . getElementById ( "VideoTitle" ) . value = data . video _title ? data . video _title : data . 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 ;
document . getElementById ( "VideoDescription" ) . value = data . video _description ? data . video _description : data . description ;
@ -41,53 +47,127 @@ 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 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' ) ;
}
// Default time range to the last 10min. This is useful for giffers, immediate replay, etc.
loadPlaylist ( isEditor ) ;
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 ( ) ;
}
}
} ;
} ;
timestampToBustime = function ( ts ) {
// Time-formatting functions
date = new Date ( ts + "Z" ) ;
return ( date < desertBusStart ? "-" : "" ) + videojs . formatTime ( Math . abs ( ( date - desertBusStart ) / 1000 ) , 600.01 ) . padStart ( 7 , "0:" ) ;
} ;
bustimeToTimestamp = function ( bustime ) {
parseDuration = function ( duration ) {
direction = 1 ;
var direction = 1 ;
if ( bustime . startsWith ( "-" ) ) {
if ( duration . startsWith ( "-" ) ) {
bustime = bustime . slice ( 1 ) ;
duration = duration . slice ( 1 ) ;
direction = - 1 ;
direction = - 1 ;
}
}
parts = bustime . split ( ':' )
var parts = duration . split ( ':' ) ;
bustime _ms = ( parseInt ( parts [ 0 ] ) + parts [ 1 ] / 60 + parts [ 2 ] / 3600 ) * 1000 * 60 * 60 ;
return ( parseInt ( parts [ 0 ] ) + ( parts [ 1 ] || "0" ) / 60 + ( parts [ 2 ] || "0" ) / 3600 ) * 60 * 60 * direction ;
return new Date ( desertBusStart . getTime ( ) + direction * bustime _ms ) . toISOString ( ) . substring ( 0 , 19 ) ;
}
toBustime = function ( date ) {
return ( date < desertBusStart ? "-" : "" ) + videojs . formatTime ( Math . abs ( ( date - desertBusStart ) / 1000 ) , 600.01 ) . padStart ( 7 , "0:" ) ;
} ;
} ;
setBustimeRange = function ( ) {
fromBustime = function ( bustime ) {
document . getElementById ( "BusTimeStart" ) . value = timestampToBustime ( document . getElementById ( "StreamStart" ) . value ) ;
return new Date ( desertBusStart . getTime ( ) + 1000 * parseDuration ( bustime ) ) ;
document . getElementById ( "BusTimeEnd" ) . value = timestampToBustime ( document . getElementById ( "StreamEnd" ) . value ) ;
} ;
} ;
setStreamRange = function ( ) {
toTimestamp = function ( date ) {
document . getElementById ( "StreamStart" ) . value = bustimeToTimestamp ( document . getElementById ( "BusTimeStart" ) . value ) ;
return date . toISOString ( ) . substring ( 0 , 19 ) ;
document . getElementById ( "StreamEnd" ) . value = bustimeToTimestamp ( document . getElementById ( "BusTimeEnd" ) . value ) ;
}
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 ) {
return new Date ( new Date ( ) . getTime ( ) - 1000 * parseDuration ( 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 ] ;
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 ( ) {
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 ) ,
} ;
}
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 ) {
// 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.
// For a given select input element id, add the given list of options.
@ -102,21 +182,21 @@ setOptions = function(element, options, selected) {
} ) ;
} ) ;
}
}
loadPlaylist = function ( startTrim , endTrim , defaultQuality ) {
buildQuery = function ( params ) {
var playlist = "/playlist/" + document . getElementById ( "StreamName" ) . value + ".m3u8" ;
return Object . keys ( params ) . filter ( key => params [ key ] !== null ) . map ( key =>
encodeURIComponent ( key ) + '=' + encodeURIComponent ( params [ key ] )
) . join ( '&' ) ;
}
// If we're using bustime, update stream start/end from it first
loadPlaylist = function ( isEditor , startTrim , endTrim , defaultQuality ) {
if ( document . getElementById ( "BusTimeToggleBus" ) . checked ) {
var playlist = "/playlist/" + document . getElementById ( "StreamName" ) . value + ".m3u8" ;
setStreamRange ( ) ;
}
var streamStart = document . getElementById ( "StreamStart" ) . value ? "start=" + document . getElementById ( "StreamStart" ) . value : null ;
var range = getTimeRangeAsTimestamp ( ) ;
var streamEnd = document . getElementById ( "StreamEnd" ) . value ? "end=" + document . getElementById ( "StreamEnd" ) . value : null ;
var queryString = buildQuery ( range ) ;
var queryString = ( streamStart || streamEnd ) ? "?" + [ streamStart , streamEnd ] . filter ( ( a ) => ! ! a ) . join ( "&" ) : "" ;
setupPlayer ( playlist + queryString , startTrim , endTrim ) ;
setupPlayer ( isEditor, playlist + '?' + queryString , startTrim , endTrim ) ;
//Get quality levels for advanced properties .
//Get quality levels for advanced properties / download
document . getElementById ( 'qualityLevel' ) . innerHTML = "" ;
document . getElementById ( 'qualityLevel' ) . innerHTML = "" ;
fetch ( '/files/' + document . getElementById ( 'StreamName' ) . value ) . then ( data => data . json ( ) ) . then ( function ( data ) {
fetch ( '/files/' + document . getElementById ( 'StreamName' ) . value ) . then ( data => data . json ( ) ) . then ( function ( data ) {
if ( ! data . length ) {
if ( ! data . length ) {
@ -165,7 +245,7 @@ thrimbletrimmerSubmit = function(state) {
} )
} )
. then ( response => response . text ( ) . then ( text => {
. then ( response => response . text ( ) . then ( text => {
if ( ! response . ok ) {
if ( ! response . ok ) {
error = response . statusText + ": " + text ;
var error = response . statusText + ": " + text ;
console . log ( error ) ;
console . log ( error ) ;
alert ( error ) ;
alert ( error ) ;
} else if ( state == 'EDITED' ) {
} else if ( state == 'EDITED' ) {
@ -177,29 +257,34 @@ 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 ) {
alert ( "End Time must be greater than Start Time" ) ;
return ;
}
var discontinuities = mapDiscontinuities ( ) ;
var discontinuities = mapDiscontinuities ( ) ;
range . start = getRealTimeForPlayerTime ( discontinuities , player . trimmingControls ( ) . options . startTrim ) ;
var downloadStart = getRealTimeForPlayerTime ( discontinuities , player . trimmingControls ( ) . options . startTrim ) ;
range . end = getRealTimeForPlayerTime ( discontinuities , player . trimmingControls ( ) . options . endTrim ) ;
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" +
"?start=" + downloadStart +
"&end=" + downloadEnd +
"&allow_holes=" + String ( document . getElementById ( 'AllowHoles' ) . checked ) ;
console . log ( targetURL ) ;
document . getElementById ( 'outputFile' ) . src = targetURL ;
}
}
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 ( ) {
thrimbletrimmerManualLink = function ( ) {
document . getElementById ( "ManualButton" ) . disabled = true ;
document . getElementById ( "ManualButton" ) . disabled = true ;
var rowId = /id=(.*)(?:&|$)/ . exec ( document . location . search ) [ 1 ] ;
var rowId = /id=(.*)(?:&|$)/ . exec ( document . location . search ) [ 1 ] ;
body = { link : document . getElementById ( "ManualLink" ) . value } ;
var body = { link : document . getElementById ( "ManualLink" ) . value } ;
if ( ! ! user ) {
if ( ! ! user ) {
body . token = user . getAuthResponse ( ) . id _token ;
body . token = user . getAuthResponse ( ) . id _token ;
}
}
@ -213,7 +298,7 @@ thrimbletrimmerManualLink = function() {
} )
} )
. then ( response => response . text ( ) . then ( text => {
. then ( response => response . text ( ) . then ( text => {
if ( ! response . ok ) {
if ( ! response . ok ) {
error = response . statusText + ": " + text ;
var error = response . statusText + ": " + text ;
console . log ( error ) ;
console . log ( error ) ;
alert ( error ) ;
alert ( error ) ;
document . getElementById ( "ManualButton" ) . disabled = false ;
document . getElementById ( "ManualButton" ) . disabled = false ;
@ -236,7 +321,7 @@ thrimbletrimmerResetLink = function() {
return ;
return ;
}
}
document . getElementById ( "ResetButton" ) . disabled = true ;
document . getElementById ( "ResetButton" ) . disabled = true ;
body = { }
var body = { }
if ( ! ! user ) {
if ( ! ! user ) {
body . token = user . getAuthResponse ( ) . id _token ;
body . token = user . getAuthResponse ( ) . id _token ;
}
}
@ -250,7 +335,7 @@ thrimbletrimmerResetLink = function() {
} )
} )
. then ( response => response . text ( ) . then ( text => {
. then ( response => response . text ( ) . then ( text => {
if ( ! response . ok ) {
if ( ! response . ok ) {
error = response . statusText + ": " + text ;
var error = response . statusText + ": " + text ;
console . log ( error ) ;
console . log ( error ) ;
alert ( error ) ;
alert ( error ) ;
document . getElementById ( "ResetButton" ) . disabled = false ;
document . getElementById ( "ResetButton" ) . disabled = false ;