Initial merge of Thrimbletrimmer proper into repo.

pull/75/head
mg 5 years ago
parent 0cca85b4aa
commit aed2a77a88

@ -14,7 +14,7 @@ LOCATIONS=$(
[ "$name" == "restreamer" ] && generate_location / "http://restreamer:$port"
# thrimshim takes any calls to thrimshim/
[ "$name" == "thrimshim" ] && generate_location /thrimshim "http://thrimshim:$port"
# thrimbletrimmer takes any calls to thrimbletrimmer/
# thrimbletrimmer takes any calls to thrimbletrimmer/; serves content from /etc/nginx/html/thrimbletrimmer
[ "$name" == "thrimbletrimmer" ] && echo -e "\t\tlocation /thrimbletrimmer { }"
# all services have metrics under /metrics/SERVICE, except for thrimebletrimmer
[ "$name" != "thrimbletrimmer" ] && generate_location "/metrics/$name" "http://$name:$port/metrics"
@ -29,6 +29,7 @@ events {
}
http {
include /etc/nginx/mime.types;
server {
listen 80;
$LOCATIONS

@ -1,134 +1,134 @@
<!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(document.getElementById("manualLink").value)
}).then(data => console.log(data));
}
function testReset() {
fetch(document.getElementById("server").value+"/thrimshim/reset/"+document.getElementById("rowId").value, {
method: 'POST'
}).then(data => console.log(data));
}
</script>
</body>
<!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(document.getElementById("manualLink").value)
}).then(data => console.log(data));
}
function testReset() {
fetch(document.getElementById("server").value+"/thrimshim/reset/"+document.getElementById("rowId").value, {
method: 'POST'
}).then(data => console.log(data));
}
</script>
</body>
</html>

@ -0,0 +1,121 @@
<!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">
<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;
}
</style>
</head>
<body>
<div>
<!-- <div class="sectionContainer" style="display:none;">
<table>
<tr>
<th>Wubloader URL</th>
<th>Stream</th>
<th>Start Time</th>
<th>End Time</th>
<th>Allow Holes</th>
<th>Experimental</th>
<th></th>
</tr>
<tr>
<td><input id="WubloaderLocation" value="http://charm.wubs.stream:20088" /></td>
<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 id="AllowHoles" type="checkbox" checked /></td>
<td><input id="IsExperimental" type="checkbox" checked /></td>
<td><input type="button" value="Load Playlist" onclick="loadPlaylist()" /></td>
</tr>
<tr>
<td><a href="javascript:alert('https://wubloader.codegunner.com');">Wubloaders</a></td>
<td><a href="javascript:alert('seabats, lunarjade, gamesdonequick');">Streams</a></td>
<td><a href="javascript:window.open(document.getElementById('WubloaderLocation').value + '/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>
<table id="QueueTable">
<tr>
<th>Start Time</th>
<th>End Time</th>
<th>Event Type</th>
<th>Description</th>
<th>State</th>
<th>Edit</th>
<th>Manual Link</th>
<th>Reset</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);
fetch("/thrimshim").then(data => data.json()).then(function (data) {
data.forEach((event) => {
var row = document.createElement("TR");
row.innerHTML = `
<td>${event.event_start}</td>
<td>${event.event_end}</td>
<td>${event.category}</td>
<td>${event.description}</td>
<td>${event.state}</td>
<td><a href="/thrimbletrimmer?id=${event.id}">Edit</a></td>
<td><a href="#">Reset</a></td>
<td><a href="#">Manual Link</a></td>
`;
document.getElementById('QueueTable').appendChild(row);
});
});
</script>
</body>
</html>

