Switch date/time handling from JS Date objects to a datetime library to fix padding bug with DST changeover

pull/239/head
ElementalAlchemist 3 years ago committed by Mike Lang
parent da2ed19b9d
commit d37175f914

@ -1,2 +1,4 @@
videojs/ styles/video-js.min.css
scripts/video.min.js
scripts/luxon.min.js
dashboard.html dashboard.html

@ -8,6 +8,7 @@
<link rel="stylesheet" href="styles/video-js.min.css" /> <link rel="stylesheet" href="styles/video-js.min.css" />
<script src="scripts/video.min.js"></script> <script src="scripts/video.min.js"></script>
<script src="scripts/luxon.min.js"></script>
<script src="scripts/common.js"></script> <script src="scripts/common.js"></script>
<script src="scripts/edit.js"></script> <script src="scripts/edit.js"></script>
<script src="scripts/keyboard-shortcuts.js"></script> <script src="scripts/keyboard-shortcuts.js"></script>

@ -8,6 +8,7 @@
<link rel="stylesheet" href="styles/video-js.min.css" /> <link rel="stylesheet" href="styles/video-js.min.css" />
<script src="scripts/video.min.js"></script> <script src="scripts/video.min.js"></script>
<script src="scripts/luxon.min.js"></script>
<script src="scripts/common.js"></script> <script src="scripts/common.js"></script>
<script src="scripts/stream.js"></script> <script src="scripts/stream.js"></script>
<script src="scripts/keyboard-shortcuts.js"></script> <script src="scripts/keyboard-shortcuts.js"></script>

