mirror of https://github.com/ekimekim/wubloader
Initial merge of Thrimbletrimmer proper into repo.
parent
0cca85b4aa
commit
aed2a77a88
@ -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…
Reference in New Issue