@ -0,0 +1,151 @@
<!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>Wubloader URL</th>
<th>Stream</th>
<th>Start Time</th>
<th>End Time</th>
<th>Allow Holes</th>
<th>Experimental</th>
<th></th>
</tr>
<tr>
<td><input id="WubloaderLocation" value="" disabled/></td>
<td><input id="StreamName" value="rpglimitbreak" /></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 id="AllowHoles" type="checkbox" checked /></td>
<td><input id="IsExperimental" type="checkbox" checked /></td>
<td><input type="button" value="Load Playlist" onclick="loadPlaylist()" /></td>
</tr>
<tr>
<td><a href="javascript:alert('https://wubloader.codegunner.com');">Wubloaders</a></td>
<td><a href="javascript:window.open(document.getElementById('WubloaderLocation').value + '/files');">Streams</a></td>
<td><a href="javascript:window.open(document.getElementById('WubloaderLocation').value + '/files/' + document.getElementById('StreamName').value + '/source', '_blank');">Hours</a></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></td>
<td></td>
<td></td>
</tr>
<tr>
<td>Advanced Options:</td>
<td><select id="qualityLevel"></select></td>
<td><select id="uploadLocation"><option value="YouTube" selected>YouTube</option></select></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="HelpButton" style="float:right;" href="JavaScript:toggleHelp();">Help</a>
</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 toggleHelp() {
var helpPane = document.getElementById("HelpPane");
helpPane.style.display = (helpPane.style.display === "none") ? "block":"none";
}
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}

@ -0,0 +1,7 @@
/**
* videojs-hls-quality-selector
* @version 0.0.8
* @copyright 2018 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,7 @@
/**
* videojs-hls-quality-selector
* @version 0.0.8
* @copyright 2018 Chris Boustead (chris@forgemotion.com)
* @license MIT
*/
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("video.js")):"function"==typeof define&&define.amd?define(["video.js"],e):t.videojsHlsQualitySelector=e(t.videojs)}(this,function(i){"use strict";i=i&&i.hasOwnProperty("default")?i.default:i;var u="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},a=(function(){function s(t){this.value=t}function t(i){var r,u;function l(t,e){try{var n=i[t](e),o=n.value;o instanceof s?Promise.resolve(o.value).then(function(t){l("next",t)},function(t){l("throw",t)}):a(n.done?"return":"normal",n.value)}catch(t){a("throw",t)}}function a(t,e){switch(t){case"return":r.resolve({value:e,done:!0});break;case"throw":r.reject(e);break;default:r.resolve({value:e,done:!1})}(r=r.next)?l(r.key,r.arg):u=null}this._invoke=function(o,i){return new Promise(function(t,e){var n={key:o,arg:i,resolve:t,reject:e,next:null};u?u=u.next=n:(r=u=n,l(o,i))})},"function"!=typeof i.return&&(this.return=void 0)}"function"==typeof Symbol&&Symbol.asyncIterator&&(t.prototype[Symbol.asyncIterator]=function(){return this}),t.prototype.next=function(t){return this._invoke("next",t)},t.prototype.throw=function(t){return this._invoke("throw",t)},t.prototype.return=function(t){return this._invoke("return",t)}}(),function(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}),s=function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function, not "+typeof e);t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}}),e&&(Object.setPrototypeOf?Object.setPrototypeOf(t,e):t.__proto__=e)},c=function(t,e){if(!t)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!e||"object"!=typeof e&&"function"!=typeof e?t:e},r={},t=i.registerPlugin||i.plugin,l=function(){function n(t,e){a(this,n),this.player=t,this.player.qualityLevels&&this.getHls()&&(this.createQualityButton(),this.bindPlayerEvents())}return n.prototype.getHls=function(){return this.player.tech({IWillNotUseThisInPlugins:!0}).hls},n.prototype.bindPlayerEvents=function(){this.player.qualityLevels().on("addqualitylevel",this.onAddQualityLevel.bind(this))},n.prototype.createQualityButton=function(){var n=this.player,t=function(t){function e(){return a(this,e),c(this,t.call(this,n,{title:n.localize("Quality")}))}return s(e,t),e.prototype.createItems=function(){return[]},e}(i.getComponent("MenuButton"));this._qualityButton=new t;var e=n.controlBar.children().length-2,o=n.controlBar.addChild(this._qualityButton,{componentClass:"qualitySelector"},e);o.addClass("vjs-quality-selector"),o.menuButton_.$(".vjs-icon-placeholder").className+=" vjs-icon-hd",o.removeClass("vjs-hidden")},n.prototype.getQualityMenuItem=function(l){var t=this.player;return new(function(r){function u(t,e,n,o){a(this,u);var i=c(this,r.call(this,t,{label:l.label,selectable:!0,selected:l.selected||!1}));return i.item=e,i.qualityButton=n,i.plugin=o,i}return s(u,r),u.prototype.handleClick=function(){for(var t=0;t<this.qualityButton.items.length;++t)this.qualityButton.items[t].selected(!1);this.plugin.setQuality(this.item.value),this.selected(!0)},u}(i.getComponent("MenuItem")))(t,l,this._qualityButton,this)},n.prototype.onAddQualityLevel=function(){for(var n=this,t=this.player,o=t.qualityLevels().levels_||[],i=[],e=function(e){if(!i.filter(function(t){return t.item&&t.item.value===o[e].height}).length){var t=n.getQualityMenuItem.call(n,{label:o[e].height+"p",value:o[e].height});i.push(t)}},r=0;r<o.length;++r)e(r);i.sort(function(t,e){return"object"!==(void 0===t?"undefined":u(t))||"object"!==(void 0===e?"undefined":u(e))?-1:t.item.value<e.item.value?-1:t.item.value>e.item.value?1:0}),i.push(this.getQualityMenuItem.call(this,{label:t.localize("Auto"),value:"auto",selected:!0})),this._qualityButton&&(this._qualityButton.createItems=function(){return i},this._qualityButton.update())},n.prototype.setQuality=function(t){for(var e=this.player.qualityLevels(),n=0;n<e.length;++n){var o=e[n];o.enabled=o.height===t||"auto"===t}this._qualityButton.unpressButton()},n}(),e=function(n){var o=this;this.ready(function(){var t,e;t=o,e=i.mergeOptions(r,n),t.addClass("vjs-hls-quality-selector"),t.hlsQualitySelector=new l(t,e)})};return t("hlsQualitySelector",e),e.VERSION="0.0.8",e});