@ -1,4 +1,7 @@
var globalBusStartTime = new Date("1970-01-01T00:00:00Z"); var DateTime = luxon.DateTime;
var Interval = luxon.Interval;
var globalBusStartTime = DateTime.fromISO("1970-01-01T00:00:00", { zone: "utc" });
var globalStreamName = ""; var globalStreamName = "";
var globalStartTimeString = ""; var globalStartTimeString = "";
var globalEndTimeString = ""; var globalEndTimeString = "";
@ -87,35 +90,54 @@ function updateVideoPlayer(newPlaylistURL) {
player.src({ src: rangedPlaylistURL }); player.src({ src: rangedPlaylistURL });
} }
function dateObjFromBusTime(busTime) { function parseHumanTimeStringAsDateTimeMathObject(inputTime) {
// We need to handle inputs like "-0:10:15" in a way that consistently makes the time negative. // We need to handle inputs like "-0:10:15" in a way that consistently makes the time negative.
// Since we can't assign the negative sign to any particular part, we'll check for the whole thing here. // Since we can't assign the negative sign to any particular part, we'll check for the whole thing here.
let direction = 1; let direction = 1;
if (busTime.startsWith("-")) { if (inputTime.startsWith("-")) {
busTime = busTime.slice(1); inputTime = inputTime.slice(1);
direction = -1; direction = -1;
} }
const parts = busTime.split(":", 3); const parts = inputTime.split(":", 3);
const hours = (parts[0] || 0) * direction; const hours = parseInt(parts[0]) * direction;
const minutes = (parts[1] || 0) * direction; const minutes = (parts[1] || 0) * direction;
const seconds = (parts[2] || 0) * direction; const seconds = (parts[2] || 0) * direction;
const time = new Date(globalBusStartTime); return { hours: hours, minutes: minutes, seconds: seconds };
time.setHours(time.getHours() + hours); }
time.setMinutes(time.getMinutes() + minutes);
time.setSeconds(time.getSeconds() + seconds); function dateTimeFromBusTime(busTime) {
return time; return globalBusStartTime.plus(parseHumanTimeStringAsDateTimeMathObject(busTime));
}
function busTimeFromDateTime(dateTime) {
const diff = dateTime.diff(globalBusStartTime);
return formatIntervalForDisplay(diff);
} }
function dateObjFromWubloaderTime(wubloaderTime) { function formatIntervalForDisplay(interval) {
return new Date(`${wubloaderTime}Z`); if (interval.milliseconds < 0) {
const negativeInterval = interval.negate();
return `-${negativeInterval.toFormat("hh:mm:ss.SSS")}`;
}
return interval.toFormat("hh:mm:ss.SSS");
}
function dateTimeFromWubloaderTime(wubloaderTime) {
return DateTime.fromISO(wubloaderTime, { zone: "utc" });
} }
function wubloaderTimeFromDateObj(date) { function wubloaderTimeFromDateTime(dateTime) {
if (!date) { if (!dateTime) {
return null; return null;
} }
return date.toISOString().substring(0, 23); // Trim "Z" marker and smaller than milliseconds // Not using ISO here because Luxon doesn't give us a quick way to print an ISO8601 string with no offset.
return dateTime.toFormat("yyyy-LL-dd'T'HH:mm:ss.SSS");
}
function busTimeFromWubloaderTime(wubloaderTime) {
const dt = dateTimeFromWubloaderTime(wubloaderTime);
return busTimeFromDateTime(dt);
} }
function assembleVideoPlaylistURL(basePlaylistURL) { function assembleVideoPlaylistURL(basePlaylistURL) {
@ -134,10 +156,10 @@ function startAndEndTimeQueryStringParts() {
let queryStringParts = []; let queryStringParts = [];
if (startTime) { if (startTime) {
queryStringParts.push(`start=${wubloaderTimeFromDateObj(startTime)}`); queryStringParts.push(`start=${wubloaderTimeFromDateTime(startTime)}`);
} }
if (endTime) { if (endTime) {
queryStringParts.push(`end=${wubloaderTimeFromDateObj(endTime)}`); queryStringParts.push(`end=${wubloaderTimeFromDateTime(endTime)}`);
} }
return queryStringParts; return queryStringParts;
} }

@ -17,7 +17,7 @@ window.addEventListener("DOMContentLoaded", async (event) => {
} }
const newStartField = document.getElementById("stream-time-setting-start"); const newStartField = document.getElementById("stream-time-setting-start");
const newStart = dateObjFromBusTime(newStartField.value); const newStart = dateTimeFromBusTime(newStartField.value);
if (!newStart) { if (!newStart) {
addError("Failed to parse start time"); addError("Failed to parse start time");
return; return;
@ -26,7 +26,7 @@ window.addEventListener("DOMContentLoaded", async (event) => {
const newEndField = document.getElementById("stream-time-setting-end"); const newEndField = document.getElementById("stream-time-setting-end");
let newEnd = null; let newEnd = null;
if (newEndField.value !== "") { if (newEndField.value !== "") {
newEnd = dateObjFromBusTime(newEndField.value); newEnd = dateTimeFromBusTime(newEndField.value);
if (!newEnd) { if (!newEnd) {
addError("Failed to parse end time"); addError("Failed to parse end time");
return; return;
@ -34,8 +34,14 @@ window.addEventListener("DOMContentLoaded", async (event) => {
} }
const oldStart = getStartTime(); const oldStart = getStartTime();
const startAdjustment = newStart - oldStart; const startAdjustment = newStart.diff(oldStart, "seconds").seconds;
const newDuration = newEnd === null ? Infinity : newEnd - newStart; let newDuration = newEnd === null ? Infinity : newEnd.diff(newStart, "seconds").seconds;
// The video duration isn't precisely the video times, but can be padded by up to the
// segment length on either side.
// This makes the assumption that all segments have the same length.
const segmentLength = getPlaylistData().segments[0].duration;
newDuration += segmentLength * 2;
// Abort for ranges that exceed new times // Abort for ranges that exceed new times
for (const rangeContainer of document.getElementById("range-definitions").children) { for (const rangeContainer of document.getElementById("range-definitions").children) {
@ -54,8 +60,8 @@ window.addEventListener("DOMContentLoaded", async (event) => {
} }
} }
globalStartTimeString = wubloaderTimeFromDateObj(newStart); globalStartTimeString = wubloaderTimeFromDateTime(newStart);
globalEndTimeString = wubloaderTimeFromDateObj(newEnd); globalEndTimeString = wubloaderTimeFromDateTime(newEnd);
updateSegmentPlaylist(); updateSegmentPlaylist();
@ -98,25 +104,17 @@ window.addEventListener("DOMContentLoaded", async (event) => {
document.getElementById("stream-time-setting-start-pad").addEventListener("click", (_event) => { document.getElementById("stream-time-setting-start-pad").addEventListener("click", (_event) => {
const startTimeField = document.getElementById("stream-time-setting-start"); const startTimeField = document.getElementById("stream-time-setting-start");
let startTime = startTimeField.value; let startTime = startTimeField.value;
startTime = dateObjFromBusTime(startTime); startTime = dateTimeFromBusTime(startTime);
if (isNaN(startTime)) { startTime = startTime.minus({ minutes: 1 });
addError("Couldn't parse entered start time for padding"); startTimeField.value = busTimeFromDateTime(startTime);
return;
}
startTime.setMinutes(startTime.getMinutes() - 1);
startTimeField.value = busTimeFromDateObj(startTime);
}); });
document.getElementById("stream-time-setting-end-pad").addEventListener("click", (_event) => { document.getElementById("stream-time-setting-end-pad").addEventListener("click", (_event) => {
const endTimeField = document.getElementById("stream-time-setting-end"); const endTimeField = document.getElementById("stream-time-setting-end");
let endTime = endTimeField.value; let endTime = endTimeField.value;
endTime = dateObjFromBusTime(endTime); endTime = dateTimeFromBusTime(endTime);
if (isNaN(endTime)) { endTime = endTime.plus({ minutes: 1 });
addError("Couldn't parse entered end time for padding"); endTimeField.value = busTimeFromDateTime(endTime);
return;
}
endTime.setMinutes(endTime.getMinutes() + 1);
endTimeField.value = busTimeFromDateObj(endTime);
}); });
const addRangeIcon = document.getElementById("add-range-definition"); const addRangeIcon = document.getElementById("add-range-definition");
@ -225,23 +223,23 @@ async function loadVideoInfo() {
async function initializeVideoInfo() { async function initializeVideoInfo() {
globalStreamName = videoInfo.video_channel; globalStreamName = videoInfo.video_channel;
globalBusStartTime = new Date(videoInfo.bustime_start); globalBusStartTime = DateTime.fromISO(videoInfo.bustime_start, { zone: "utc" });
const eventStartTime = dateObjFromWubloaderTime(videoInfo.event_start); let eventStartTime = dateTimeFromWubloaderTime(videoInfo.event_start);
const eventEndTime = videoInfo.event_end ? dateObjFromWubloaderTime(videoInfo.event_end) : null; let eventEndTime = videoInfo.event_end ? dateTimeFromWubloaderTime(videoInfo.event_end) : null;
// To account for various things (stream delay, just slightly off logging, etc.), we pad the start time by one minute // To account for various things (stream delay, just slightly off logging, etc.), we pad the start time by one minute
eventStartTime.setMinutes(eventStartTime.getMinutes() - 1); eventStartTime = eventStartTime.minus({ minutes: 1 });
// To account for various things (stream delay, just slightly off logging, etc.), we pad the end time by one minute. // To account for various things (stream delay, just slightly off logging, etc.), we pad the end time by one minute.
// To account for the fact that we don't record seconds, but the event could've ended any time in the recorded minute, we pad by an additional minute. // To account for the fact that we don't record seconds, but the event could've ended any time in the recorded minute, we pad by an additional minute.
if (eventEndTime) { if (eventEndTime) {
eventEndTime.setMinutes(eventEndTime.getMinutes() + 2); eventEndTime = eventEndTime.plus({ minutes: 2 });
} }
globalStartTimeString = wubloaderTimeFromDateObj(eventStartTime); globalStartTimeString = wubloaderTimeFromDateTime(eventStartTime);
if (eventEndTime) { if (eventEndTime) {
globalEndTimeString = wubloaderTimeFromDateObj(eventEndTime); globalEndTimeString = wubloaderTimeFromDateTime(eventEndTime);
} else { } else {
document.getElementById("waveform").classList.add("hidden"); document.getElementById("waveform").classList.add("hidden");
} }
@ -255,42 +253,42 @@ async function initializeVideoInfo() {
let endTime = range[1]; let endTime = range[1];
if (startTime) { if (startTime) {
startTime = dateObjFromWubloaderTime(startTime); startTime = dateTimeFromWubloaderTime(startTime);
} else { } else {
startTime = null; startTime = null;
} }
if (endTime) { if (endTime) {
endTime = dateObjFromWubloaderTime(endTime); endTime = dateTimeFromWubloaderTime(endTime);
} else { } else {
endTime = null; endTime = null;
} }
if (!earliestStartTime || (startTime && startTime < earliestStartTime)) { if (!earliestStartTime || (startTime && startTime.diff(earliestStartTime).milliseconds < 0)) {
earliestStartTime = startTime; earliestStartTime = startTime;
} }
if (!latestEndTime || (endTime && endTime > latestEndTime)) { if (!latestEndTime || (endTime && endTime.diff(latestEndTime).milliseconds > 0)) {
latestEndTime = endTime; latestEndTime = endTime;
} }
} }
if (earliestStartTime && earliestStartTime < eventStartTime) { if (earliestStartTime && earliestStartTime.diff(eventStartTime).milliseconds < 0) {
earliestStartTime.setMinutes(earliestStartTime.getMinutes() - 1); earliestStartTime = earliestStartTime.minus({ minutes: 1 });
globalStartTimeString = wubloaderTimeFromDateObj(earliestStartTime); globalStartTimeString = wubloaderTimeFromDateTime(earliestStartTime);
} }
if (latestEndTime && latestEndTime > eventEndTime) { if (latestEndTime && latestEndTime.diff(eventEndTime).milliseconds > 0) {
// If we're getting the time from a previous draft edit, we have seconds, so one minute is enough // If we're getting the time from a previous draft edit, we have seconds, so one minute is enough
latestEndTime.setMinutes(latestEndTime.getMinutes() + 1); latestEndTime = latestEndTime.plus({ minutes: 1 });
globalEndTimeString = wubloaderTimeFromDateObj(latestEndTime); globalEndTimeString = wubloaderTimeFromDateTime(latestEndTime);
} }
} }
document.getElementById("stream-time-setting-stream").innerText = globalStreamName; document.getElementById("stream-time-setting-stream").innerText = globalStreamName;
document.getElementById("stream-time-setting-start").value = document.getElementById("stream-time-setting-start").value =
getBusTimeFromTimeString(globalStartTimeString); busTimeFromWubloaderTime(globalStartTimeString);
document.getElementById("stream-time-setting-end").value = document.getElementById("stream-time-setting-end").value =
getBusTimeFromTimeString(globalEndTimeString); busTimeFromWubloaderTime(globalEndTimeString);
updateWaveform(); updateWaveform();
@ -392,13 +390,11 @@ async function initializeVideoInfo() {
} else { } else {
const rangeStartField = const rangeStartField =
rangeDefinitionsContainer.getElementsByClassName("range-definition-start")[0]; rangeDefinitionsContainer.getElementsByClassName("range-definition-start")[0];
rangeStartField.value = videoHumanTimeFromVideoPlayerTime(0); rangeStartField.value = videoHumanTimeFromWubloaderTime(globalStartTimeString);
const player = getVideoJS(); if (globalEndTimeString) {
const videoDuration = player.duration();
if (isFinite(videoDuration)) {
const rangeEndField = const rangeEndField =
rangeDefinitionsContainer.getElementsByClassName("range-definition-end")[0]; rangeDefinitionsContainer.getElementsByClassName("range-definition-end")[0];
rangeEndField.value = videoHumanTimeFromVideoPlayerTime(videoDuration); rangeEndField.value = videoHumanTimeFromWubloaderTime(globalEndTimeString);
} }
} }
rangeDataUpdated(); rangeDataUpdated();
@ -445,56 +441,14 @@ function getStartTime() {
if (!globalStartTimeString) { if (!globalStartTimeString) {
return null; return null;
} }
return dateObjFromWubloaderTime(globalStartTimeString); return dateTimeFromWubloaderTime(globalStartTimeString);
} }
function getEndTime() { function getEndTime() {
if (!globalEndTimeString) { if (!globalEndTimeString) {
return null; return null;
} }
return dateObjFromWubloaderTime(globalEndTimeString); return dateTimeFromWubloaderTime(globalEndTimeString);
}
function getBusTimeFromTimeString(timeString) {
if (timeString === "") {
return "";
}
const time = dateObjFromWubloaderTime(timeString);
return busTimeFromDateObj(time);
}
function busTimeFromDateObj(time) {
const busTimeMilliseconds = time - globalBusStartTime;
let remainingBusTimeSeconds = busTimeMilliseconds / 1000;
let sign = "";
if (remainingBusTimeSeconds < 0) {
sign = "-";
remainingBusTimeSeconds = Math.abs(remainingBusTimeSeconds);
}
const hours = Math.floor(remainingBusTimeSeconds / 3600);
remainingBusTimeSeconds %= 3600;
let minutes = Math.floor(remainingBusTimeSeconds / 60);
let seconds = remainingBusTimeSeconds % 60;
let milliseconds = Math.round((seconds % 1) * 1000);
seconds = Math.trunc(seconds);
while (minutes.toString().length < 2) {
minutes = `0${minutes}`;
}
while (seconds.toString().length < 2) {
seconds = `0${seconds}`;
}
if (milliseconds > 0) {
while (milliseconds.toString().length < 3) {
milliseconds = `0${milliseconds}`;
}
return `${sign}${hours}:${minutes}:${seconds}.${milliseconds}`;
}
return `${sign}${hours}:${minutes}:${seconds}`;
} }
async function submitVideo() { async function submitVideo() {
@ -632,11 +586,11 @@ function generateDownloadURL(timeRanges, downloadType, allowHoles, quality) {
for (const range of timeRanges) { for (const range of timeRanges) {
let timeRangeString = ""; let timeRangeString = "";
if (range.hasOwnProperty("start")) { if (range.hasOwnProperty("start")) {
timeRangeString += wubloaderTimeFromDateObj(range.start); timeRangeString += range.start;
} }
timeRangeString += ","; timeRangeString += ",";
if (range.hasOwnProperty("end")) { if (range.hasOwnProperty("end")) {
timeRangeString += wubloaderTimeFromDateObj(range.end); timeRangeString += range.end;
} }
queryParts.push(`range=${timeRangeString}`); queryParts.push(`range=${timeRangeString}`);
} }
@ -954,14 +908,21 @@ function setCurrentRangeEndToVideoTime() {
function videoPlayerTimeFromWubloaderTime(wubloaderTime) { function videoPlayerTimeFromWubloaderTime(wubloaderTime) {
const videoPlaylist = getPlaylistData(); const videoPlaylist = getPlaylistData();
const wubloaderDateObj = dateObjFromWubloaderTime(wubloaderTime); const wubloaderDateTime = dateTimeFromWubloaderTime(wubloaderTime);
let highestDiscontinuitySegmentBefore = 0; let highestDiscontinuitySegmentBefore = 0;
for (start of videoPlaylist.discontinuityStarts) { for (start of videoPlaylist.discontinuityStarts) {
const discontinuityStartSegment = videoPlaylist.segments[start]; const discontinuityStartSegment = videoPlaylist.segments[start];
const discontinuityStartDateTime = DateTime.fromJSDate(
discontinuityStartSegment.dateTimeObject,
{ zone: "utc" }
);
const highestDiscontinuitySegmentDateTime = DateTime.fromJSDate(
videoPlaylist.segments[highestDiscontinuitySegmentBefore].dateTimeObject,
{ zone: "utc" }
);
if ( if (
discontinuityStartSegment.dateTimeObject < wubloaderDateObj && discontinuityStartDateTime.diff(wubloaderDateTime).milliseconds < 0 && // Discontinuity starts before the provided time
discontinuityStartSegment.dateTimeObject > discontinuityStartDateTime.diff(highestDiscontinuitySegmentDateTime).milliseconds > 0 // Discontinuity starts after the latest found discontinuity
videoPlaylist.segments[highestDiscontinuitySegmentBefore].dateTimeObject
) { ) {
highestDiscontinuitySegmentBefore = start; highestDiscontinuitySegmentBefore = start;
} }
@ -971,16 +932,17 @@ function videoPlayerTimeFromWubloaderTime(wubloaderTime) {
for (let segment = 0; segment < highestDiscontinuitySegmentBefore; segment++) { for (let segment = 0; segment < highestDiscontinuitySegmentBefore; segment++) {
highestDiscontinuitySegmentStart += videoPlaylist.segments[segment].duration; highestDiscontinuitySegmentStart += videoPlaylist.segments[segment].duration;
} }
const highestDiscontinuitySegmentDateTime = DateTime.fromJSDate(
videoPlaylist.segments[highestDiscontinuitySegmentBefore].dateTimeObject,
{ zone: "utc" }
);
return ( return (
highestDiscontinuitySegmentStart + highestDiscontinuitySegmentStart +
secondsDifference( wubloaderDateTime.diff(highestDiscontinuitySegmentDateTime, "seconds").seconds
videoPlaylist.segments[highestDiscontinuitySegmentBefore].dateTimeObject,
wubloaderDateObj
)
); );
} }
function wubloaderTimeFromVideoPlayerTime(videoPlayerTime) { function dateTimeFromVideoPlayerTime(videoPlayerTime) {
const videoPlaylist = getPlaylistData(); const videoPlaylist = getPlaylistData();
let segmentStartTime = 0; let segmentStartTime = 0;
let segmentDateObj; let segmentDateObj;
@ -997,11 +959,14 @@ function wubloaderTimeFromVideoPlayerTime(videoPlayerTime) {
if (segmentDateObj === undefined) { if (segmentDateObj === undefined) {
return null; return null;
} }
let wubloaderDateObj = new Date(segmentDateObj); let wubloaderDateTime = DateTime.fromJSDate(segmentDateObj, { zone: "utc" });
const offset = videoPlayerTime - segmentStartTime; const offset = videoPlayerTime - segmentStartTime;
const offsetMilliseconds = offset * 1000; return wubloaderDateTime.plus({ seconds: offset });
wubloaderDateObj.setMilliseconds(wubloaderDateObj.getMilliseconds() + offsetMilliseconds); }
return wubloaderDateObj;
function wubloaderTimeFromVideoPlayerTime(videoPlayerTime) {
const dt = dateTimeFromVideoPlayerTime(videoPlayerTime);
return wubloaderTimeFromDateTime(dt);
} }
function videoHumanTimeFromVideoPlayerTime(videoPlayerTime) { function videoHumanTimeFromVideoPlayerTime(videoPlayerTime) {
@ -1058,10 +1023,3 @@ function getPlaylistData() {
// etc.), this and all callers will need to be updated. // etc.), this and all callers will need to be updated.
return player.tech("OK").vhs.playlists.master.playlists[0]; return player.tech("OK").vhs.playlists.master.playlists[0];
} }
function secondsDifference(date1, date2) {
if (date2 > date1) {
return (date2 - date1) / 1000;
}
return (date1 - date2) / 1000;
}

File diff suppressed because one or more lines are too long

@ -29,20 +29,18 @@ async function loadDefaults() {
const streamNameField = document.getElementById("stream-time-setting-stream"); const streamNameField = document.getElementById("stream-time-setting-stream");
streamNameField.value = defaultData.video_channel; streamNameField.value = defaultData.video_channel;
globalBusStartTime = new Date(defaultData.bustime_start); globalBusStartTime = DateTime.fromISO(defaultData.bustime_start, { zone: "utc" });
} }
// Gets the start time of the video from settings. Returns an invalid date object if the user entered bad data. // Gets the start time of the video from settings. Returns an invalid date object if the user entered bad data.
function getStartTime() { function getStartTime() {
switch (globalVideoTimeReference) { switch (globalVideoTimeReference) {
case 1: case 1:
return dateObjFromWubloaderTime(globalStartTimeString); return dateTimeFromWubloaderTime(globalStartTimeString);
case 2: case 2:
return dateObjFromBusTime(globalStartTimeString); return dateTimeFromBusTime(globalStartTimeString);
case 3: case 3:
return new Date( return DateTime.now().minus(parseHumanTimeStringAsDateTimeMathObject(globalStartTimeString));
new Date().getTime() - 1000 * parseInputTimeAsNumberOfSeconds(globalStartTimeString)
);
} }
} }
@ -53,27 +51,12 @@ function getEndTime() {
} }
switch (globalVideoTimeReference) { switch (globalVideoTimeReference) {
case 1: case 1:
return dateObjFromWubloaderTime(globalEndTimeString); return dateTimeFromWubloaderTime(globalEndTimeString);
case 2: case 2:
return dateObjFromBusTime(globalEndTimeString); return dateTimeFromBusTime(globalEndTimeString);
case 3: case 3:
return new Date( return DateTime.now().minus(parseHumanTimeStringAsDateTimeMathObject(globalEndTimeString));
new Date().getTime() - 1000 * parseInputTimeAsNumberOfSeconds(globalEndTimeString)
);
}
}
function parseInputTimeAsNumberOfSeconds(inputTime) {
// We need to handle inputs like "-0:10:15" in a way that consistently makes the time negative.
// Since we can't assign the negative sign to any particular part, we'll check for the whole thing here.
let direction = 1;
if (inputTime.startsWith("-")) {
inputTime = inputTime.slice(1);
direction = -1;
} }
const parts = inputTime.split(":", 3);
return (parseInt(parts[0]) + (parts[1] || 0) / 60 + (parts[2] || 0) / 3600) * 60 * 60 * direction;
} }
function updateTimeSettings() { function updateTimeSettings() {
@ -89,7 +72,7 @@ function updateTimeSettings() {
const startTime = getStartTime(); const startTime = getStartTime();
const endTime = getEndTime(); const endTime = getEndTime();
if (endTime && endTime < startTime) { if (endTime && endTime.diff(startTime) < 0) {
addError( addError(
"End time is before the start time. This will prevent video loading and cause other problems." "End time is before the start time. This will prevent video loading and cause other problems."
); );
@ -97,8 +80,8 @@ function updateTimeSettings() {
} }
function generateDownloadURL(startTime, endTime, downloadType, allowHoles, quality) { function generateDownloadURL(startTime, endTime, downloadType, allowHoles, quality) {
const startURLTime = wubloaderTimeFromDateObj(startTime); const startURLTime = wubloaderTimeFromDateTime(startTime);
const endURLTime = wubloaderTimeFromDateObj(endTime); const endURLTime = wubloaderTimeFromDateTime(endTime);
const queryParts = [`type=${downloadType}`, `allow_holes=${allowHoles}`]; const queryParts = [`type=${downloadType}`, `allow_holes=${allowHoles}`];
if (startURLTime) { if (startURLTime) {

Loading…
Cancel
Save