mirror of https://github.com/ekimekim/wubloader
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
158 lines
4.8 KiB
JavaScript
158 lines
4.8 KiB
JavaScript
3 years ago
|
var globalBusStartTime = new Date("1970-01-01T00:00:00Z");
|
||
|
var globalStreamName = "";
|
||
|
var globalStartTimeString = 0;
|
||
|
var globalEndTimeString = 0;
|
||
|
|
||
|
const VIDEO_FRAMES_PER_SECOND = 30;
|
||
|
|
||
|
const TIME_FRAME_UTC = 1;
|
||
|
const TIME_FRAME_BUS = 2;
|
||
|
const TIME_FRAME_AGO = 3;
|
||
|
|
||
|
const PLAYBACK_RATES = [0.5, 1, 1.25, 1.5, 2];
|
||
|
|
||
|
function getVideoJS() {
|
||
|
return videojs("video");
|
||
|
}
|
||
|
|
||
|
function addError(errorText) {
|
||
|
const errorElement = document.createElement("div");
|
||
|
errorElement.innerText = errorText;
|
||
|
|
||
|
const dismissElement = document.createElement("a");
|
||
|
dismissElement.classList.add("error-dismiss");
|
||
|
dismissElement.innerText = "[X]";
|
||
|
errorElement.appendChild(dismissElement);
|
||
|
dismissElement.addEventListener("click", (event) => {
|
||
|
const errorHost = document.getElementById("errors");
|
||
|
errorHost.removeChild(errorElement);
|
||
|
});
|
||
|
|
||
|
const errorHost = document.getElementById("errors");
|
||
|
errorHost.appendChild(errorElement);
|
||
|
}
|
||
|
|
||
|
function loadVideoPlayer(playlistURL) {
|
||
|
let rangedPlaylistURL = assembleVideoPlaylistURL(playlistURL);
|
||
|
|
||
|
let defaultOptions = {
|
||
|
sources: [{ src: rangedPlaylistURL }],
|
||
|
liveui: true,
|
||
|
controls: true,
|
||
|
autoplay: false,
|
||
|
playbackRates: PLAYBACK_RATES,
|
||
|
inactivityTimeout: 0,
|
||
|
controlBar: {
|
||
|
fullscreenToggle: true,
|
||
|
volumePanel: {
|
||
|
inline: false
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
const player = videojs("video", defaultOptions);
|
||
|
player.ready(() => {
|
||
|
player.volume(0.5); // Initialize to half volume
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function updateVideoPlayer(newPlaylistURL) {
|
||
|
let rangedPlaylistURL = assembleVideoPlaylistURL(newPlaylistURL);
|
||
|
const player = getVideoJS();
|
||
|
player.src({ src: rangedPlaylistURL });
|
||
|
}
|
||
|
|
||
|
function updateStoredTimeSettings() {
|
||
|
globalStreamName = document.getElementById("stream-time-setting-stream").value;
|
||
|
globalStartTimeString = document.getElementById("stream-time-setting-start").value;
|
||
|
globalEndTimeString = document.getElementById("stream-time-setting-end").value;
|
||
|
}
|
||
|
|
||
|
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 getSelectedTimeConversion() {
|
||
|
const radioSelection = document.querySelectorAll("#stream-time-frame-of-reference > input");
|
||
|
for (radioItem of radioSelection) {
|
||
|
if (radioItem.checked) {
|
||
|
return +radioItem.value;
|
||
|
}
|
||
|
}
|
||
|
// This selection shouldn't ever become fully unchecked. We'll return the bus time by default
|
||
|
// if it does because why not?
|
||
|
return TIME_FRAME_BUS;
|
||
|
}
|
||
|
|
||
|
// Gets the start time of the video from settings. Returns an invalid date object if the user entered bad data.
|
||
|
function getStartTime() {
|
||
|
switch (getSelectedTimeConversion()) {
|
||
|
case 1:
|
||
|
return new Date(globalStartTimeString + "Z");
|
||
|
case 2:
|
||
|
return new Date(globalBusStartTime.getTime() + (1000 * parseInputTimeAsNumberOfSeconds(globalStartTimeString)));
|
||
|
case 3:
|
||
|
return new Date(new Date().getTime() - (1000 * parseInputTimeAsNumberOfSeconds(globalStartTimeString)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Gets the end time of the video from settings. Returns null if there's no end time. Returns an invalid date object if the user entered bad data.
|
||
|
function getEndTime() {
|
||
|
if (globalEndTimeString === "") {
|
||
|
return null;
|
||
|
}
|
||
|
switch (getSelectedTimeConversion()) {
|
||
|
case 1:
|
||
|
return new Date(globalEndTimeString + "Z");
|
||
|
case 2:
|
||
|
return new Date(globalBusStartTime.getTime() + (1000 * parseInputTimeAsNumberOfSeconds(globalEndTimeString)));
|
||
|
case 3:
|
||
|
return new Date(new Date().getTime() - (1000 * parseInputTimeAsNumberOfSeconds(globalEndTimeString)));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function getWubloaderTimeFromDate(date) {
|
||
|
if (!date) {
|
||
|
return null;
|
||
|
}
|
||
|
return date.toISOString().substring(0, 19); // Trim milliseconds and "Z" marker
|
||
|
}
|
||
|
|
||
|
function assembleVideoPlaylistURL(basePlaylistURL) {
|
||
|
let playlistURL = basePlaylistURL;
|
||
|
|
||
|
let startTime = getStartTime();
|
||
|
let endTime = getEndTime();
|
||
|
|
||
|
let queryStringParts = [];
|
||
|
if (startTime) {
|
||
|
queryStringParts.push("start=" + getWubloaderTimeFromDate(startTime));
|
||
|
}
|
||
|
if (endTime) {
|
||
|
queryStringParts.push("end=" + getWubloaderTimeFromDate(endTime));
|
||
|
}
|
||
|
if (queryStringParts) {
|
||
|
playlistURL += "?" + queryStringParts.join("&");
|
||
|
}
|
||
|
return playlistURL;
|
||
|
}
|
||
|
|
||
|
function generateDownloadURL(startTime, endTime, downloadType, allowHoles) {
|
||
|
const startURLTime = getWubloaderTimeFromDate(startTime);
|
||
|
const endURLTime = getWubloaderTimeFromDate(endTime);
|
||
|
|
||
|
const queryParts = ["start=" + startURLTime, "end=" + endURLTime, "type=" + downloadType, "allow_holes=" + allowHoles];
|
||
|
|
||
|
const downloadURL = "/cut/" + globalStreamName + "/source.ts?" + queryParts.join("&");
|
||
|
return downloadURL;
|
||
|
}
|