@ -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,132 @@
var desertBusStart = new Date("1970-01-01T00:00:00Z");
//var desertBusChannel = "gamesdonequick";
//document.getElementById("StreamName").value = desertBusChannel;
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) { // {mode: 'cors'} ???
if (!data) {
alert("No video available for stream.");
return;
}
//data = testThrimShim;
document.getElementById("hiddenSubmissionID").value = data.id;
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);
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);
document.getElementById("VideoTitle").value = data.video_title;
document.getElementById("VideoDescription").value = data.video_description ? data.video_description:data.description;
loadPlaylist();
});
}
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() {
var playlist = document.getElementById("WubloaderLocation").value + "/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);
//Get quality levels for advanced properties.
document.getElementById('qualityLevel').innerHTML = "";
fetch(document.getElementById('WubloaderLocation').value + '/files/' + document.getElementById('StreamName').value).then(data => data.json()).then(function (data) { // {mode: 'cors'} ???
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),
experimental:String(document.getElementById('IsExperimental').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, { // {mode: 'cors'} ???
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify(wubData)
}).then(data => console.log(data));
}
};
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 = document.getElementById("WubloaderLocation").value +
"/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) +
"&experimental=" + String(document.getElementById('IsExperimental').checked);
console.log(targetURL);
document.getElementById('outputFile').src = targetURL;
}
};

@ -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,89 @@
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 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.
var trimmingControls = player.trimmingControls({ startTrim:(startTrim ? startTrim:0), endTrim:(endTrim ? endTrim:player.duration()) });
});
// 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,34 @@
html, body {
height:100%;
margin:0px;
background-color:darkgrey;
}
.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…
Cancel
Save