mirror of https://github.com/ekimekim/wubloader
Merge pull request #75 from ekimekim/gunner/thrimbletrimmer-integration
Gunner/thrimbletrimmer integrationmike/render-dashboard
commit
54f6a707f5
@ -1,4 +1,5 @@
|
|||||||
# nginx container contains config that exposes all the various services metrics
|
# nginx container contains config that exposes all the various services metrics
|
||||||
FROM nginx:latest
|
FROM nginx:latest
|
||||||
ADD nginx/generate-config /
|
ADD nginx/generate-config /
|
||||||
|
COPY thrimbletrimmer /etc/nginx/html/thrimbletrimmer
|
||||||
ENTRYPOINT ["/bin/sh", "-c", "/generate-config && nginx -g \"daemon off;\""]
|
ENTRYPOINT ["/bin/sh", "-c", "/generate-config && nginx -g \"daemon off;\""]
|
||||||
|
@ -0,0 +1,142 @@
|
|||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en-US">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<title>Thrimbletrimmer Goes Forth</title>
|
||||||
|
<meta name="description" content="">
|
||||||
|
|
||||||
|
<meta name="google-signin-client_id" content="345276493482-r84m2giavk10glnmqna0lbq8e1hdaus0.apps.googleusercontent.com">
|
||||||
|
<script src="https://apis.google.com/js/platform.js?onload=onGLoad" async defer></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!-- https://developers.google.com/identity/sign-in/web/sign-in -->
|
||||||
|
<div class="g-signin2" data-onsuccess="onSignIn"></div>
|
||||||
|
<a href="#" onclick="signOut();">Sign out</a>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var user;
|
||||||
|
function onSignIn(googleUser) {
|
||||||
|
user = googleUser;
|
||||||
|
var profile = googleUser.getBasicProfile();
|
||||||
|
console.log('ID: ' + profile.getId()); // Do not send to your backend! Use an ID token instead.
|
||||||
|
console.log('Name: ' + profile.getName());
|
||||||
|
console.log('Image URL: ' + profile.getImageUrl());
|
||||||
|
console.log('Email: ' + profile.getEmail()); // This is null if the 'email' scope is not present.
|
||||||
|
console.log('ID Token: ' + googleUser.getAuthResponse().id_token);
|
||||||
|
}
|
||||||
|
function signOut() {
|
||||||
|
user = null;
|
||||||
|
var auth2 = gapi.auth2.getAuthInstance();
|
||||||
|
auth2.signOut().then(function () {
|
||||||
|
console.log('User signed out.');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<div>
|
||||||
|
<br/>
|
||||||
|
<input id="server" value="" />
|
||||||
|
<input id="rowId" value="04860aa4-d6a5-11e9-9d36-2a2ae2dbcce4" />
|
||||||
|
<input type="button" onclick="getRow()" value="Get Row"/>
|
||||||
|
<a href="/thrimshim">All Rows</a>
|
||||||
|
<br/>
|
||||||
|
<textarea id="rowdump"></textarea>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<br/>
|
||||||
|
<input type="button" onclick="testAuth()" value="Test Auth" /><br />
|
||||||
|
<input type="button" onclick="testSubmit()" value="Test Submit" /><br />
|
||||||
|
<input type="button" onclick="testManualLink()" value="Test Manual Link" /><input id="manualLink" value="google.ca"/><br />
|
||||||
|
<input type="button" onclick="testReset()" value="Test Reset" /><br />
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
function getRow() {
|
||||||
|
fetch(document.getElementById("server").value+"/thrimshim/"+document.getElementById("rowId").value).then(function (response) {
|
||||||
|
response.text().then(function(data) {
|
||||||
|
document.getElementById("rowdump").value=data;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function testAuth() {
|
||||||
|
fetch(document.getElementById("server").value+"/thrimshim/auth-test", {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
test: "123 Hello World?",
|
||||||
|
token: user.getAuthResponse().id_token
|
||||||
|
})
|
||||||
|
}).then(function(response) {
|
||||||
|
if (response.status !== 200) {
|
||||||
|
console.log('Looks like there was a problem. Status Code: ' + response.status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Examine the text in the response
|
||||||
|
response.json().then(function(data) {
|
||||||
|
console.log(data);
|
||||||
|
});
|
||||||
|
}).catch(function(err) {
|
||||||
|
console.log('Fetch Error :-S', err);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function testSubmit() {
|
||||||
|
var wubData = {
|
||||||
|
allow_holes: "true",
|
||||||
|
experimental: "true",
|
||||||
|
state: "EDITED",
|
||||||
|
token: user.getAuthResponse().id_token,
|
||||||
|
upload_location: "YouTube",
|
||||||
|
uploader_whitelist: null,
|
||||||
|
video_channel: "rpglimitbreak",
|
||||||
|
video_description: "Test Description",
|
||||||
|
video_end: "2019-09-14T03:54:28.546",
|
||||||
|
video_quality: "source",
|
||||||
|
video_start: "2019-09-14T03:48:06.546",
|
||||||
|
video_title: "Test"
|
||||||
|
}
|
||||||
|
|
||||||
|
//Submit to thrimshim
|
||||||
|
fetch(document.getElementById("server").value+"/thrimshim/"+document.getElementById("rowId").value, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(wubData)
|
||||||
|
}).then(data => console.log(data));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function testManualLink() {
|
||||||
|
fetch(document.getElementById("server").value+"/thrimshim/manual-link/"+document.getElementById("rowId").value, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
link: document.getElementById("manualLink").value,
|
||||||
|
token: user.getAuthResponse().id_token
|
||||||
|
})
|
||||||
|
}).then(data => console.log(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
function testReset() {
|
||||||
|
fetch(document.getElementById("server").value+"/thrimshim/reset/"+document.getElementById("rowId").value, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({token: user.getAuthResponse().id_token})
|
||||||
|
}).then(data => console.log(data));
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,247 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en-US">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<title>Thrimbletrimmer Goes Forth</title>
|
||||||
|
<meta name="description" content="">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||||
|
<!-- <link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
|
||||||
|
|
||||||
|
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
|
||||||
|
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script> -->
|
||||||
|
<style>
|
||||||
|
html, body {
|
||||||
|
height:100%;
|
||||||
|
margin:0px;
|
||||||
|
background-color:darkgrey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sectionContainer {
|
||||||
|
margin:24px auto;
|
||||||
|
padding:32px;
|
||||||
|
border-radius:4px;
|
||||||
|
background:white;
|
||||||
|
box-shadow:0 0 34px rgba(0,0,0,.26);
|
||||||
|
max-width:1280px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#QueueTable {
|
||||||
|
width:100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
#QueueTable, #QueueTable th, #QueueTable td {
|
||||||
|
border: 1px solid #cccccc;
|
||||||
|
}
|
||||||
|
#QueueTable tr:nth-child(even) {
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
}
|
||||||
|
#QueueTable tr:hover {
|
||||||
|
background-color:#dddddd;
|
||||||
|
}
|
||||||
|
#QueueTable th {
|
||||||
|
line-height:32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filterMenu {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: rgb(221, 221, 221);
|
||||||
|
border-radius: 5px 5px 0px 0px;
|
||||||
|
}
|
||||||
|
.filterList {
|
||||||
|
display:none;
|
||||||
|
List-style-type:none;
|
||||||
|
margin:10px 0px 0px -10px;
|
||||||
|
padding:10px;
|
||||||
|
border:1px solid black;
|
||||||
|
position:absolute;
|
||||||
|
background-color:white;
|
||||||
|
min-width:100px;
|
||||||
|
}
|
||||||
|
.filterMenu:hover .filterList {
|
||||||
|
display:inline-block;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style>
|
||||||
|
/* Styles based on event category */
|
||||||
|
#QueueTable .RDP {
|
||||||
|
background-color: #f4cccc;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<!-- <div class="sectionContainer" style="display:none;">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Stream</th>
|
||||||
|
<th>Start Time</th>
|
||||||
|
<th>End Time</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><input id="StreamName" value="gamesdonequick" /></td>
|
||||||
|
<td><input id="StreamStart" value="2019-01-06T16:00:00" /></td>
|
||||||
|
<td><input id="StreamEnd" value="2019-01-06T17:00:00" /></td>
|
||||||
|
<td><input type="button" value="Load Playlist" onclick="loadPlaylist()" /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><a href="javascript:alert('seabats, lunarjade, gamesdonequick');">Streams</a></td>
|
||||||
|
<td><a href="javascript:window.open('/files/' + document.getElementById('StreamName').value + '/source', '_blank');">Hours</a></td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div> -->
|
||||||
|
|
||||||
|
<div class="sectionContainer">
|
||||||
|
<h1 style="color:#1976d2;font-size:34px;line-height:38px;">Wubloader Queue</h1>
|
||||||
|
<!-- Add in filters based on time period, category, and state -->
|
||||||
|
<!-- Throw in JQueryUI to run the filter menus, not worth re-inventing the wheel -->
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.ui-menu { width: 150px; }
|
||||||
|
</style>
|
||||||
|
<div id="FiltersMenu">
|
||||||
|
<div class="filterMenu" style="padding-bottom:7px;">
|
||||||
|
<input id="DateFilterStart" placeholder="Start Date" />
|
||||||
|
</div>
|
||||||
|
<div class="filterMenu" style="padding-bottom:7px;">
|
||||||
|
<input id="DateFilterEnd" placeholder="End Date" />
|
||||||
|
</div>
|
||||||
|
<div id="CategoryFiltersMenu" class="filterMenu">
|
||||||
|
<div>Category Filter</div>
|
||||||
|
<ul id="CategoryFilter" class="filterList"></ul>
|
||||||
|
</div>
|
||||||
|
<div id="StateFiltersMenu" class="filterMenu">
|
||||||
|
<div>State Filter</div>
|
||||||
|
<ul id="StateFilter" class="filterList"></ul>
|
||||||
|
</div>
|
||||||
|
<input type="button" value="Apply Filters" onclick="applyFilters()"/>
|
||||||
|
<input type="button" value="Reset Filters" onclick="window.location.href = '/thrimbletrimmer/dashboard.html'"/>
|
||||||
|
</div>
|
||||||
|
<table id="QueueTable">
|
||||||
|
<tr>
|
||||||
|
<th>Start Time</th>
|
||||||
|
<th>End Time</th>
|
||||||
|
<th>Category</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>State</th>
|
||||||
|
<th>Edit</th>
|
||||||
|
<th>Link</th>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
// var startOfHour = new Date(new Date().setMinutes(0,0,0));
|
||||||
|
// document.getElementById("StreamStart").value = new Date(startOfHour.getTime() - 1000*60*60).toISOString().substring(0,19);
|
||||||
|
// document.getElementById("StreamEnd").value = startOfHour.toISOString().substring(0,19);
|
||||||
|
function sanitizeInput(input) {
|
||||||
|
let tempElement = document.createElement("SPAN");
|
||||||
|
tempElement.appendChild(document.createTextNode(input));
|
||||||
|
return tempElement.innerHTML;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getEvents() {
|
||||||
|
let response = await fetch("/thrimshim");
|
||||||
|
let data = await response.json();
|
||||||
|
//Sanitize user inputs that could be used for xss
|
||||||
|
data.forEach(event => {
|
||||||
|
event.category = sanitizeInput(event.category);
|
||||||
|
event.description = sanitizeInput(event.description);
|
||||||
|
})
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function populateFilters(events) {
|
||||||
|
var urlParams = new URLSearchParams(window.location.search);
|
||||||
|
|
||||||
|
//Set up Date filters
|
||||||
|
if (urlParams.has("start")) {
|
||||||
|
document.getElementById("DateFilterStart").value = urlParams.get("start");
|
||||||
|
}
|
||||||
|
if (urlParams.has("end")) {
|
||||||
|
document.getElementById("DateFilterEnd").value = urlParams.get("end");
|
||||||
|
}
|
||||||
|
|
||||||
|
//Set up Category filters
|
||||||
|
let categoryFilters = urlParams.has("category") ? urlParams.get("category").split(","):null;
|
||||||
|
new Set(events.map(event => event.category).sort()).forEach((category, index) => {
|
||||||
|
let row = document.createElement("TR");
|
||||||
|
row.innerHTML = `<li><input type="checkbox" name="categoryCheckbox-${index}" filtervalue="${category}" ${!categoryFilters || categoryFilters.indexOf(category) >=0 ? "checked":""}><label for="categoryCheckbox-${index}">${category}</label></li>`;
|
||||||
|
document.getElementById('CategoryFilter').appendChild(row);
|
||||||
|
});
|
||||||
|
|
||||||
|
//Set up State filters
|
||||||
|
let stateFilters = urlParams.has("state") ? urlParams.get("state").split(","):null;
|
||||||
|
//new Set(events.map(event => event.state).sort()).forEach((state, index) => {
|
||||||
|
["UNEDITED", "EDITED", "CLAIMED", "FINALIZING", "TRANSCODING", "DONE"].forEach((state, index) => {
|
||||||
|
let row = document.createElement("TR");
|
||||||
|
row.innerHTML = `<li><input type="checkbox" name="stateCheckbox-${index}" filtervalue="${state}" ${!stateFilters || stateFilters.indexOf(state) >=0 ? "checked":""}><label for="stateCheckbox-${index}">${state}</label></li>`;
|
||||||
|
document.getElementById('StateFilter').appendChild(row);
|
||||||
|
});
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
|
||||||
|
function filterEvents(events) {
|
||||||
|
if(!window.location.search) { return events; }
|
||||||
|
|
||||||
|
var urlParams = new URLSearchParams(window.location.search);
|
||||||
|
|
||||||
|
if(urlParams.has("start")) {
|
||||||
|
let startDate = new Date(urlParams.get("start"));
|
||||||
|
events = events.filter(event => new Date(event.event_start) >= startDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(urlParams.has("end")) {
|
||||||
|
let endDate = new Date(urlParams.get("end"));
|
||||||
|
events = events.filter(event => new Date(event.event_start) <= endDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(urlParams.has("category")) {
|
||||||
|
events = events.filter(event => urlParams.get("category").split(",").indexOf(event.category) >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(urlParams.has("state")) {
|
||||||
|
events = events.filter(event => urlParams.get("state").split(",").indexOf(event.state) >= 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
|
||||||
|
function populateTable (events) {
|
||||||
|
events.forEach(event => {
|
||||||
|
let row = document.createElement("TR");
|
||||||
|
row.innerHTML = `
|
||||||
|
<td>${event.event_start}</td>
|
||||||
|
<td>${event.event_end}</td>
|
||||||
|
<td class="${event.category.replace(/ /g, "")}">${event.category}</td>
|
||||||
|
<td>${event.description}</td>
|
||||||
|
<td>${event.state}</td>
|
||||||
|
<td><a href="/thrimbletrimmer?id=${event.id}">Edit</a></td>
|
||||||
|
<td>${event.video_link ? "<a href='"+event.video_link+"'>"+event.video_link+"</a>":""}</td>
|
||||||
|
`;
|
||||||
|
document.getElementById('QueueTable').appendChild(row);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyFilters() {
|
||||||
|
let startDateFilter = document.getElementById("DateFilterStart").value;
|
||||||
|
let endDateFilter = document.getElementById("DateFilterEnd").value;
|
||||||
|
let categoryfilters = Array.from(document.querySelectorAll("#CategoryFilter :checked")).map(checkbox => checkbox.getAttribute("filtervalue")).join();
|
||||||
|
let statefilters = Array.from(document.querySelectorAll("#StateFilter :checked")).map(checkbox => checkbox.getAttribute("filtervalue")).join();
|
||||||
|
window.location.href = `/thrimbletrimmer/dashboard.html?${startDateFilter ? "start="+startDateFilter+"&":""}${endDateFilter ? "end="+endDateFilter+"&":""}category=${categoryfilters}&state=${statefilters}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
//On Page Load
|
||||||
|
getEvents().then(populateFilters).then(filterEvents).then(populateTable);
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,163 @@
|
|||||||
|
|
||||||
|
<!--
|
||||||
|
TODOs:
|
||||||
|
Move Google sign-in/out buttons, and make it clear when you're not signed in.
|
||||||
|
Move "Reset" and "Manual Link" options in here.
|
||||||
|
Clean up the Options/Input header, move parts of it into a hidden "Advanced" menu.
|
||||||
|
Create a cleaner player-only version of the page, or find a way to make it a version of this one via URL switch.
|
||||||
|
-->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en-US">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<title>Thrimbletrimmer Goes Forth</title>
|
||||||
|
<meta name="description" content="">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="google-signin-client_id" content="345276493482-r84m2giavk10glnmqna0lbq8e1hdaus0.apps.googleusercontent.com">
|
||||||
|
|
||||||
|
<link href="/thrimbletrimmer/plugins/video.js/dist/video-js.min.css" rel="stylesheet">
|
||||||
|
<link href="/thrimbletrimmer/plugins/videojs-hls-quality-selector/dist/videojs-hls-quality-selector.css" rel="stylesheet">
|
||||||
|
<link href="/thrimbletrimmer/plugins/videojs-trimming-controls/dist/videojs-trimming-controls.css" rel="stylesheet">
|
||||||
|
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||||
|
<!-- <script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script> -->
|
||||||
|
<script src="/thrimbletrimmer/plugins/video.js/dist/video.min.js"></script>
|
||||||
|
<script src="/thrimbletrimmer/plugins/videojs-contrib-quality-levels/dist/videojs-contrib-quality-levels.min.js"></script>
|
||||||
|
<script src="/thrimbletrimmer/plugins/videojs-hls-quality-selector/dist/videojs-hls-quality-selector.min.js"></script>
|
||||||
|
<script src="/thrimbletrimmer/plugins/videojs-trimming-controls/dist/videojs-trimming-controls.js"></script>
|
||||||
|
|
||||||
|
<script src="https://apis.google.com/js/platform.js?onload=onGLoad" async defer></script>
|
||||||
|
|
||||||
|
<link href="/thrimbletrimmer/styles/style.css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div style="max-width:1280px;margin:auto;padding-top:25px;">
|
||||||
|
<table id="wubloaderInputTable">
|
||||||
|
<tr>
|
||||||
|
<th>Stream</th>
|
||||||
|
<th>Start Time</th>
|
||||||
|
<th>End Time</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><input id="StreamName" value="desertbus" /></td>
|
||||||
|
<td><input id="StreamStart" style="display:none;" class="UTCTimeInput" value="" /><input id="BusTimeStart" class="BusTimeInput" value="0:00" /></td>
|
||||||
|
<td><input id="StreamEnd" style="display:none;" class="UTCTimeInput" value="" /><input id="BusTimeEnd" class="BusTimeInput" value="1:00" /></td>
|
||||||
|
<td><input type="button" value="Load Playlist" onclick="loadPlaylist()" /></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td>
|
||||||
|
<input type="radio" id="BusTimeToggleUTC" name="BusTimeToggle" value="UTC" onclick="toggleTimeInput(this.value)"> UTC
|
||||||
|
<input type="radio" id="BusTimeToggleBus" name="BusTimeToggle" value="BUSTIME" onclick="toggleTimeInput(this.value)" checked="checked"> Bustime
|
||||||
|
</td>
|
||||||
|
<td><a id="AdvancedOptionsButton" href="JavaScript:toggleHiddenPane('wubloaderAdvancedInputTable');">Advanced Submit Options</a></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<table id="wubloaderAdvancedInputTable" style="display:none;">
|
||||||
|
<tr>
|
||||||
|
<td><a href="javascript:window.open('/files');">Streams</a></td>
|
||||||
|
<td><a href="javascript:window.open('/files/' + document.getElementById('StreamName').value + '/source', '_blank');">Hours</a></td>
|
||||||
|
</tr>
|
||||||
|
<tr><td>Allow Holes: </td><td><input id="AllowHoles" type="checkbox" checked /></td></tr>
|
||||||
|
<tr><td>Quality Level: </td><td><select id="qualityLevel"></select></td></tr>
|
||||||
|
<tr><td>Upload Location: </td><td><select id="uploadLocation"><option value="YouTube" selected>YouTube</option></select></td></tr>
|
||||||
|
<tr><td>Uploader Whitelist: </td><td><input id="uploaderWhitelist" title="Uploader Whitelist" /></td></tr>
|
||||||
|
<tr>
|
||||||
|
<td>ThrimShim ID:</td>
|
||||||
|
<td><input id="hiddenSubmissionID" value="" /></td>
|
||||||
|
<td><input type="button" value="Load Event" onclick="window.location.search = '?id='+document.getElementById('hiddenSubmissionID').value"/></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div id="EditorContainer">
|
||||||
|
<video id="my-player" class="video-js" controls preload="auto" style="display:none">
|
||||||
|
<p class="vjs-no-js">To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="http://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a></p>
|
||||||
|
</video>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="EditorDetailsPane">
|
||||||
|
<div>
|
||||||
|
Title: <br />
|
||||||
|
<input type="text" id="VideoTitle" value="DB2019 - " maxlength="91" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
Description:<br/>
|
||||||
|
<textarea id="VideoDescription" ></textarea>
|
||||||
|
</div>
|
||||||
|
<input type="button" id="SubmitButton" value="Submit" onclick="thrimbletrimmerSubmit()"/>
|
||||||
|
<input type="button" id="DownloadButton" value="Download" onclick="thrimbletrimmerDownload()"/>
|
||||||
|
<a href="/thrimbletrimmer/dashboard.html">Go To Dashboard</a> |
|
||||||
|
<a id="ManualLinkButton" href="JavaScript:toggleHiddenPane('ManualLinkPane');">Manual Link</a> |
|
||||||
|
<a id="ResetButton" href="JavaScript:thrimbletrimmerResetLink();">Reset Edits</a>
|
||||||
|
<a id="HelpButton" style="float:right;" href="JavaScript:toggleHiddenPane('HelpPane');">Help</a>
|
||||||
|
<a id="UltrawideButton" style="float:right;margin-right:10px;" href="JavaScript:toggleUltrawide();">Ultrawide</a>
|
||||||
|
</div>
|
||||||
|
<div id="ManualLinkPane" style="display:none">
|
||||||
|
<input id="ManualLink" /> <input type="button" onclick="thrimbletrimmerManualLink()" value="Set Link" />
|
||||||
|
</div>
|
||||||
|
<div id="HelpPane" style="display:none;">
|
||||||
|
<ul>
|
||||||
|
<li>J/K/L - Back 10 seconds, Play/Pause, Advance 10 seconds</li>
|
||||||
|
<li>LeftArrow/RightArrow - Back 5 seconds, Advance 5 seconds</li>
|
||||||
|
<li>,/. - Back 0.1 seconds, Advance 0.1 seconds</li>
|
||||||
|
<li>I/O - Set start of trim at playhead, set end of trim at playhead</li>
|
||||||
|
<li>0-9 - Jump to 0% - 90% through the video.</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<iframe id="outputFile" style="display:none;"></iframe>
|
||||||
|
|
||||||
|
<script src="/thrimbletrimmer/scripts/playerSetup.js"></script>
|
||||||
|
<script src="/thrimbletrimmer/scripts/keyboardShortcuts.js"></script>
|
||||||
|
<script src="/thrimbletrimmer/scripts/IO.js"></script>
|
||||||
|
|
||||||
|
<script>pageSetup();</script>
|
||||||
|
<script>
|
||||||
|
function toggleHiddenPane(paneID) {
|
||||||
|
var pane = document.getElementById(paneID);
|
||||||
|
pane.style.display = (pane.style.display === "none") ? "block":"none";
|
||||||
|
}
|
||||||
|
function toggleUltrawide() {
|
||||||
|
var body = document.getElementsByTagName("Body")[0];
|
||||||
|
body.classList.contains("ultrawide") ? body.classList.remove("ultrawide"):body.classList.add("ultrawide");
|
||||||
|
}
|
||||||
|
function toggleTimeInput(toggleInput) {
|
||||||
|
if(toggleInput == "UTC") {
|
||||||
|
document.getElementById("BusTimeStart").style.display = "none";
|
||||||
|
document.getElementById("BusTimeEnd").style.display = "none";
|
||||||
|
document.getElementById("StreamStart").style.display = "";
|
||||||
|
document.getElementById("StreamEnd").style.display = "";
|
||||||
|
} else {
|
||||||
|
document.getElementById("StreamStart").style.display = "none";
|
||||||
|
document.getElementById("StreamEnd").style.display = "none";
|
||||||
|
document.getElementById("BusTimeStart").style.display = "";
|
||||||
|
document.getElementById("BusTimeEnd").style.display = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="g-signin2" data-onsuccess="onSignIn"></div>
|
||||||
|
<a href="#" onclick="signOut();">Sign out</a>
|
||||||
|
<script>
|
||||||
|
var user;
|
||||||
|
function onSignIn(googleUser) {
|
||||||
|
user = googleUser;
|
||||||
|
var profile = googleUser.getBasicProfile();
|
||||||
|
console.log('ID: ' + profile.getId()); // Do not send to your backend! Use an ID token instead.
|
||||||
|
console.log('Name: ' + profile.getName());
|
||||||
|
console.log('Image URL: ' + profile.getImageUrl());
|
||||||
|
console.log('Email: ' + profile.getEmail()); // This is null if the 'email' scope is not present.
|
||||||
|
console.log('ID Token: ' + googleUser.getAuthResponse().id_token);
|
||||||
|
}
|
||||||
|
function signOut() {
|
||||||
|
user = null;
|
||||||
|
var auth2 = gapi.auth2.getAuthInstance();
|
||||||
|
auth2.signOut().then(function () {
|
||||||
|
console.log('User signed out.');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,2 @@
|
|||||||
|
/*! @name videojs-contrib-quality-levels @version 2.0.9 @license Apache-2.0 */
|
||||||
|
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("video.js"),require("global/document")):"function"==typeof define&&define.amd?define(["video.js","global/document"],t):e.videojsContribQualityLevels=t(e.videojs,e.document)}(this,function(e,t){"use strict";function n(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}e=e&&e.hasOwnProperty("default")?e.default:e,t=t&&t.hasOwnProperty("default")?t.default:t;var r=function(r){var i,l;function o(){var i,l=n(n(i=r.call(this)||this));if(e.browser.IS_IE8)for(var s in l=t.createElement("custom"),o.prototype)"constructor"!==s&&(l[s]=o.prototype[s]);return l.levels_=[],l.selectedIndex_=-1,Object.defineProperty(l,"selectedIndex",{get:function(){return l.selectedIndex_}}),Object.defineProperty(l,"length",{get:function(){return l.levels_.length}}),l||n(i)}l=r,(i=o).prototype=Object.create(l.prototype),i.prototype.constructor=i,i.__proto__=l;var s=o.prototype;return s.addQualityLevel=function(n){var r=this.getQualityLevelById(n.id);if(r)return r;var i=this.levels_.length;return r=new function n(r){var i=this;if(e.browser.IS_IE8)for(var l in i=t.createElement("custom"),n.prototype)"constructor"!==l&&(i[l]=n.prototype[l]);return i.id=r.id,i.label=i.id,i.width=r.width,i.height=r.height,i.bitrate=r.bandwidth,i.enabled_=r.enabled,Object.defineProperty(i,"enabled",{get:function(){return i.enabled_()},set:function(e){i.enabled_(e)}}),i}(n),""+i in this||Object.defineProperty(this,i,{get:function(){return this.levels_[i]}}),this.levels_.push(r),this.trigger({qualityLevel:r,type:"addqualitylevel"}),r},s.removeQualityLevel=function(e){for(var t=null,n=0,r=this.length;n<r;n++)if(this[n]===e){t=this.levels_.splice(n,1)[0],this.selectedIndex_===n?this.selectedIndex_=-1:this.selectedIndex_>n&&this.selectedIndex_--;break}return t&&this.trigger({qualityLevel:e,type:"removequalitylevel"}),t},s.getQualityLevelById=function(e){for(var t=0,n=this.length;t<n;t++){var r=this[t];if(r.id===e)return r}return null},s.dispose=function(){this.selectedIndex_=-1,this.levels_.length=0},o}(e.EventTarget);for(var i in r.prototype.allowedEvents_={change:"change",addqualitylevel:"addqualitylevel",removequalitylevel:"removequalitylevel"},r.prototype.allowedEvents_)r.prototype["on"+i]=null;var l=function(t){return n=this,e.mergeOptions({},t),i=n.qualityLevels,l=new r,n.on("dispose",function e(){l.dispose(),n.qualityLevels=i,n.off("dispose",e)}),n.qualityLevels=function(){return l},n.qualityLevels.VERSION="2.0.9",l;var n,i,l};return(e.registerPlugin||e.plugin)("qualityLevels",l),l.VERSION="2.0.9",l});
|
@ -0,0 +1,7 @@
|
|||||||
|
/**
|
||||||
|
* videojs-hls-quality-selector
|
||||||
|
* @version 1.0.4
|
||||||
|
* @copyright 2019 Chris Boustead (chris@forgemotion.com)
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
.video-js.vjs-hls-quality-selector{display:block}
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,456 @@
|
|||||||
|
/*! @name videojs-trimming-controls @version 0.0.0 @license MIT */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
|
||||||
|
|
||||||
|
var videojs = _interopDefault(require('video.js'));
|
||||||
|
|
||||||
|
function _inheritsLoose(subClass, superClass) {
|
||||||
|
subClass.prototype = Object.create(superClass.prototype);
|
||||||
|
subClass.prototype.constructor = subClass;
|
||||||
|
subClass.__proto__ = superClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
var version = "0.0.0";
|
||||||
|
|
||||||
|
var Plugin = videojs.getPlugin('plugin'); // Default options for the plugin.
|
||||||
|
|
||||||
|
var defaults = {
|
||||||
|
startTrim: 60,
|
||||||
|
endTrim: 120,
|
||||||
|
limitPlayback: false
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* An advanced Video.js plugin. For more information on the API
|
||||||
|
*
|
||||||
|
* See: https://blog.videojs.com/feature-spotlight-advanced-plugins/
|
||||||
|
*/
|
||||||
|
|
||||||
|
var TrimmingControls =
|
||||||
|
/*#__PURE__*/
|
||||||
|
function (_Plugin) {
|
||||||
|
_inheritsLoose(TrimmingControls, _Plugin);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a TrimmingControls plugin instance.
|
||||||
|
*
|
||||||
|
* @param {Player} player
|
||||||
|
* A Video.js Player instance.
|
||||||
|
*
|
||||||
|
* @param {Object} [options]
|
||||||
|
* An optional options object.
|
||||||
|
*
|
||||||
|
* While not a core part of the Video.js plugin architecture, a
|
||||||
|
* second argument of options is a convenient way to accept inputs
|
||||||
|
* from your plugin's caller.
|
||||||
|
*/
|
||||||
|
function TrimmingControls(player, options) {
|
||||||
|
var _this;
|
||||||
|
|
||||||
|
// the parent class will add player under this.player
|
||||||
|
_this = _Plugin.call(this, player) || this;
|
||||||
|
_this.options = videojs.mergeOptions(defaults, options);
|
||||||
|
|
||||||
|
_this.createTrimmingControls();
|
||||||
|
|
||||||
|
player.ready(function () {
|
||||||
|
setTimeout(function () {
|
||||||
|
_this.updateTrimTimes(_this.options.startTrim, _this.options.endTrim);
|
||||||
|
}, 100);
|
||||||
|
player.on("timeupdate", function () {
|
||||||
|
if (_this.options.limitPlayback && _this.player.currentTime() >= _this.options.endTrim) {
|
||||||
|
_this.player.currentTime(_this.options.endTrim);
|
||||||
|
|
||||||
|
_this.player.pause();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
player.on('playing', function () {
|
||||||
|
videojs.log('playback began!');
|
||||||
|
|
||||||
|
_this.updateTrimTimes(_this.options.startTrim, _this.options.endTrim);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _proto = TrimmingControls.prototype;
|
||||||
|
|
||||||
|
_proto.createTrimmingControls = function createTrimmingControls() {
|
||||||
|
var player = this.player;
|
||||||
|
var videoJsComponentClass = videojs.getComponent('Component');
|
||||||
|
/**
|
||||||
|
* Extend vjs button class for quality button.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var TrimControlBarClass =
|
||||||
|
/*#__PURE__*/
|
||||||
|
function (_videoJsComponentClas) {
|
||||||
|
_inheritsLoose(TrimControlBarClass, _videoJsComponentClas);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component constructor.
|
||||||
|
*/
|
||||||
|
function TrimControlBarClass() {
|
||||||
|
return _videoJsComponentClas.call(this, player, {
|
||||||
|
title: player.localize('Trimming Controls')
|
||||||
|
}) || this;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _proto2 = TrimControlBarClass.prototype;
|
||||||
|
|
||||||
|
_proto2.createEl = function createEl() {
|
||||||
|
return videojs.dom.createEl('div', {
|
||||||
|
// Prefixing classes of elements within a player with "vjs-" is a convention used in Video.js.
|
||||||
|
className: 'vjs-control-bar vjs-trimming-controls',
|
||||||
|
dir: 'ltr'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return TrimControlBarClass;
|
||||||
|
}(videoJsComponentClass);
|
||||||
|
|
||||||
|
var videoJSSpacerClass = videojs.getComponent('Spacer');
|
||||||
|
var videoJSButtonClass = videojs.getComponent('Button');
|
||||||
|
|
||||||
|
var GoToButtonClass =
|
||||||
|
/*#__PURE__*/
|
||||||
|
function (_videoJSButtonClass) {
|
||||||
|
_inheritsLoose(GoToButtonClass, _videoJSButtonClass);
|
||||||
|
|
||||||
|
function GoToButtonClass(_plugin, _targetPosition, _text) {
|
||||||
|
var _this2;
|
||||||
|
|
||||||
|
_this2 = _videoJSButtonClass.call(this, player, {// title: player.localize('Trim Button'),
|
||||||
|
// label: "Trim Here"
|
||||||
|
}) || this;
|
||||||
|
_this2.trimmingControls = _plugin;
|
||||||
|
_this2.targetPosition = _targetPosition;
|
||||||
|
|
||||||
|
_this2.controlText(_text);
|
||||||
|
|
||||||
|
_this2.el().getElementsByClassName('vjs-icon-placeholder')[0].classList += " material-icons";
|
||||||
|
return _this2;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _proto3 = GoToButtonClass.prototype;
|
||||||
|
|
||||||
|
_proto3.handleClick = function handleClick() {
|
||||||
|
if (this.targetPosition == 0) {
|
||||||
|
this.player().currentTime(this.trimmingControls.options.startTrim);
|
||||||
|
} else if (this.targetPosition == 1) {
|
||||||
|
this.player().currentTime(this.trimmingControls.options.endTrim);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return GoToButtonClass;
|
||||||
|
}(videoJSButtonClass);
|
||||||
|
|
||||||
|
var TrimButtonClass =
|
||||||
|
/*#__PURE__*/
|
||||||
|
function (_videoJSButtonClass2) {
|
||||||
|
_inheritsLoose(TrimButtonClass, _videoJSButtonClass2);
|
||||||
|
|
||||||
|
function TrimButtonClass(_plugin, _targetPosition, _text) {
|
||||||
|
var _this3;
|
||||||
|
|
||||||
|
_this3 = _videoJSButtonClass2.call(this, player, {// title: player.localize('Trim Button'),
|
||||||
|
// label: "Trim Here"
|
||||||
|
}) || this;
|
||||||
|
_this3.trimmingControls = _plugin;
|
||||||
|
_this3.targetPosition = _targetPosition;
|
||||||
|
|
||||||
|
_this3.controlText(_text);
|
||||||
|
|
||||||
|
_this3.el().getElementsByClassName('vjs-icon-placeholder')[0].classList += " material-icons";
|
||||||
|
return _this3;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _proto4 = TrimButtonClass.prototype;
|
||||||
|
|
||||||
|
_proto4.handleClick = function handleClick() {
|
||||||
|
if (this.targetPosition == 0) {
|
||||||
|
this.trimmingControls.updateTrimTimes(this.player().currentTime(), this.trimmingControls.options.endTrim);
|
||||||
|
} else if (this.targetPosition == 1) {
|
||||||
|
this.trimmingControls.updateTrimTimes(this.trimmingControls.options.startTrim, this.player().currentTime());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return TrimButtonClass;
|
||||||
|
}(videoJSButtonClass);
|
||||||
|
|
||||||
|
var TrimTimeDisplayClass =
|
||||||
|
/*#__PURE__*/
|
||||||
|
function (_videoJsComponentClas2) {
|
||||||
|
_inheritsLoose(TrimTimeDisplayClass, _videoJsComponentClas2);
|
||||||
|
|
||||||
|
function TrimTimeDisplayClass(_defaultTime) {
|
||||||
|
var _this4;
|
||||||
|
|
||||||
|
_this4 = _videoJsComponentClas2.call(this, player, {}) || this;
|
||||||
|
|
||||||
|
_this4.updateTimeContent(_defaultTime);
|
||||||
|
|
||||||
|
return _this4;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _proto5 = TrimTimeDisplayClass.prototype;
|
||||||
|
|
||||||
|
_proto5.createEl = function createEl() {
|
||||||
|
return videojs.dom.createEl('input', {
|
||||||
|
// Prefixing classes of elements within a player with "vjs-" is a convention used in Video.js.
|
||||||
|
className: 'vjs-time-display'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
_proto5.updateTimeContent = function updateTimeContent(timeInSeconds) {
|
||||||
|
videojs.dom.emptyEl(this.el()); //this.controlText(videojs.formatTime(timeInSeconds, 600))
|
||||||
|
//videojs.dom.appendContent(this.el(), videojs.formatTime(timeInSeconds, 600));
|
||||||
|
//videojs.dom.textContent(this.el(), videojs.formatTime(timeInSeconds, 600));
|
||||||
|
|
||||||
|
this.el().value = videojs.formatTime(timeInSeconds, 600.01);
|
||||||
|
};
|
||||||
|
|
||||||
|
return TrimTimeDisplayClass;
|
||||||
|
}(videoJsComponentClass);
|
||||||
|
|
||||||
|
var FrameButtonClass =
|
||||||
|
/*#__PURE__*/
|
||||||
|
function (_videoJSButtonClass3) {
|
||||||
|
_inheritsLoose(FrameButtonClass, _videoJSButtonClass3);
|
||||||
|
|
||||||
|
function FrameButtonClass(_plugin, _targetPosition, _text) {
|
||||||
|
var _this5;
|
||||||
|
|
||||||
|
_this5 = _videoJSButtonClass3.call(this, player, {// title: player.localize('Trim Button'),
|
||||||
|
// label: "Trim Here"
|
||||||
|
}) || this;
|
||||||
|
_this5.trimmingControls = _plugin;
|
||||||
|
_this5.targetPosition = _targetPosition;
|
||||||
|
|
||||||
|
_this5.controlText(_text);
|
||||||
|
|
||||||
|
_this5.el().getElementsByClassName('vjs-icon-placeholder')[0].classList += " material-icons";
|
||||||
|
return _this5;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _proto6 = FrameButtonClass.prototype;
|
||||||
|
|
||||||
|
_proto6.handleClick = function handleClick() {
|
||||||
|
if (this.targetPosition == 0) {
|
||||||
|
this.player().currentTime(this.player().currentTime() - 0.1);
|
||||||
|
} else if (this.targetPosition == 1) {
|
||||||
|
this.player().currentTime(this.player().currentTime() + 0.1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return FrameButtonClass;
|
||||||
|
}(videoJSButtonClass);
|
||||||
|
|
||||||
|
var videoJSPlayToggleClass = videojs.getComponent('PlayToggle');
|
||||||
|
|
||||||
|
var playbackEndToggleClass =
|
||||||
|
/*#__PURE__*/
|
||||||
|
function (_videoJSButtonClass4) {
|
||||||
|
_inheritsLoose(playbackEndToggleClass, _videoJSButtonClass4);
|
||||||
|
|
||||||
|
function playbackEndToggleClass(_plugin, _text) {
|
||||||
|
var _this6;
|
||||||
|
|
||||||
|
_this6 = _videoJSButtonClass4.call(this, player, {// title: player.localize('Trim Button'),
|
||||||
|
// label: "Trim Here"
|
||||||
|
}) || this;
|
||||||
|
_this6.trimmingControls = _plugin;
|
||||||
|
|
||||||
|
_this6.controlText(_text);
|
||||||
|
|
||||||
|
_this6.el().getElementsByClassName('vjs-icon-placeholder')[0].classList += " material-icons";
|
||||||
|
return _this6;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _proto7 = playbackEndToggleClass.prototype;
|
||||||
|
|
||||||
|
_proto7.handleClick = function handleClick() {
|
||||||
|
this.trimmingControls.options.limitPlayback = !this.trimmingControls.options.limitPlayback;
|
||||||
|
this.toggleClass('playbackLimited');
|
||||||
|
};
|
||||||
|
|
||||||
|
return playbackEndToggleClass;
|
||||||
|
}(videoJSButtonClass); //Creating Trimming Seek Bar
|
||||||
|
|
||||||
|
|
||||||
|
this._trimSeekControlBar = new TrimControlBarClass();
|
||||||
|
var trimSeekControlBarInstance = player.addChild(this._trimSeekControlBar, {
|
||||||
|
componentClass: 'trimControlBar'
|
||||||
|
}, player.children().length);
|
||||||
|
trimSeekControlBarInstance.addClass('vljs-trim-seek');
|
||||||
|
trimSeekControlBarInstance.el().innerHTML = '<div id="trimBarPlaceholderContainer"><div id="trimBarPlaceholder"></div></div>'; // //Spacer
|
||||||
|
// this._spacer1 = new videoJSSpacerClass();
|
||||||
|
// const spacer1Instance = this._trimSeekControlBar.addChild(this._spacer1, {componentClass: 'spacer'}, 0);
|
||||||
|
// spacer1Instance.setAttribute("style", "flex: 0 0 158px");
|
||||||
|
// //Spacer
|
||||||
|
// this._spacer1 = new videoJSSpacerClass();
|
||||||
|
// const spacer2Instance = this._trimSeekControlBar.addChild(this._spacer1, {componentClass: 'spacer'}, 2);
|
||||||
|
// spacer2Instance.setAttribute("style", "flex: 0 0 178px");
|
||||||
|
//Creating Trimming Controls Bar
|
||||||
|
|
||||||
|
this._trimControlBar = new TrimControlBarClass();
|
||||||
|
var trimControlBarInstance = player.addChild(this._trimControlBar, {
|
||||||
|
componentClass: 'trimControlBar'
|
||||||
|
}, player.children().length);
|
||||||
|
trimControlBarInstance.addClass('vljs-trim-buttons'); //Trim Bar Controls order: spacer,GoTo,Time,SetPlayhead,frameadjust,playpause,frameAdjust,setPlayhead,time,GoTo, endplayback
|
||||||
|
//Spacer for balance
|
||||||
|
|
||||||
|
this._spacer = new videoJSSpacerClass();
|
||||||
|
|
||||||
|
var spacerInstance = this._trimControlBar.addChild(this._spacer, {
|
||||||
|
componentClass: 'spacer'
|
||||||
|
}, 0); //Go To start of Trim
|
||||||
|
|
||||||
|
|
||||||
|
this._startGoToButton = new GoToButtonClass(this, 0, "Go to start of trim segment");
|
||||||
|
|
||||||
|
var startGoToButtonInstance = this._trimControlBar.addChild(this._startGoToButton, {
|
||||||
|
componentClass: 'goToButton'
|
||||||
|
}, 5);
|
||||||
|
|
||||||
|
startGoToButtonInstance.addClass('vljs-trimming-button');
|
||||||
|
startGoToButtonInstance.el().getElementsByClassName('vjs-icon-placeholder')[0].innerText = "skip_previous"; //Create trim start time display
|
||||||
|
|
||||||
|
this._startTrimTimeDisplay = new TrimTimeDisplayClass(this.options.startTrim);
|
||||||
|
|
||||||
|
var startTrimTimeDisplayInstance = this._trimControlBar.addChild(this._startTrimTimeDisplay, {
|
||||||
|
componentClass: 'trimTimeDisplay'
|
||||||
|
}, 10);
|
||||||
|
|
||||||
|
startTrimTimeDisplayInstance.on("change", function () {
|
||||||
|
this.player_.trimmingControls().setTimestamps(startTrimTimeDisplayInstance.el().value, 0);
|
||||||
|
}); //Create set start at playhead button
|
||||||
|
|
||||||
|
this._startTrimButton = new TrimButtonClass(this, 0, "Set trim start at playhead");
|
||||||
|
|
||||||
|
var startTrimButtonInstance = this._trimControlBar.addChild(this._startTrimButton, {
|
||||||
|
componentClass: 'trimButton'
|
||||||
|
}, 20);
|
||||||
|
|
||||||
|
startTrimButtonInstance.addClass('vljs-trimming-button');
|
||||||
|
startTrimButtonInstance.el().getElementsByClassName('vjs-icon-placeholder')[0].innerText = "edit"; //Create Frame Back Button
|
||||||
|
|
||||||
|
this._frameBackButton = new FrameButtonClass(this, 0, "Move back 1 frame");
|
||||||
|
|
||||||
|
var frameBackButtonInstance = this._trimControlBar.addChild(this._frameBackButton, {
|
||||||
|
componentClass: 'frameButton'
|
||||||
|
}, 22);
|
||||||
|
|
||||||
|
frameBackButtonInstance.addClass('vljs-trimming-button');
|
||||||
|
frameBackButtonInstance.el().getElementsByClassName('vjs-icon-placeholder')[0].innerText = "fast_rewind"; //Create Play/Pause Button
|
||||||
|
|
||||||
|
this._playPauseButton = new videoJSPlayToggleClass(this.player);
|
||||||
|
|
||||||
|
var playPauseButtonInstance = this._trimControlBar.addChild(this._playPauseButton, {
|
||||||
|
componentClass: 'playPauseButton'
|
||||||
|
}, 25); //Create Frame Forward Button
|
||||||
|
|
||||||
|
|
||||||
|
this._frameForwardButton = new FrameButtonClass(this, 1, "Move forward 1 frame");
|
||||||
|
|
||||||
|
var frameForwardButtonInstance = this._trimControlBar.addChild(this._frameForwardButton, {
|
||||||
|
componentClass: 'frameButton'
|
||||||
|
}, 27);
|
||||||
|
|
||||||
|
frameForwardButtonInstance.addClass('vljs-trimming-button');
|
||||||
|
frameForwardButtonInstance.el().getElementsByClassName('vjs-icon-placeholder')[0].innerText = "fast_forward"; //Create set end at playhead button
|
||||||
|
|
||||||
|
this._endTrimButton = new TrimButtonClass(this, 1, "Set trim end at playhead");
|
||||||
|
|
||||||
|
var endTrimButtonInstance = this._trimControlBar.addChild(this._endTrimButton, {
|
||||||
|
componentClass: 'trimButton'
|
||||||
|
}, 30);
|
||||||
|
|
||||||
|
endTrimButtonInstance.addClass('vljs-trimming-button');
|
||||||
|
endTrimButtonInstance.el().getElementsByClassName('vjs-icon-placeholder')[0].innerText = "edit"; //Create trim end time display
|
||||||
|
|
||||||
|
this._endTrimTimeDisplay = new TrimTimeDisplayClass(this.options.endTrim);
|
||||||
|
|
||||||
|
var endTrimTimeDisplayInstance = this._trimControlBar.addChild(this._endTrimTimeDisplay, {
|
||||||
|
componentClass: 'trimTimeDisplay'
|
||||||
|
}, 40);
|
||||||
|
|
||||||
|
endTrimTimeDisplayInstance.on("change", function () {
|
||||||
|
this.player_.trimmingControls().setTimestamps(endTrimTimeDisplayInstance.el().value, 1);
|
||||||
|
}); //Go To end of Trim
|
||||||
|
|
||||||
|
this._endGoToButton = new GoToButtonClass(this, 1, "Go to end of trim segment");
|
||||||
|
|
||||||
|
var endGoToButtonInstance = this._trimControlBar.addChild(this._endGoToButton, {
|
||||||
|
componentClass: 'goToButton'
|
||||||
|
}, 50);
|
||||||
|
|
||||||
|
endGoToButtonInstance.addClass('vljs-trimming-button');
|
||||||
|
endGoToButtonInstance.el().getElementsByClassName('vjs-icon-placeholder')[0].innerText = "skip_next"; //End playback at trim endpoint
|
||||||
|
|
||||||
|
this._playbackEndToggle = new playbackEndToggleClass(this, "End playback at trim endpoint");
|
||||||
|
|
||||||
|
var playbackEndToggleInstance = this._trimControlBar.addChild(this._playbackEndToggle, {
|
||||||
|
componentClass: 'playbackEndToggle'
|
||||||
|
}, 60);
|
||||||
|
|
||||||
|
playbackEndToggleInstance.addClass('vljs-trimming-button');
|
||||||
|
playbackEndToggleInstance.el().getElementsByClassName('vjs-icon-placeholder')[0].innerText = "stop";
|
||||||
|
};
|
||||||
|
|
||||||
|
_proto.updateTrimTimes = function updateTrimTimes(startValue, endValue) {
|
||||||
|
//Update stored values
|
||||||
|
this.options.startTrim = startValue;
|
||||||
|
this.options.endTrim = endValue; //Update timestamp displays
|
||||||
|
|
||||||
|
this._startTrimTimeDisplay.updateTimeContent(startValue);
|
||||||
|
|
||||||
|
this._endTrimTimeDisplay.updateTimeContent(endValue); //Update slider
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById("trimBarPlaceholder").style["marginLeft"] = startValue / this.player.duration() * 100 + "%";
|
||||||
|
document.getElementById("trimBarPlaceholder").style["marginRight"] = 100 - endValue / this.player.duration() * 100 + "%";
|
||||||
|
};
|
||||||
|
|
||||||
|
_proto.setTimestamps = function setTimestamps(value, index) {
|
||||||
|
if (/^\d*:?\d*:?\d*\.?\d*$/.test(value)) {
|
||||||
|
if (index === 0) {
|
||||||
|
this.updateTrimTimes(this.getSeconds(value), this.options.endTrim);
|
||||||
|
} else if (index === 1) {
|
||||||
|
this.updateTrimTimes(this.options.startTrim, this.getSeconds(value));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this._startTrimTimeDisplay.updateTimeContent(startValue);
|
||||||
|
|
||||||
|
this._endTrimTimeDisplay.updateTimeContent(endValue);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_proto.getSeconds = function getSeconds(time) {
|
||||||
|
var timeArr = time.split(':'),
|
||||||
|
//Array of hours, minutes, and seconds.
|
||||||
|
s = 0,
|
||||||
|
//Seconds total
|
||||||
|
m = 1; //Multiplier
|
||||||
|
|
||||||
|
while (timeArr.length > 0) {
|
||||||
|
//Iterate through time segments starting from the seconds,
|
||||||
|
s += m * timeArr.pop(); //multiply as appropriate, and add to seconds total,
|
||||||
|
|
||||||
|
m *= 60; //increase multiplier.
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
};
|
||||||
|
|
||||||
|
return TrimmingControls;
|
||||||
|
}(Plugin); // Define default values for the plugin's `state` object here.
|
||||||
|
|
||||||
|
|
||||||
|
TrimmingControls.defaultState = {}; // Include the version number.
|
||||||
|
|
||||||
|
TrimmingControls.VERSION = version; // Register the plugin with video.js.
|
||||||
|
|
||||||
|
videojs.registerPlugin('trimmingControls', TrimmingControls);
|
||||||
|
|
||||||
|
module.exports = TrimmingControls;
|
@ -0,0 +1 @@
|
|||||||
|
.video-js .vjs-control-bar{bottom:-3em;padding-top:3px}.video-js .vjs-progress-control.vjs-control{position:absolute;width:100%;margin-top:-16px}.video-js .vjs-current-time.vjs-time-control.vjs-control{flex:auto;text-align:right}.video-js .vjs-duration.vjs-time-control.vjs-control{flex:auto;text-align:left}.video-js .vjs-control-bar.vjs-trimming-controls.vljs-trim-seek{bottom:-6em;padding-top:0px}.video-js #trimBarPlaceholderContainer{background-color:rgba(115,133,159,0.5);margin-top:5px;margin-left:10px;margin-right:10px;height:3px;width:100%}.video-js #trimBarPlaceholder{background-color:darkorange;height:3px}.video-js .vjs-control-bar.vjs-trimming-controls.vljs-trim-buttons{bottom:-9em;padding-top:0px;justify-content:space-evenly}.video-js .vjs-time-display{width:50px;height:27px;text-align:center}.video-js .vljs-trimming-button .vjs-icon-placeholder{cursor:pointer}.video-js .playbackLimited{color:darkred}
|
@ -0,0 +1,452 @@
|
|||||||
|
/*! @name videojs-trimming-controls @version 0.0.0 @license MIT */
|
||||||
|
import videojs from 'video.js';
|
||||||
|
|
||||||
|
function _inheritsLoose(subClass, superClass) {
|
||||||
|
subClass.prototype = Object.create(superClass.prototype);
|
||||||
|
subClass.prototype.constructor = subClass;
|
||||||
|
subClass.__proto__ = superClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
var version = "0.0.0";
|
||||||
|
|
||||||
|
var Plugin = videojs.getPlugin('plugin'); // Default options for the plugin.
|
||||||
|
|
||||||
|
var defaults = {
|
||||||
|
startTrim: 60,
|
||||||
|
endTrim: 120,
|
||||||
|
limitPlayback: false
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* An advanced Video.js plugin. For more information on the API
|
||||||
|
*
|
||||||
|
* See: https://blog.videojs.com/feature-spotlight-advanced-plugins/
|
||||||
|
*/
|
||||||
|
|
||||||
|
var TrimmingControls =
|
||||||
|
/*#__PURE__*/
|
||||||
|
function (_Plugin) {
|
||||||
|
_inheritsLoose(TrimmingControls, _Plugin);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a TrimmingControls plugin instance.
|
||||||
|
*
|
||||||
|
* @param {Player} player
|
||||||
|
* A Video.js Player instance.
|
||||||
|
*
|
||||||
|
* @param {Object} [options]
|
||||||
|
* An optional options object.
|
||||||
|
*
|
||||||
|
* While not a core part of the Video.js plugin architecture, a
|
||||||
|
* second argument of options is a convenient way to accept inputs
|
||||||
|
* from your plugin's caller.
|
||||||
|
*/
|
||||||
|
function TrimmingControls(player, options) {
|
||||||
|
var _this;
|
||||||
|
|
||||||
|
// the parent class will add player under this.player
|
||||||
|
_this = _Plugin.call(this, player) || this;
|
||||||
|
_this.options = videojs.mergeOptions(defaults, options);
|
||||||
|
|
||||||
|
_this.createTrimmingControls();
|
||||||
|
|
||||||
|
player.ready(function () {
|
||||||
|
setTimeout(function () {
|
||||||
|
_this.updateTrimTimes(_this.options.startTrim, _this.options.endTrim);
|
||||||
|
}, 100);
|
||||||
|
player.on("timeupdate", function () {
|
||||||
|
if (_this.options.limitPlayback && _this.player.currentTime() >= _this.options.endTrim) {
|
||||||
|
_this.player.currentTime(_this.options.endTrim);
|
||||||
|
|
||||||
|
_this.player.pause();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
player.on('playing', function () {
|
||||||
|
videojs.log('playback began!');
|
||||||
|
|
||||||
|
_this.updateTrimTimes(_this.options.startTrim, _this.options.endTrim);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _proto = TrimmingControls.prototype;
|
||||||
|
|
||||||
|
_proto.createTrimmingControls = function createTrimmingControls() {
|
||||||
|
var player = this.player;
|
||||||
|
var videoJsComponentClass = videojs.getComponent('Component');
|
||||||
|
/**
|
||||||
|
* Extend vjs button class for quality button.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var TrimControlBarClass =
|
||||||
|
/*#__PURE__*/
|
||||||
|
function (_videoJsComponentClas) {
|
||||||
|
_inheritsLoose(TrimControlBarClass, _videoJsComponentClas);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component constructor.
|
||||||
|
*/
|
||||||
|
function TrimControlBarClass() {
|
||||||
|
return _videoJsComponentClas.call(this, player, {
|
||||||
|
title: player.localize('Trimming Controls')
|
||||||
|
}) || this;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _proto2 = TrimControlBarClass.prototype;
|
||||||
|
|
||||||
|
_proto2.createEl = function createEl() {
|
||||||
|
return videojs.dom.createEl('div', {
|
||||||
|
// Prefixing classes of elements within a player with "vjs-" is a convention used in Video.js.
|
||||||
|
className: 'vjs-control-bar vjs-trimming-controls',
|
||||||
|
dir: 'ltr'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return TrimControlBarClass;
|
||||||
|
}(videoJsComponentClass);
|
||||||
|
|
||||||
|
var videoJSSpacerClass = videojs.getComponent('Spacer');
|
||||||
|
var videoJSButtonClass = videojs.getComponent('Button');
|
||||||
|
|
||||||
|
var GoToButtonClass =
|
||||||
|
/*#__PURE__*/
|
||||||
|
function (_videoJSButtonClass) {
|
||||||
|
_inheritsLoose(GoToButtonClass, _videoJSButtonClass);
|
||||||
|
|
||||||
|
function GoToButtonClass(_plugin, _targetPosition, _text) {
|
||||||
|
var _this2;
|
||||||
|
|
||||||
|
_this2 = _videoJSButtonClass.call(this, player, {// title: player.localize('Trim Button'),
|
||||||
|
// label: "Trim Here"
|
||||||
|
}) || this;
|
||||||
|
_this2.trimmingControls = _plugin;
|
||||||
|
_this2.targetPosition = _targetPosition;
|
||||||
|
|
||||||
|
_this2.controlText(_text);
|
||||||
|
|
||||||
|
_this2.el().getElementsByClassName('vjs-icon-placeholder')[0].classList += " material-icons";
|
||||||
|
return _this2;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _proto3 = GoToButtonClass.prototype;
|
||||||
|
|
||||||
|
_proto3.handleClick = function handleClick() {
|
||||||
|
if (this.targetPosition == 0) {
|
||||||
|
this.player().currentTime(this.trimmingControls.options.startTrim);
|
||||||
|
} else if (this.targetPosition == 1) {
|
||||||
|
this.player().currentTime(this.trimmingControls.options.endTrim);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return GoToButtonClass;
|
||||||
|
}(videoJSButtonClass);
|
||||||
|
|
||||||
|
var TrimButtonClass =
|
||||||
|
/*#__PURE__*/
|
||||||
|
function (_videoJSButtonClass2) {
|
||||||
|
_inheritsLoose(TrimButtonClass, _videoJSButtonClass2);
|
||||||
|
|
||||||
|
function TrimButtonClass(_plugin, _targetPosition, _text) {
|
||||||
|
var _this3;
|
||||||
|
|
||||||
|
_this3 = _videoJSButtonClass2.call(this, player, {// title: player.localize('Trim Button'),
|
||||||
|
// label: "Trim Here"
|
||||||
|
}) || this;
|
||||||
|
_this3.trimmingControls = _plugin;
|
||||||
|
_this3.targetPosition = _targetPosition;
|
||||||
|
|
||||||
|
_this3.controlText(_text);
|
||||||
|
|
||||||
|
_this3.el().getElementsByClassName('vjs-icon-placeholder')[0].classList += " material-icons";
|
||||||
|
return _this3;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _proto4 = TrimButtonClass.prototype;
|
||||||
|
|
||||||
|
_proto4.handleClick = function handleClick() {
|
||||||
|
if (this.targetPosition == 0) {
|
||||||
|
this.trimmingControls.updateTrimTimes(this.player().currentTime(), this.trimmingControls.options.endTrim);
|
||||||
|
} else if (this.targetPosition == 1) {
|
||||||
|
this.trimmingControls.updateTrimTimes(this.trimmingControls.options.startTrim, this.player().currentTime());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return TrimButtonClass;
|
||||||
|
}(videoJSButtonClass);
|
||||||
|
|
||||||
|
var TrimTimeDisplayClass =
|
||||||
|
/*#__PURE__*/
|
||||||
|
function (_videoJsComponentClas2) {
|
||||||
|
_inheritsLoose(TrimTimeDisplayClass, _videoJsComponentClas2);
|
||||||
|
|
||||||
|
function TrimTimeDisplayClass(_defaultTime) {
|
||||||
|
var _this4;
|
||||||
|
|
||||||
|
_this4 = _videoJsComponentClas2.call(this, player, {}) || this;
|
||||||
|
|
||||||
|
_this4.updateTimeContent(_defaultTime);
|
||||||
|
|
||||||
|
return _this4;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _proto5 = TrimTimeDisplayClass.prototype;
|
||||||
|
|
||||||
|
_proto5.createEl = function createEl() {
|
||||||
|
return videojs.dom.createEl('input', {
|
||||||
|
// Prefixing classes of elements within a player with "vjs-" is a convention used in Video.js.
|
||||||
|
className: 'vjs-time-display'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
_proto5.updateTimeContent = function updateTimeContent(timeInSeconds) {
|
||||||
|
videojs.dom.emptyEl(this.el()); //this.controlText(videojs.formatTime(timeInSeconds, 600))
|
||||||
|
//videojs.dom.appendContent(this.el(), videojs.formatTime(timeInSeconds, 600));
|
||||||
|
//videojs.dom.textContent(this.el(), videojs.formatTime(timeInSeconds, 600));
|
||||||
|
|
||||||
|
this.el().value = videojs.formatTime(timeInSeconds, 600.01);
|
||||||
|
};
|
||||||
|
|
||||||
|
return TrimTimeDisplayClass;
|
||||||
|
}(videoJsComponentClass);
|
||||||
|
|
||||||
|
var FrameButtonClass =
|
||||||
|
/*#__PURE__*/
|
||||||
|
function (_videoJSButtonClass3) {
|
||||||
|
_inheritsLoose(FrameButtonClass, _videoJSButtonClass3);
|
||||||
|
|
||||||
|
function FrameButtonClass(_plugin, _targetPosition, _text) {
|
||||||
|
var _this5;
|
||||||
|
|
||||||
|
_this5 = _videoJSButtonClass3.call(this, player, {// title: player.localize('Trim Button'),
|
||||||
|
// label: "Trim Here"
|
||||||
|
}) || this;
|
||||||
|
_this5.trimmingControls = _plugin;
|
||||||
|
_this5.targetPosition = _targetPosition;
|
||||||
|
|
||||||
|
_this5.controlText(_text);
|
||||||
|
|
||||||
|
_this5.el().getElementsByClassName('vjs-icon-placeholder')[0].classList += " material-icons";
|
||||||
|
return _this5;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _proto6 = FrameButtonClass.prototype;
|
||||||
|
|
||||||
|
_proto6.handleClick = function handleClick() {
|
||||||
|
if (this.targetPosition == 0) {
|
||||||
|
this.player().currentTime(this.player().currentTime() - 0.1);
|
||||||
|
} else if (this.targetPosition == 1) {
|
||||||
|
this.player().currentTime(this.player().currentTime() + 0.1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return FrameButtonClass;
|
||||||
|
}(videoJSButtonClass);
|
||||||
|
|
||||||
|
var videoJSPlayToggleClass = videojs.getComponent('PlayToggle');
|
||||||
|
|
||||||
|
var playbackEndToggleClass =
|
||||||
|
/*#__PURE__*/
|
||||||
|
function (_videoJSButtonClass4) {
|
||||||
|
_inheritsLoose(playbackEndToggleClass, _videoJSButtonClass4);
|
||||||
|
|
||||||
|
function playbackEndToggleClass(_plugin, _text) {
|
||||||
|
var _this6;
|
||||||
|
|
||||||
|
_this6 = _videoJSButtonClass4.call(this, player, {// title: player.localize('Trim Button'),
|
||||||
|
// label: "Trim Here"
|
||||||
|
}) || this;
|
||||||
|
_this6.trimmingControls = _plugin;
|
||||||
|
|
||||||
|
_this6.controlText(_text);
|
||||||
|
|
||||||
|
_this6.el().getElementsByClassName('vjs-icon-placeholder')[0].classList += " material-icons";
|
||||||
|
return _this6;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _proto7 = playbackEndToggleClass.prototype;
|
||||||
|
|
||||||
|
_proto7.handleClick = function handleClick() {
|
||||||
|
this.trimmingControls.options.limitPlayback = !this.trimmingControls.options.limitPlayback;
|
||||||
|
this.toggleClass('playbackLimited');
|
||||||
|
};
|
||||||
|
|
||||||
|
return playbackEndToggleClass;
|
||||||
|
}(videoJSButtonClass); //Creating Trimming Seek Bar
|
||||||
|
|
||||||
|
|
||||||
|
this._trimSeekControlBar = new TrimControlBarClass();
|
||||||
|
var trimSeekControlBarInstance = player.addChild(this._trimSeekControlBar, {
|
||||||
|
componentClass: 'trimControlBar'
|
||||||
|
}, player.children().length);
|
||||||
|
trimSeekControlBarInstance.addClass('vljs-trim-seek');
|
||||||
|
trimSeekControlBarInstance.el().innerHTML = '<div id="trimBarPlaceholderContainer"><div id="trimBarPlaceholder"></div></div>'; // //Spacer
|
||||||
|
// this._spacer1 = new videoJSSpacerClass();
|
||||||
|
// const spacer1Instance = this._trimSeekControlBar.addChild(this._spacer1, {componentClass: 'spacer'}, 0);
|
||||||
|
// spacer1Instance.setAttribute("style", "flex: 0 0 158px");
|
||||||
|
// //Spacer
|
||||||
|
// this._spacer1 = new videoJSSpacerClass();
|
||||||
|
// const spacer2Instance = this._trimSeekControlBar.addChild(this._spacer1, {componentClass: 'spacer'}, 2);
|
||||||
|
// spacer2Instance.setAttribute("style", "flex: 0 0 178px");
|
||||||
|
//Creating Trimming Controls Bar
|
||||||
|
|
||||||
|
this._trimControlBar = new TrimControlBarClass();
|
||||||
|
var trimControlBarInstance = player.addChild(this._trimControlBar, {
|
||||||
|
componentClass: 'trimControlBar'
|
||||||
|
}, player.children().length);
|
||||||
|
trimControlBarInstance.addClass('vljs-trim-buttons'); //Trim Bar Controls order: spacer,GoTo,Time,SetPlayhead,frameadjust,playpause,frameAdjust,setPlayhead,time,GoTo, endplayback
|
||||||
|
//Spacer for balance
|
||||||
|
|
||||||
|
this._spacer = new videoJSSpacerClass();
|
||||||
|
|
||||||
|
var spacerInstance = this._trimControlBar.addChild(this._spacer, {
|
||||||
|
componentClass: 'spacer'
|
||||||
|
}, 0); //Go To start of Trim
|
||||||
|
|
||||||
|
|
||||||
|
this._startGoToButton = new GoToButtonClass(this, 0, "Go to start of trim segment");
|
||||||
|
|
||||||
|
var startGoToButtonInstance = this._trimControlBar.addChild(this._startGoToButton, {
|
||||||
|
componentClass: 'goToButton'
|
||||||
|
}, 5);
|
||||||
|
|
||||||
|
startGoToButtonInstance.addClass('vljs-trimming-button');
|
||||||
|
startGoToButtonInstance.el().getElementsByClassName('vjs-icon-placeholder')[0].innerText = "skip_previous"; //Create trim start time display
|
||||||
|
|
||||||
|
this._startTrimTimeDisplay = new TrimTimeDisplayClass(this.options.startTrim);
|
||||||
|
|
||||||
|
var startTrimTimeDisplayInstance = this._trimControlBar.addChild(this._startTrimTimeDisplay, {
|
||||||
|
componentClass: 'trimTimeDisplay'
|
||||||
|
}, 10);
|
||||||
|
|
||||||
|
startTrimTimeDisplayInstance.on("change", function () {
|
||||||
|
this.player_.trimmingControls().setTimestamps(startTrimTimeDisplayInstance.el().value, 0);
|
||||||
|
}); //Create set start at playhead button
|
||||||
|
|
||||||
|
this._startTrimButton = new TrimButtonClass(this, 0, "Set trim start at playhead");
|
||||||
|
|
||||||
|
var startTrimButtonInstance = this._trimControlBar.addChild(this._startTrimButton, {
|
||||||
|
componentClass: 'trimButton'
|
||||||
|
}, 20);
|
||||||
|
|
||||||
|
startTrimButtonInstance.addClass('vljs-trimming-button');
|
||||||
|
startTrimButtonInstance.el().getElementsByClassName('vjs-icon-placeholder')[0].innerText = "edit"; //Create Frame Back Button
|
||||||
|
|
||||||
|
this._frameBackButton = new FrameButtonClass(this, 0, "Move back 1 frame");
|
||||||
|
|
||||||
|
var frameBackButtonInstance = this._trimControlBar.addChild(this._frameBackButton, {
|
||||||
|
componentClass: 'frameButton'
|
||||||
|
}, 22);
|
||||||
|
|
||||||
|
frameBackButtonInstance.addClass('vljs-trimming-button');
|
||||||
|
frameBackButtonInstance.el().getElementsByClassName('vjs-icon-placeholder')[0].innerText = "fast_rewind"; //Create Play/Pause Button
|
||||||
|
|
||||||
|
this._playPauseButton = new videoJSPlayToggleClass(this.player);
|
||||||
|
|
||||||
|
var playPauseButtonInstance = this._trimControlBar.addChild(this._playPauseButton, {
|
||||||
|
componentClass: 'playPauseButton'
|
||||||
|
}, 25); //Create Frame Forward Button
|
||||||
|
|
||||||
|
|
||||||
|
this._frameForwardButton = new FrameButtonClass(this, 1, "Move forward 1 frame");
|
||||||
|
|
||||||
|
var frameForwardButtonInstance = this._trimControlBar.addChild(this._frameForwardButton, {
|
||||||
|
componentClass: 'frameButton'
|
||||||
|
}, 27);
|
||||||
|
|
||||||
|
frameForwardButtonInstance.addClass('vljs-trimming-button');
|
||||||
|
frameForwardButtonInstance.el().getElementsByClassName('vjs-icon-placeholder')[0].innerText = "fast_forward"; //Create set end at playhead button
|
||||||
|
|
||||||
|
this._endTrimButton = new TrimButtonClass(this, 1, "Set trim end at playhead");
|
||||||
|
|
||||||
|
var endTrimButtonInstance = this._trimControlBar.addChild(this._endTrimButton, {
|
||||||
|
componentClass: 'trimButton'
|
||||||
|
}, 30);
|
||||||
|
|
||||||
|
endTrimButtonInstance.addClass('vljs-trimming-button');
|
||||||
|
endTrimButtonInstance.el().getElementsByClassName('vjs-icon-placeholder')[0].innerText = "edit"; //Create trim end time display
|
||||||
|
|
||||||
|
this._endTrimTimeDisplay = new TrimTimeDisplayClass(this.options.endTrim);
|
||||||
|
|
||||||
|
var endTrimTimeDisplayInstance = this._trimControlBar.addChild(this._endTrimTimeDisplay, {
|
||||||
|
componentClass: 'trimTimeDisplay'
|
||||||
|
}, 40);
|
||||||
|
|
||||||
|
endTrimTimeDisplayInstance.on("change", function () {
|
||||||
|
this.player_.trimmingControls().setTimestamps(endTrimTimeDisplayInstance.el().value, 1);
|
||||||
|
}); //Go To end of Trim
|
||||||
|
|
||||||
|
this._endGoToButton = new GoToButtonClass(this, 1, "Go to end of trim segment");
|
||||||
|
|
||||||
|
var endGoToButtonInstance = this._trimControlBar.addChild(this._endGoToButton, {
|
||||||
|
componentClass: 'goToButton'
|
||||||
|
}, 50);
|
||||||
|
|
||||||
|
endGoToButtonInstance.addClass('vljs-trimming-button');
|
||||||
|
endGoToButtonInstance.el().getElementsByClassName('vjs-icon-placeholder')[0].innerText = "skip_next"; //End playback at trim endpoint
|
||||||
|
|
||||||
|
this._playbackEndToggle = new playbackEndToggleClass(this, "End playback at trim endpoint");
|
||||||
|
|
||||||
|
var playbackEndToggleInstance = this._trimControlBar.addChild(this._playbackEndToggle, {
|
||||||
|
componentClass: 'playbackEndToggle'
|
||||||
|
}, 60);
|
||||||
|
|
||||||
|
playbackEndToggleInstance.addClass('vljs-trimming-button');
|
||||||
|
playbackEndToggleInstance.el().getElementsByClassName('vjs-icon-placeholder')[0].innerText = "stop";
|
||||||
|
};
|
||||||
|
|
||||||
|
_proto.updateTrimTimes = function updateTrimTimes(startValue, endValue) {
|
||||||
|
//Update stored values
|
||||||
|
this.options.startTrim = startValue;
|
||||||
|
this.options.endTrim = endValue; //Update timestamp displays
|
||||||
|
|
||||||
|
this._startTrimTimeDisplay.updateTimeContent(startValue);
|
||||||
|
|
||||||
|
this._endTrimTimeDisplay.updateTimeContent(endValue); //Update slider
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById("trimBarPlaceholder").style["marginLeft"] = startValue / this.player.duration() * 100 + "%";
|
||||||
|
document.getElementById("trimBarPlaceholder").style["marginRight"] = 100 - endValue / this.player.duration() * 100 + "%";
|
||||||
|
};
|
||||||
|
|
||||||
|
_proto.setTimestamps = function setTimestamps(value, index) {
|
||||||
|
if (/^\d*:?\d*:?\d*\.?\d*$/.test(value)) {
|
||||||
|
if (index === 0) {
|
||||||
|
this.updateTrimTimes(this.getSeconds(value), this.options.endTrim);
|
||||||
|
} else if (index === 1) {
|
||||||
|
this.updateTrimTimes(this.options.startTrim, this.getSeconds(value));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this._startTrimTimeDisplay.updateTimeContent(startValue);
|
||||||
|
|
||||||
|
this._endTrimTimeDisplay.updateTimeContent(endValue);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_proto.getSeconds = function getSeconds(time) {
|
||||||
|
var timeArr = time.split(':'),
|
||||||
|
//Array of hours, minutes, and seconds.
|
||||||
|
s = 0,
|
||||||
|
//Seconds total
|
||||||
|
m = 1; //Multiplier
|
||||||
|
|
||||||
|
while (timeArr.length > 0) {
|
||||||
|
//Iterate through time segments starting from the seconds,
|
||||||
|
s += m * timeArr.pop(); //multiply as appropriate, and add to seconds total,
|
||||||
|
|
||||||
|
m *= 60; //increase multiplier.
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
};
|
||||||
|
|
||||||
|
return TrimmingControls;
|
||||||
|
}(Plugin); // Define default values for the plugin's `state` object here.
|
||||||
|
|
||||||
|
|
||||||
|
TrimmingControls.defaultState = {}; // Include the version number.
|
||||||
|
|
||||||
|
TrimmingControls.VERSION = version; // Register the plugin with video.js.
|
||||||
|
|
||||||
|
videojs.registerPlugin('trimmingControls', TrimmingControls);
|
||||||
|
|
||||||
|
export default TrimmingControls;
|
@ -0,0 +1,460 @@
|
|||||||
|
/*! @name videojs-trimming-controls @version 0.0.0 @license MIT */
|
||||||
|
(function (global, factory) {
|
||||||
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('video.js')) :
|
||||||
|
typeof define === 'function' && define.amd ? define(['video.js'], factory) :
|
||||||
|
(global.videojsTrimmingControls = factory(global.videojs));
|
||||||
|
}(this, (function (videojs) { 'use strict';
|
||||||
|
|
||||||
|
videojs = videojs && videojs.hasOwnProperty('default') ? videojs['default'] : videojs;
|
||||||
|
|
||||||
|
function _inheritsLoose(subClass, superClass) {
|
||||||
|
subClass.prototype = Object.create(superClass.prototype);
|
||||||
|
subClass.prototype.constructor = subClass;
|
||||||
|
subClass.__proto__ = superClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
var version = "0.0.0";
|
||||||
|
|
||||||
|
var Plugin = videojs.getPlugin('plugin'); // Default options for the plugin.
|
||||||
|
|
||||||
|
var defaults = {
|
||||||
|
startTrim: 60,
|
||||||
|
endTrim: 120,
|
||||||
|
limitPlayback: false
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* An advanced Video.js plugin. For more information on the API
|
||||||
|
*
|
||||||
|
* See: https://blog.videojs.com/feature-spotlight-advanced-plugins/
|
||||||
|
*/
|
||||||
|
|
||||||
|
var TrimmingControls =
|
||||||
|
/*#__PURE__*/
|
||||||
|
function (_Plugin) {
|
||||||
|
_inheritsLoose(TrimmingControls, _Plugin);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a TrimmingControls plugin instance.
|
||||||
|
*
|
||||||
|
* @param {Player} player
|
||||||
|
* A Video.js Player instance.
|
||||||
|
*
|
||||||
|
* @param {Object} [options]
|
||||||
|
* An optional options object.
|
||||||
|
*
|
||||||
|
* While not a core part of the Video.js plugin architecture, a
|
||||||
|
* second argument of options is a convenient way to accept inputs
|
||||||
|
* from your plugin's caller.
|
||||||
|
*/
|
||||||
|
function TrimmingControls(player, options) {
|
||||||
|
var _this;
|
||||||
|
|
||||||
|
// the parent class will add player under this.player
|
||||||
|
_this = _Plugin.call(this, player) || this;
|
||||||
|
_this.options = videojs.mergeOptions(defaults, options);
|
||||||
|
|
||||||
|
_this.createTrimmingControls();
|
||||||
|
|
||||||
|
player.ready(function () {
|
||||||
|
setTimeout(function () {
|
||||||
|
_this.updateTrimTimes(_this.options.startTrim, _this.options.endTrim);
|
||||||
|
}, 100);
|
||||||
|
player.on("timeupdate", function () {
|
||||||
|
if (_this.options.limitPlayback && _this.player.currentTime() >= _this.options.endTrim) {
|
||||||
|
_this.player.currentTime(_this.options.endTrim);
|
||||||
|
|
||||||
|
_this.player.pause();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
player.on('playing', function () {
|
||||||
|
videojs.log('playback began!');
|
||||||
|
|
||||||
|
_this.updateTrimTimes(_this.options.startTrim, _this.options.endTrim);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _proto = TrimmingControls.prototype;
|
||||||
|
|
||||||
|
_proto.createTrimmingControls = function createTrimmingControls() {
|
||||||
|
var player = this.player;
|
||||||
|
var videoJsComponentClass = videojs.getComponent('Component');
|
||||||
|
/**
|
||||||
|
* Extend vjs button class for quality button.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var TrimControlBarClass =
|
||||||
|
/*#__PURE__*/
|
||||||
|
function (_videoJsComponentClas) {
|
||||||
|
_inheritsLoose(TrimControlBarClass, _videoJsComponentClas);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component constructor.
|
||||||
|
*/
|
||||||
|
function TrimControlBarClass() {
|
||||||
|
return _videoJsComponentClas.call(this, player, {
|
||||||
|
title: player.localize('Trimming Controls')
|
||||||
|
}) || this;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _proto2 = TrimControlBarClass.prototype;
|
||||||
|
|
||||||
|
_proto2.createEl = function createEl() {
|
||||||
|
return videojs.dom.createEl('div', {
|
||||||
|
// Prefixing classes of elements within a player with "vjs-" is a convention used in Video.js.
|
||||||
|
className: 'vjs-control-bar vjs-trimming-controls',
|
||||||
|
dir: 'ltr'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return TrimControlBarClass;
|
||||||
|
}(videoJsComponentClass);
|
||||||
|
|
||||||
|
var videoJSSpacerClass = videojs.getComponent('Spacer');
|
||||||
|
var videoJSButtonClass = videojs.getComponent('Button');
|
||||||
|
|
||||||
|
var GoToButtonClass =
|
||||||
|
/*#__PURE__*/
|
||||||
|
function (_videoJSButtonClass) {
|
||||||
|
_inheritsLoose(GoToButtonClass, _videoJSButtonClass);
|
||||||
|
|
||||||
|
function GoToButtonClass(_plugin, _targetPosition, _text) {
|
||||||
|
var _this2;
|
||||||
|
|
||||||
|
_this2 = _videoJSButtonClass.call(this, player, {// title: player.localize('Trim Button'),
|
||||||
|
// label: "Trim Here"
|
||||||
|
}) || this;
|
||||||
|
_this2.trimmingControls = _plugin;
|
||||||
|
_this2.targetPosition = _targetPosition;
|
||||||
|
|
||||||
|
_this2.controlText(_text);
|
||||||
|
|
||||||
|
_this2.el().getElementsByClassName('vjs-icon-placeholder')[0].classList += " material-icons";
|
||||||
|
return _this2;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _proto3 = GoToButtonClass.prototype;
|
||||||
|
|
||||||
|
_proto3.handleClick = function handleClick() {
|
||||||
|
if (this.targetPosition == 0) {
|
||||||
|
this.player().currentTime(this.trimmingControls.options.startTrim);
|
||||||
|
} else if (this.targetPosition == 1) {
|
||||||
|
this.player().currentTime(this.trimmingControls.options.endTrim);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return GoToButtonClass;
|
||||||
|
}(videoJSButtonClass);
|
||||||
|
|
||||||
|
var TrimButtonClass =
|
||||||
|
/*#__PURE__*/
|
||||||
|
function (_videoJSButtonClass2) {
|
||||||
|
_inheritsLoose(TrimButtonClass, _videoJSButtonClass2);
|
||||||
|
|
||||||
|
function TrimButtonClass(_plugin, _targetPosition, _text) {
|
||||||
|
var _this3;
|
||||||
|
|
||||||
|
_this3 = _videoJSButtonClass2.call(this, player, {// title: player.localize('Trim Button'),
|
||||||
|
// label: "Trim Here"
|
||||||
|
}) || this;
|
||||||
|
_this3.trimmingControls = _plugin;
|
||||||
|
_this3.targetPosition = _targetPosition;
|
||||||
|
|
||||||
|
_this3.controlText(_text);
|
||||||
|
|
||||||
|
_this3.el().getElementsByClassName('vjs-icon-placeholder')[0].classList += " material-icons";
|
||||||
|
return _this3;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _proto4 = TrimButtonClass.prototype;
|
||||||
|
|
||||||
|
_proto4.handleClick = function handleClick() {
|
||||||
|
if (this.targetPosition == 0) {
|
||||||
|
this.trimmingControls.updateTrimTimes(this.player().currentTime(), this.trimmingControls.options.endTrim);
|
||||||
|
} else if (this.targetPosition == 1) {
|
||||||
|
this.trimmingControls.updateTrimTimes(this.trimmingControls.options.startTrim, this.player().currentTime());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return TrimButtonClass;
|
||||||
|
}(videoJSButtonClass);
|
||||||
|
|
||||||
|
var TrimTimeDisplayClass =
|
||||||
|
/*#__PURE__*/
|
||||||
|
function (_videoJsComponentClas2) {
|
||||||
|
_inheritsLoose(TrimTimeDisplayClass, _videoJsComponentClas2);
|
||||||
|
|
||||||
|
function TrimTimeDisplayClass(_defaultTime) {
|
||||||
|
var _this4;
|
||||||
|
|
||||||
|
_this4 = _videoJsComponentClas2.call(this, player, {}) || this;
|
||||||
|
|
||||||
|
_this4.updateTimeContent(_defaultTime);
|
||||||
|
|
||||||
|
return _this4;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _proto5 = TrimTimeDisplayClass.prototype;
|
||||||
|
|
||||||
|
_proto5.createEl = function createEl() {
|
||||||
|
return videojs.dom.createEl('input', {
|
||||||
|
// Prefixing classes of elements within a player with "vjs-" is a convention used in Video.js.
|
||||||
|
className: 'vjs-time-display'
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
_proto5.updateTimeContent = function updateTimeContent(timeInSeconds) {
|
||||||
|
videojs.dom.emptyEl(this.el()); //this.controlText(videojs.formatTime(timeInSeconds, 600))
|
||||||
|
//videojs.dom.appendContent(this.el(), videojs.formatTime(timeInSeconds, 600));
|
||||||
|
//videojs.dom.textContent(this.el(), videojs.formatTime(timeInSeconds, 600));
|
||||||
|
|
||||||
|
this.el().value = videojs.formatTime(timeInSeconds, 600.01);
|
||||||
|
};
|
||||||
|
|
||||||
|
return TrimTimeDisplayClass;
|
||||||
|
}(videoJsComponentClass);
|
||||||
|
|
||||||
|
var FrameButtonClass =
|
||||||
|
/*#__PURE__*/
|
||||||
|
function (_videoJSButtonClass3) {
|
||||||
|
_inheritsLoose(FrameButtonClass, _videoJSButtonClass3);
|
||||||
|
|
||||||
|
function FrameButtonClass(_plugin, _targetPosition, _text) {
|
||||||
|
var _this5;
|
||||||
|
|
||||||
|
_this5 = _videoJSButtonClass3.call(this, player, {// title: player.localize('Trim Button'),
|
||||||
|
// label: "Trim Here"
|
||||||
|
}) || this;
|
||||||
|
_this5.trimmingControls = _plugin;
|
||||||
|
_this5.targetPosition = _targetPosition;
|
||||||
|
|
||||||
|
_this5.controlText(_text);
|
||||||
|
|
||||||
|
_this5.el().getElementsByClassName('vjs-icon-placeholder')[0].classList += " material-icons";
|
||||||
|
return _this5;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _proto6 = FrameButtonClass.prototype;
|
||||||
|
|
||||||
|
_proto6.handleClick = function handleClick() {
|
||||||
|
if (this.targetPosition == 0) {
|
||||||
|
this.player().currentTime(this.player().currentTime() - 0.1);
|
||||||
|
} else if (this.targetPosition == 1) {
|
||||||
|
this.player().currentTime(this.player().currentTime() + 0.1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return FrameButtonClass;
|
||||||
|
}(videoJSButtonClass);
|
||||||
|
|
||||||
|
var videoJSPlayToggleClass = videojs.getComponent('PlayToggle');
|
||||||
|
|
||||||
|
var playbackEndToggleClass =
|
||||||
|
/*#__PURE__*/
|
||||||
|
function (_videoJSButtonClass4) {
|
||||||
|
_inheritsLoose(playbackEndToggleClass, _videoJSButtonClass4);
|
||||||
|
|
||||||
|
function playbackEndToggleClass(_plugin, _text) {
|
||||||
|
var _this6;
|
||||||
|
|
||||||
|
_this6 = _videoJSButtonClass4.call(this, player, {// title: player.localize('Trim Button'),
|
||||||
|
// label: "Trim Here"
|
||||||
|
}) || this;
|
||||||
|
_this6.trimmingControls = _plugin;
|
||||||
|
|
||||||
|
_this6.controlText(_text);
|
||||||
|
|
||||||
|
_this6.el().getElementsByClassName('vjs-icon-placeholder')[0].classList += " material-icons";
|
||||||
|
return _this6;
|
||||||
|
}
|
||||||
|
|
||||||
|
var _proto7 = playbackEndToggleClass.prototype;
|
||||||
|
|
||||||
|
_proto7.handleClick = function handleClick() {
|
||||||
|
this.trimmingControls.options.limitPlayback = !this.trimmingControls.options.limitPlayback;
|
||||||
|
this.toggleClass('playbackLimited');
|
||||||
|
};
|
||||||
|
|
||||||
|
return playbackEndToggleClass;
|
||||||
|
}(videoJSButtonClass); //Creating Trimming Seek Bar
|
||||||
|
|
||||||
|
|
||||||
|
this._trimSeekControlBar = new TrimControlBarClass();
|
||||||
|
var trimSeekControlBarInstance = player.addChild(this._trimSeekControlBar, {
|
||||||
|
componentClass: 'trimControlBar'
|
||||||
|
}, player.children().length);
|
||||||
|
trimSeekControlBarInstance.addClass('vljs-trim-seek');
|
||||||
|
trimSeekControlBarInstance.el().innerHTML = '<div id="trimBarPlaceholderContainer"><div id="trimBarPlaceholder"></div></div>'; // //Spacer
|
||||||
|
// this._spacer1 = new videoJSSpacerClass();
|
||||||
|
// const spacer1Instance = this._trimSeekControlBar.addChild(this._spacer1, {componentClass: 'spacer'}, 0);
|
||||||
|
// spacer1Instance.setAttribute("style", "flex: 0 0 158px");
|
||||||
|
// //Spacer
|
||||||
|
// this._spacer1 = new videoJSSpacerClass();
|
||||||
|
// const spacer2Instance = this._trimSeekControlBar.addChild(this._spacer1, {componentClass: 'spacer'}, 2);
|
||||||
|
// spacer2Instance.setAttribute("style", "flex: 0 0 178px");
|
||||||
|
//Creating Trimming Controls Bar
|
||||||
|
|
||||||
|
this._trimControlBar = new TrimControlBarClass();
|
||||||
|
var trimControlBarInstance = player.addChild(this._trimControlBar, {
|
||||||
|
componentClass: 'trimControlBar'
|
||||||
|
}, player.children().length);
|
||||||
|
trimControlBarInstance.addClass('vljs-trim-buttons'); //Trim Bar Controls order: spacer,GoTo,Time,SetPlayhead,frameadjust,playpause,frameAdjust,setPlayhead,time,GoTo, endplayback
|
||||||
|
//Spacer for balance
|
||||||
|
|
||||||
|
this._spacer = new videoJSSpacerClass();
|
||||||
|
|
||||||
|
var spacerInstance = this._trimControlBar.addChild(this._spacer, {
|
||||||
|
componentClass: 'spacer'
|
||||||
|
}, 0); //Go To start of Trim
|
||||||
|
|
||||||
|
|
||||||
|
this._startGoToButton = new GoToButtonClass(this, 0, "Go to start of trim segment");
|
||||||
|
|
||||||
|
var startGoToButtonInstance = this._trimControlBar.addChild(this._startGoToButton, {
|
||||||
|
componentClass: 'goToButton'
|
||||||
|
}, 5);
|
||||||
|
|
||||||
|
startGoToButtonInstance.addClass('vljs-trimming-button');
|
||||||
|
startGoToButtonInstance.el().getElementsByClassName('vjs-icon-placeholder')[0].innerText = "skip_previous"; //Create trim start time display
|
||||||
|
|
||||||
|
this._startTrimTimeDisplay = new TrimTimeDisplayClass(this.options.startTrim);
|
||||||
|
|
||||||
|
var startTrimTimeDisplayInstance = this._trimControlBar.addChild(this._startTrimTimeDisplay, {
|
||||||
|
componentClass: 'trimTimeDisplay'
|
||||||
|
}, 10);
|
||||||
|
|
||||||
|
startTrimTimeDisplayInstance.on("change", function () {
|
||||||
|
this.player_.trimmingControls().setTimestamps(startTrimTimeDisplayInstance.el().value, 0);
|
||||||
|
}); //Create set start at playhead button
|
||||||
|
|
||||||
|
this._startTrimButton = new TrimButtonClass(this, 0, "Set trim start at playhead");
|
||||||
|
|
||||||
|
var startTrimButtonInstance = this._trimControlBar.addChild(this._startTrimButton, {
|
||||||
|
componentClass: 'trimButton'
|
||||||
|
}, 20);
|
||||||
|
|
||||||
|
startTrimButtonInstance.addClass('vljs-trimming-button');
|
||||||
|
startTrimButtonInstance.el().getElementsByClassName('vjs-icon-placeholder')[0].innerText = "edit"; //Create Frame Back Button
|
||||||
|
|
||||||
|
this._frameBackButton = new FrameButtonClass(this, 0, "Move back 1 frame");
|
||||||
|
|
||||||
|
var frameBackButtonInstance = this._trimControlBar.addChild(this._frameBackButton, {
|
||||||
|
componentClass: 'frameButton'
|
||||||
|
}, 22);
|
||||||
|
|
||||||
|
frameBackButtonInstance.addClass('vljs-trimming-button');
|
||||||
|
frameBackButtonInstance.el().getElementsByClassName('vjs-icon-placeholder')[0].innerText = "fast_rewind"; //Create Play/Pause Button
|
||||||
|
|
||||||
|
this._playPauseButton = new videoJSPlayToggleClass(this.player);
|
||||||
|
|
||||||
|
var playPauseButtonInstance = this._trimControlBar.addChild(this._playPauseButton, {
|
||||||
|
componentClass: 'playPauseButton'
|
||||||
|
}, 25); //Create Frame Forward Button
|
||||||
|
|
||||||
|
|
||||||
|
this._frameForwardButton = new FrameButtonClass(this, 1, "Move forward 1 frame");
|
||||||
|
|
||||||
|
var frameForwardButtonInstance = this._trimControlBar.addChild(this._frameForwardButton, {
|
||||||
|
componentClass: 'frameButton'
|
||||||
|
}, 27);
|
||||||
|
|
||||||
|
frameForwardButtonInstance.addClass('vljs-trimming-button');
|
||||||
|
frameForwardButtonInstance.el().getElementsByClassName('vjs-icon-placeholder')[0].innerText = "fast_forward"; //Create set end at playhead button
|
||||||
|
|
||||||
|
this._endTrimButton = new TrimButtonClass(this, 1, "Set trim end at playhead");
|
||||||
|
|
||||||
|
var endTrimButtonInstance = this._trimControlBar.addChild(this._endTrimButton, {
|
||||||
|
componentClass: 'trimButton'
|
||||||
|
}, 30);
|
||||||
|
|
||||||
|
endTrimButtonInstance.addClass('vljs-trimming-button');
|
||||||
|
endTrimButtonInstance.el().getElementsByClassName('vjs-icon-placeholder')[0].innerText = "edit"; //Create trim end time display
|
||||||
|
|
||||||
|
this._endTrimTimeDisplay = new TrimTimeDisplayClass(this.options.endTrim);
|
||||||
|
|
||||||
|
var endTrimTimeDisplayInstance = this._trimControlBar.addChild(this._endTrimTimeDisplay, {
|
||||||
|
componentClass: 'trimTimeDisplay'
|
||||||
|
}, 40);
|
||||||
|
|
||||||
|
endTrimTimeDisplayInstance.on("change", function () {
|
||||||
|
this.player_.trimmingControls().setTimestamps(endTrimTimeDisplayInstance.el().value, 1);
|
||||||
|
}); //Go To end of Trim
|
||||||
|
|
||||||
|
this._endGoToButton = new GoToButtonClass(this, 1, "Go to end of trim segment");
|
||||||
|
|
||||||
|
var endGoToButtonInstance = this._trimControlBar.addChild(this._endGoToButton, {
|
||||||
|
componentClass: 'goToButton'
|
||||||
|
}, 50);
|
||||||
|
|
||||||
|
endGoToButtonInstance.addClass('vljs-trimming-button');
|
||||||
|
endGoToButtonInstance.el().getElementsByClassName('vjs-icon-placeholder')[0].innerText = "skip_next"; //End playback at trim endpoint
|
||||||
|
|
||||||
|
this._playbackEndToggle = new playbackEndToggleClass(this, "End playback at trim endpoint");
|
||||||
|
|
||||||
|
var playbackEndToggleInstance = this._trimControlBar.addChild(this._playbackEndToggle, {
|
||||||
|
componentClass: 'playbackEndToggle'
|
||||||
|
}, 60);
|
||||||
|
|
||||||
|
playbackEndToggleInstance.addClass('vljs-trimming-button');
|
||||||
|
playbackEndToggleInstance.el().getElementsByClassName('vjs-icon-placeholder')[0].innerText = "stop";
|
||||||
|
};
|
||||||
|
|
||||||
|
_proto.updateTrimTimes = function updateTrimTimes(startValue, endValue) {
|
||||||
|
//Update stored values
|
||||||
|
this.options.startTrim = startValue;
|
||||||
|
this.options.endTrim = endValue; //Update timestamp displays
|
||||||
|
|
||||||
|
this._startTrimTimeDisplay.updateTimeContent(startValue);
|
||||||
|
|
||||||
|
this._endTrimTimeDisplay.updateTimeContent(endValue); //Update slider
|
||||||
|
|
||||||
|
|
||||||
|
document.getElementById("trimBarPlaceholder").style["marginLeft"] = startValue / this.player.duration() * 100 + "%";
|
||||||
|
document.getElementById("trimBarPlaceholder").style["marginRight"] = 100 - endValue / this.player.duration() * 100 + "%";
|
||||||
|
};
|
||||||
|
|
||||||
|
_proto.setTimestamps = function setTimestamps(value, index) {
|
||||||
|
if (/^\d*:?\d*:?\d*\.?\d*$/.test(value)) {
|
||||||
|
if (index === 0) {
|
||||||
|
this.updateTrimTimes(this.getSeconds(value), this.options.endTrim);
|
||||||
|
} else if (index === 1) {
|
||||||
|
this.updateTrimTimes(this.options.startTrim, this.getSeconds(value));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this._startTrimTimeDisplay.updateTimeContent(startValue);
|
||||||
|
|
||||||
|
this._endTrimTimeDisplay.updateTimeContent(endValue);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_proto.getSeconds = function getSeconds(time) {
|
||||||
|
var timeArr = time.split(':'),
|
||||||
|
//Array of hours, minutes, and seconds.
|
||||||
|
s = 0,
|
||||||
|
//Seconds total
|
||||||
|
m = 1; //Multiplier
|
||||||
|
|
||||||
|
while (timeArr.length > 0) {
|
||||||
|
//Iterate through time segments starting from the seconds,
|
||||||
|
s += m * timeArr.pop(); //multiply as appropriate, and add to seconds total,
|
||||||
|
|
||||||
|
m *= 60; //increase multiplier.
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
};
|
||||||
|
|
||||||
|
return TrimmingControls;
|
||||||
|
}(Plugin); // Define default values for the plugin's `state` object here.
|
||||||
|
|
||||||
|
|
||||||
|
TrimmingControls.defaultState = {}; // Include the version number.
|
||||||
|
|
||||||
|
TrimmingControls.VERSION = version; // Register the plugin with video.js.
|
||||||
|
|
||||||
|
videojs.registerPlugin('trimmingControls', TrimmingControls);
|
||||||
|
|
||||||
|
return TrimmingControls;
|
||||||
|
|
||||||
|
})));
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,168 @@
|
|||||||
|
var desertBusStart = new Date("1970-01-01T00:00:00Z");
|
||||||
|
|
||||||
|
pageSetup = function() {
|
||||||
|
//Get values from ThrimShim
|
||||||
|
if(/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) {
|
||||||
|
alert("No video available for stream.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
//data = testThrimShim;
|
||||||
|
desertBusStart = new Date(data.bustime_start);
|
||||||
|
document.getElementById("hiddenSubmissionID").value = data.id;
|
||||||
|
document.getElementById("StreamName").value = data.video_channel ? data.video_channel:document.getElementById("StreamName").value;
|
||||||
|
document.getElementById("StreamStart").value = data.event_start;
|
||||||
|
document.getElementById("BusTimeStart").value = (new Date(data.event_start+"Z") < desertBusStart ? "-":"") + videojs.formatTime(Math.abs((new Date(data.event_start+"Z") - desertBusStart)/1000), 600.01).padStart(7, "0:");
|
||||||
|
document.getElementById("StreamEnd").value = data.event_end;
|
||||||
|
document.getElementById("BusTimeEnd").value = (new Date(data.event_end+"Z") < desertBusStart ? "-":"") + videojs.formatTime(Math.abs((new Date(data.event_end+"Z") - desertBusStart)/1000), 600.01).padStart(7, "0:");
|
||||||
|
document.getElementById("VideoTitle").value = data.video_title ? data.video_title:document.getElementById("VideoTitle").value;
|
||||||
|
document.getElementById("VideoDescription").value = data.video_description ? data.video_description:data.description;
|
||||||
|
|
||||||
|
loadPlaylist(data.video_start, data.video_end);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
document.getElementById('SubmitButton').disabled = true;
|
||||||
|
|
||||||
|
var startOfHour = new Date(new Date().setMinutes(0,0,0));
|
||||||
|
document.getElementById("StreamStart").value = new Date(startOfHour.getTime() - 1000*60*60).toISOString().substring(0,19);
|
||||||
|
document.getElementById("StreamEnd").value = startOfHour.toISOString().substring(0,19);
|
||||||
|
|
||||||
|
loadPlaylist();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
loadPlaylist = function(startTrim, endTrim) {
|
||||||
|
var playlist = "/playlist/" + document.getElementById("StreamName").value + ".m3u8";
|
||||||
|
|
||||||
|
if(document.getElementById("BusTimeToggleBus").checked) {
|
||||||
|
var streamStart = desertBusStart;
|
||||||
|
var busTimeStart = document.getElementById("BusTimeStart").value;
|
||||||
|
var busTimeEnd = document.getElementById("BusTimeEnd").value;
|
||||||
|
|
||||||
|
//Convert BusTime to milliseconds from start of stream
|
||||||
|
busTimeStart = (parseInt(busTimeStart.split(':')[0]) + busTimeStart.split(':')[1]/60) * 1000 * 60 * 60;
|
||||||
|
busTimeEnd = (parseInt(busTimeEnd.split(':')[0]) + busTimeEnd.split(':')[1]/60) * 1000 * 60 * 60;
|
||||||
|
|
||||||
|
document.getElementById("StreamStart").value = new Date(streamStart.getTime() + busTimeStart).toISOString().substring(0,19);
|
||||||
|
document.getElementById("StreamEnd").value = new Date(streamStart.getTime() + busTimeEnd).toISOString().substring(0,19);
|
||||||
|
}
|
||||||
|
|
||||||
|
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("&"):"";
|
||||||
|
|
||||||
|
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();
|
||||||
|
qualityLevels.forEach(function(level, index) {
|
||||||
|
document.getElementById('qualityLevel').innerHTML += '<option value="'+level+'" '+(index==0 ? 'selected':'')+'>'+level+'</option>';
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
thrimbletrimmerSubmit = function() {
|
||||||
|
document.getElementById('SubmitButton').disabled = true;
|
||||||
|
if(player.trimmingControls().options.startTrim >= player.trimmingControls().options.endTrim) {
|
||||||
|
alert("End Time must be greater than Start Time");
|
||||||
|
document.getElementById('SubmitButton').disabled = false;
|
||||||
|
} else {
|
||||||
|
var discontinuities = mapDiscontinuities();
|
||||||
|
|
||||||
|
var wubData = {
|
||||||
|
video_start:getRealTimeForPlayerTime(discontinuities, player.trimmingControls().options.startTrim).replace('Z',''),
|
||||||
|
video_end:getRealTimeForPlayerTime(discontinuities, player.trimmingControls().options.endTrim).replace('Z',''),
|
||||||
|
video_title:document.getElementById("VideoTitle").value,
|
||||||
|
video_description:document.getElementById("VideoDescription").value,
|
||||||
|
allow_holes:String(document.getElementById('AllowHoles').checked),
|
||||||
|
upload_location:document.getElementById('uploadLocation').value,
|
||||||
|
video_channel:document.getElementById("StreamName").value,
|
||||||
|
video_quality:document.getElementById('qualityLevel').options[document.getElementById('qualityLevel').options.selectedIndex].value,
|
||||||
|
uploader_whitelist:(document.getElementById('uploaderWhitelist').value ? document.getElementById('uploaderWhitelist').value.split(','):null),
|
||||||
|
state:"EDITED",
|
||||||
|
token: user.getAuthResponse().id_token
|
||||||
|
};
|
||||||
|
// state_columns = ['state', 'uploader', 'error', 'video_link']
|
||||||
|
console.log(wubData);
|
||||||
|
console.log(JSON.stringify(wubData));
|
||||||
|
|
||||||
|
//Submit to thrimshim
|
||||||
|
var rowId = /id=(.*)(?:&|$)/.exec(document.location.search)[1];
|
||||||
|
fetch("/thrimshim/"+rowId, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(wubData)
|
||||||
|
})
|
||||||
|
.then(response => { if (!response.ok) { throw Error(response.statusText); }; return response; })
|
||||||
|
.then(data => { console.log(data); setTimeout(() => { window.location.href = '/thrimbletrimmer/dashboard.html'; }, 500); })
|
||||||
|
.catch(error => { console.log(error); alert(error); });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
thrimbletrimmerDownload = function() {
|
||||||
|
document.getElementById('SubmitButton').disabled = true;
|
||||||
|
if(player.trimmingControls().options.startTrim >= player.trimmingControls().options.endTrim) {
|
||||||
|
alert("End Time must be greater than Start Time");
|
||||||
|
document.getElementById('SubmitButton').disabled = false;
|
||||||
|
} 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" +
|
||||||
|
"?start=" + downloadStart +
|
||||||
|
"&end=" + downloadEnd +
|
||||||
|
"&allow_holes=" + String(document.getElementById('AllowHoles').checked);
|
||||||
|
console.log(targetURL);
|
||||||
|
document.getElementById('outputFile').src = targetURL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
thrimbletrimmerManualLink = function() {
|
||||||
|
var rowId = /id=(.*)(?:&|$)/.exec(document.location.search)[1];
|
||||||
|
fetch("/thrimshim/manual-link/"+rowId, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
link: document.getElementById("ManualLink").value,
|
||||||
|
token: user.getAuthResponse().id_token
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.then(response => { if (!response.ok) { throw Error(response.statusText); }; return response; })
|
||||||
|
.then(data => { console.log(data); setTimeout(() => { alert("Manual link set"); }, 500); })
|
||||||
|
.catch(error => { console.log(error); alert(error); });
|
||||||
|
};
|
||||||
|
|
||||||
|
thrimbletrimmerResetLink = function() {
|
||||||
|
var rowId = /id=(.*)(?:&|$)/.exec(document.location.search)[1];
|
||||||
|
if(confirm('Are you sure you want to reset this event?')) {
|
||||||
|
fetch("/thrimshim/reset/"+rowId, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Accept': 'application/json',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({token: user.getAuthResponse().id_token})
|
||||||
|
})
|
||||||
|
.then(response => { if (!response.ok) { throw Error(response.statusText); }; return response; })
|
||||||
|
.then(data => { console.log(data); setTimeout(() => { window.location.reload() }, 500); })
|
||||||
|
.catch(error => { console.log(error); alert(error); });
|
||||||
|
}
|
||||||
|
};
|
@ -0,0 +1,77 @@
|
|||||||
|
document.addEventListener('keypress', (event) => {
|
||||||
|
//if(event.target.nodeName == "BODY") {
|
||||||
|
if(event.target.nodeName !== "INPUT" && event.target.nodeName !== "TEXTAREA") {
|
||||||
|
switch(event.key) {
|
||||||
|
case "j":
|
||||||
|
player.currentTime(player.currentTime()-10);
|
||||||
|
break;
|
||||||
|
case "k":
|
||||||
|
player.paused() ? player.play():player.pause();
|
||||||
|
break;
|
||||||
|
case "l":
|
||||||
|
player.currentTime(player.currentTime()+10);
|
||||||
|
break;
|
||||||
|
case ",":
|
||||||
|
player.currentTime(player.currentTime()-0.1);
|
||||||
|
break;
|
||||||
|
case ".":
|
||||||
|
player.currentTime(player.currentTime()+0.1);
|
||||||
|
break;
|
||||||
|
case "i":
|
||||||
|
player.trimmingControls().updateTrimTimes(player.currentTime(), player.trimmingControls().options.endTrim);
|
||||||
|
break;
|
||||||
|
case "o":
|
||||||
|
player.trimmingControls().updateTrimTimes(player.trimmingControls().options.startTrim, player.currentTime());
|
||||||
|
break;
|
||||||
|
case "0":
|
||||||
|
player.currentTime(0);
|
||||||
|
break;
|
||||||
|
case "1":
|
||||||
|
player.currentTime(player.duration()*0.1);
|
||||||
|
break;
|
||||||
|
case "2":
|
||||||
|
player.currentTime(player.duration()*0.2);
|
||||||
|
break;
|
||||||
|
case "3":
|
||||||
|
player.currentTime(player.duration()*0.3);
|
||||||
|
break;
|
||||||
|
case "4":
|
||||||
|
player.currentTime(player.duration()*0.4);
|
||||||
|
break;
|
||||||
|
case "5":
|
||||||
|
player.currentTime(player.duration()*0.5);
|
||||||
|
break;
|
||||||
|
case "6":
|
||||||
|
player.currentTime(player.duration()*0.6);
|
||||||
|
break;
|
||||||
|
case "7":
|
||||||
|
player.currentTime(player.duration()*0.7);
|
||||||
|
break;
|
||||||
|
case "8":
|
||||||
|
player.currentTime(player.duration()*0.8);
|
||||||
|
break;
|
||||||
|
case "9":
|
||||||
|
player.currentTime(player.duration()*0.9);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// const keyName = event.key;
|
||||||
|
// console.log('keypress event\n\n' + 'key: ' + keyName);
|
||||||
|
// console.log(event.target.nodeName);
|
||||||
|
});
|
||||||
|
|
||||||
|
//Arrow keys only detected on keydown, keypress only works in "some" browsers
|
||||||
|
document.addEventListener('keydown', (event) => {
|
||||||
|
if(event.target.nodeName !== "INPUT" && event.target.nodeName !== "TEXTAREA") {
|
||||||
|
switch(event.keyCode) {
|
||||||
|
case 37:
|
||||||
|
player.currentTime(player.currentTime()-5);
|
||||||
|
break;
|
||||||
|
case 39:
|
||||||
|
player.currentTime(player.currentTime()+5);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
@ -0,0 +1,92 @@
|
|||||||
|
var player = null;
|
||||||
|
|
||||||
|
function setupPlayer(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 = {
|
||||||
|
sources: [{ src: source }],
|
||||||
|
liveui: true,
|
||||||
|
//fluid:true,
|
||||||
|
controls:true,
|
||||||
|
autoplay:false,
|
||||||
|
width:1280,
|
||||||
|
height:420,
|
||||||
|
playbackRates: [0.5, 1, 1.25, 1.5, 2],
|
||||||
|
inactivityTimeout: 0,
|
||||||
|
controlBar: {
|
||||||
|
fullscreenToggle: false,
|
||||||
|
volumePanel: {
|
||||||
|
inline: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if(player) { //Destroy and recreate the player if it already exists.
|
||||||
|
player.dispose();
|
||||||
|
document.getElementById("EditorContainer").innerHTML = `
|
||||||
|
<video id="my-player" class="video-js" controls disablePictureInPicture preload="auto">
|
||||||
|
<p class="vjs-no-js">To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="http://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a></p>
|
||||||
|
</video>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
player = videojs('my-player', options, function onPlayerReady() {
|
||||||
|
videojs.log('Your player is ready!');
|
||||||
|
|
||||||
|
// In this context, `this` is the player that was created by Video.js.
|
||||||
|
this.on('ready', function() {
|
||||||
|
//this.play();
|
||||||
|
});
|
||||||
|
|
||||||
|
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;
|
||||||
|
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?
|
||||||
|
this.on('ended', function() {
|
||||||
|
videojs.log('Awww...over so soon?!');
|
||||||
|
});
|
||||||
|
|
||||||
|
this.on('error', function() {
|
||||||
|
videojs.log("Could not load video stream");
|
||||||
|
alert("No video available for stream.");
|
||||||
|
document.getElementById("my-player").style.display = "none";
|
||||||
|
})
|
||||||
|
});
|
||||||
|
var hlsQS = player.hlsQualitySelector();
|
||||||
|
//var trimmingControls = player.trimmingControls({ startTrim:(startTrim ? startTrim:0), endTrim:(endTrim ? endTrim:player.duration()) });
|
||||||
|
}
|
||||||
|
|
||||||
|
mapDiscontinuities = function() {
|
||||||
|
var playlist = player.vhs.playlists.master.playlists.filter(playlist => typeof playlist.discontinuityStarts !== "undefined")[0]; //Only one of the playlists will have the discontinuity or stream start objects, and it's not necessarily the first one or the source one.
|
||||||
|
var discontinuities = playlist.discontinuityStarts.map(segmentIndex => { return {segmentIndex:segmentIndex, segmentTimestamp:playlist.segments[segmentIndex].dateTimeObject, playbackIndex:null}; });
|
||||||
|
//var lastDiscontinuity = Math.max(...playlist.discontinuityStarts);
|
||||||
|
var lastDiscontinuity = playlist.discontinuityStarts.slice(-1).pop(); //Assumes discontinuities are sorted in ascending order.
|
||||||
|
|
||||||
|
var durationMarker = 0;
|
||||||
|
for (var index = 0; index <= lastDiscontinuity; index++) {
|
||||||
|
let segment = playlist.segments[index];
|
||||||
|
if(segment.discontinuity) {
|
||||||
|
discontinuities.find(discontinuity => discontinuity.segmentIndex == index).playbackIndex = durationMarker;
|
||||||
|
}
|
||||||
|
durationMarker += segment.duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
return discontinuities;
|
||||||
|
};
|
||||||
|
|
||||||
|
getRealTimeForPlayerTime = function(discontinuities, playbackIndex) {
|
||||||
|
var streamStart = player.vhs.playlists.master.playlists.filter(playlist => typeof playlist.dateTimeObject !== "undefined")[0].dateTimeObject; //Only one of the playlists will have the discontinuity or stream start objects, and it's not necessarily the first one or the source one.
|
||||||
|
|
||||||
|
//Find last discontinuity before playbackIndex
|
||||||
|
var lastDiscontinuity = discontinuities.filter(discontinuity => discontinuity.playbackIndex < playbackIndex).slice(-1).pop();
|
||||||
|
if(lastDiscontinuity) {
|
||||||
|
streamStart = lastDiscontinuity.segmentTimestamp;
|
||||||
|
playbackIndex -= lastDiscontinuity.playbackIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Date(streamStart.getTime()+playbackIndex*1000).toISOString();
|
||||||
|
};
|
@ -0,0 +1,37 @@
|
|||||||
|
html, body {
|
||||||
|
height:100%;
|
||||||
|
margin:0px;
|
||||||
|
background-color:darkgrey;
|
||||||
|
}
|
||||||
|
body.ultrawide > div { max-width:100% !important; }
|
||||||
|
body.ultrawide .my-player-dimensions { width:100% !important; }
|
||||||
|
|
||||||
|
.video-js .vjs-control-bar {
|
||||||
|
background-color:#2b333f;
|
||||||
|
}
|
||||||
|
.video-js .vjs-time-control {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.video-js .vjs-remaining-time {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.video-js .vjs-current-time.vjs-time-control, .video-js .vjs-duration.vjs-time-control {
|
||||||
|
padding:0em;
|
||||||
|
}
|
||||||
|
.video-js .vjs-progress-control .vjs-mouse-display {
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
.vjs-menu-button-popup .vjs-menu {
|
||||||
|
bottom:-3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#EditorDetailsPane {
|
||||||
|
margin-top:100px;
|
||||||
|
}
|
||||||
|
#VideoTitle, #VideoDescription {
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
*:focus {
|
||||||
|
outline:none;
|
||||||
|
}
|
Loading…
Reference in New Issue