Move beta Thrimbletrimmer code to primary Thrimbletrimmer code
@ -1,83 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>VST Restreamer</title>
|
||||
|
||||
<link rel="stylesheet" href="styles/thrimbletrimmer.css" />
|
||||
<link rel="stylesheet" href="videojs/video-js.min.css" />
|
||||
|
||||
<script src="videojs/video.min.js"></script>
|
||||
<script src="scripts/common.js"></script>
|
||||
<script src="scripts/stream.js"></script>
|
||||
<script src="scripts/keyboard-shortcuts.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="errors"></div>
|
||||
<form id="stream-time-settings">
|
||||
<div>
|
||||
<label for="stream-time-setting-stream" class="field-label">Stream</label>
|
||||
<input type="text" id="stream-time-setting-stream" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="stream-time-setting-start" class="field-label">Start Time</label>
|
||||
<input type="text" id="stream-time-setting-start" value="0:10:00" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="stream-time-setting-end" class="field-label">End Time</label>
|
||||
<input type="text" id="stream-time-setting-end" />
|
||||
</div>
|
||||
<div>
|
||||
<div id="stream-time-frame-of-reference">
|
||||
<input
|
||||
type="radio"
|
||||
name="time-frame-of-reference"
|
||||
id="stream-time-frame-of-reference-utc"
|
||||
value="1"
|
||||
/>
|
||||
<label for="stream-time-frame-of-reference-utc">UTC</label>
|
||||
<input
|
||||
type="radio"
|
||||
name="time-frame-of-reference"
|
||||
id="stream-time-frame-of-reference-bus"
|
||||
value="2"
|
||||
/>
|
||||
<label for="stream-time-frame-of-reference-bus">Bus Time</label>
|
||||
<input
|
||||
type="radio"
|
||||
name="time-frame-of-reference"
|
||||
id="stream-time-frame-of-reference-ago"
|
||||
value="3"
|
||||
checked
|
||||
/>
|
||||
<label for="stream-time-frame-of-reference-ago">Time Ago</label>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<button id="stream-time-settings-submit" type="submit">Load Playlist</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<video id="video" class="video-js" controls preload="auto"></video>
|
||||
|
||||
<div id="editor-help">
|
||||
<a href="#" id="editor-help-link">Help</a>
|
||||
<div id="editor-help-box" class="hidden">
|
||||
<h2>Keyboard Shortcuts</h2>
|
||||
<ul>
|
||||
<li>Number keys (0-9): Jump to that 10% interval of the video (0% - 90%)</li>
|
||||
<li>K or Space: Toggle pause</li>
|
||||
<li>J: Back 10 seconds</li>
|
||||
<li>L: Forward 10 seconds</li>
|
||||
<li>Left arrow: Back 5 seconds</li>
|
||||
<li>Right arrow: Forward 5 seconds</li>
|
||||
<li>Comma (,): Back 1 frame</li>
|
||||
<li>Period (.): Forward 1 frame</li>
|
||||
<li>Equals (=): Increase playback speed one step</li>
|
||||
<li>Hyphen (-): Decrease playback speed one step</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<a href="#" id="download">Download Video</a>
|
||||
</body>
|
||||
</html>
|
Before Width: | Height: | Size: 637 B After Width: | Height: | Size: 637 B |
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 643 B After Width: | Height: | Size: 643 B |
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
@ -1,164 +1,83 @@
|
||||
|
||||
<!--
|
||||
TODOs:
|
||||
Move Google sign-in/out buttons, and make it clear when you're not signed in.
|
||||
Move "Reset" and "Manual Link" options in here.
|
||||
Clean up the Options/Input header, move parts of it into a hidden "Advanced" menu.
|
||||
Create a cleaner player-only version of the page, or find a way to make it a version of this one via URL switch.
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>Thrimbletrimmer Goes Forth</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="google-signin-client_id" content="345276493482-r84m2giavk10glnmqna0lbq8e1hdaus0.apps.googleusercontent.com">
|
||||
|
||||
<link href="/thrimbletrimmer/plugins/video.js/dist/video-js.min.css" rel="stylesheet">
|
||||
<link href="/thrimbletrimmer/plugins/videojs-hls-quality-selector/dist/videojs-hls-quality-selector.css" rel="stylesheet">
|
||||
<link href="/thrimbletrimmer/plugins/videojs-trimming-controls/dist/videojs-trimming-controls.css" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
<!-- <script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script> -->
|
||||
<script src="/thrimbletrimmer/plugins/video.js/dist/video.min.js"></script>
|
||||
<script src="/thrimbletrimmer/plugins/videojs-contrib-quality-levels/dist/videojs-contrib-quality-levels.min.js"></script>
|
||||
<script src="/thrimbletrimmer/plugins/videojs-hls-quality-selector/dist/videojs-hls-quality-selector.min.js"></script>
|
||||
<script src="/thrimbletrimmer/plugins/videojs-trimming-controls/dist/videojs-trimming-controls.js"></script>
|
||||
|
||||
<script src="https://apis.google.com/js/platform.js?onload=onGLoad" async defer></script>
|
||||
|
||||
<link href="/thrimbletrimmer/styles/style.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div style="max-width:1280px;margin:auto;padding-top:25px;">
|
||||
<table id="wubloaderInputTable">
|
||||
<tr>
|
||||
<th>Stream</th>
|
||||
<th>Start Time</th>
|
||||
<th>End Time</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input id="StreamName" value="desertbus" /></td>
|
||||
<td><input id="StreamStart" value="0:10:00" />
|
||||
<td><input id="StreamEnd" value="" />
|
||||
<td><input type="button" value="Load Playlist" onclick="loadPlaylist(true)" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>
|
||||
<input type="radio" id="BusTimeToggleUTC" name="BusTimeToggle" value="UTC" onclick="toggleTimeInput(this.value)"> UTC
|
||||
<input type="radio" id="BusTimeToggleBus" name="BusTimeToggle" value="BUSTIME" onclick="toggleTimeInput(this.value)" checked="checked"> Bustime
|
||||
<input type="radio" id="BusTimeToggleDelay" name="BusTimeToggle" value="AGO" onclick="toggleTimeInput(this.value)" > Time Ago
|
||||
</td>
|
||||
<td><a id="AdvancedOptionsButton" href="JavaScript:toggleHiddenPane('wubloaderAdvancedInputTable');">Advanced Submit Options</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<table id="wubloaderAdvancedInputTable" style="display:none;">
|
||||
<tr>
|
||||
<td><a href="#" onclick="window.open('/files');">Streams</a></td>
|
||||
<td><a href="#" onclick="window.open('/files/' + document.getElementById('StreamName').value + '/source', '_blank');">Hours</a></td>
|
||||
</tr>
|
||||
<tr><td>Allow Holes: </td><td><input id="AllowHoles" type="checkbox" /></td></tr>
|
||||
<tr><td>Quality Level: </td><td><select id="qualityLevel"></select></td></tr>
|
||||
<tr><td>Upload Location: </td><td><select id="uploadLocation"></select></td></tr>
|
||||
<tr><td>Uploader Whitelist: </td><td><input id="uploaderWhitelist" title="Uploader Whitelist" /></td></tr>
|
||||
<tr>
|
||||
<td>ThrimShim ID:</td>
|
||||
<td><input id="hiddenSubmissionID" value="" /></td>
|
||||
<td><input type="button" value="Load Event" onclick="window.location.search = '?id='+document.getElementById('hiddenSubmissionID').value"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div id="EditorContainer">
|
||||
<video id="my-player" class="video-js" controls preload="auto" style="display:none">
|
||||
<p class="vjs-no-js">To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="http://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a></p>
|
||||
</video>
|
||||
</div>
|
||||
|
||||
<div id="EditorDetailsPane">
|
||||
<img id="Waveform" style="width: 100%">
|
||||
<div id="EditNotesPane" style="display:none">
|
||||
Edit Notes: <br/>
|
||||
<textarea id="EditNotes" disabled ></textarea>
|
||||
</div>
|
||||
<div>
|
||||
Title: <br />
|
||||
<input type="text" id="VideoTitlePrefix" value="DB2019 - " disabled />
|
||||
<input type="text" id="VideoTitle" value="" maxlength="82" />
|
||||
</div>
|
||||
<div>
|
||||
Description:<br/>
|
||||
<textarea id="VideoDescription" ></textarea>
|
||||
</div>
|
||||
<div>
|
||||
Tags (comma-seperated):
|
||||
<input type="text" id="VideoTags" onblur="round_trip_tag_string()" />
|
||||
<br/>
|
||||
Note that tag edits made here apply only to the uploaded video. Playlists are populated based on the tags in the sheet.
|
||||
</div>
|
||||
<input type="button" id="SubmitButton" value="Submit" onclick="thrimbletrimmerSubmit('EDITED')"/>
|
||||
<input type="button" id="DraftButton" value="Save Draft" onclick="thrimbletrimmerSubmit('UNEDITED')"/>
|
||||
<input type="button" id="DownloadButton" value="Create download link" onclick="thrimbletrimmerDownload(true)"/>
|
||||
<a href="/thrimbletrimmer/dashboard.html">Go To Dashboard</a> |
|
||||
<a href="/thrimbletrimmer/stream.html">Go to Re-stream View</a> |
|
||||
<a id="ManualLinkButton" href="JavaScript:toggleHiddenPane('ManualLinkPane');">Manual Link</a> |
|
||||
<a id="CancelButton" href="JavaScript:thrimbletrimmerResetLink(false);">Cancel Upload</a> |
|
||||
<a id="ResetButton" href="JavaScript:thrimbletrimmerResetLink(true);">Force Reset Row</a>
|
||||
<a id="HelpButton" style="float:right;" href="JavaScript:toggleHiddenPane('HelpPane');">Help</a>
|
||||
<a id="UltrawideButton" style="float:right;margin-right:10px;" href="JavaScript:toggleUltrawide();">Ultrawide</a>
|
||||
<br/>
|
||||
Download type:
|
||||
<select id="DownloadType">
|
||||
<option value="rough" selected>Rough (fastest, pads start and end by a few seconds)</option>
|
||||
<option value="fast">Fast (may have artifacts a few seconds in from start and end)</option>
|
||||
<option value="mpegts">MPEG-TS (slow, consumes server resources)</option>
|
||||
</select>
|
||||
<a id="DownloadLink" href="" style="display:none">Right click here and Save Link As to Download</a>
|
||||
</div>
|
||||
<div id="ManualLinkPane" style="display:none">
|
||||
<input id="ManualLink" /> <input type="button" id="ManualButton" onclick="thrimbletrimmerManualLink()" value="Set Link" />
|
||||
Is Youtube Upload (add to playlists)? <input id="ManualYoutube" type="checkbox" />
|
||||
<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>
|
||||
<li>-/+ - Slow Down, Speed Up</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="/thrimbletrimmer/scripts/playerSetup.js"></script>
|
||||
<script src="/thrimbletrimmer/scripts/keyboardShortcuts.js"></script>
|
||||
<script src="/thrimbletrimmer/scripts/IO.js"></script>
|
||||
|
||||
<script>pageSetup(true);</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>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>VST Restreamer</title>
|
||||
|
||||
<link rel="stylesheet" href="styles/thrimbletrimmer.css" />
|
||||
<link rel="stylesheet" href="videojs/video-js.min.css" />
|
||||
|
||||
<script src="videojs/video.min.js"></script>
|
||||
<script src="scripts/common.js"></script>
|
||||
<script src="scripts/stream.js"></script>
|
||||
<script src="scripts/keyboard-shortcuts.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="errors"></div>
|
||||
<form id="stream-time-settings">
|
||||
<div>
|
||||
<label for="stream-time-setting-stream" class="field-label">Stream</label>
|
||||
<input type="text" id="stream-time-setting-stream" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="stream-time-setting-start" class="field-label">Start Time</label>
|
||||
<input type="text" id="stream-time-setting-start" value="0:10:00" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="stream-time-setting-end" class="field-label">End Time</label>
|
||||
<input type="text" id="stream-time-setting-end" />
|
||||
</div>
|
||||
<div>
|
||||
<div id="stream-time-frame-of-reference">
|
||||
<input
|
||||
type="radio"
|
||||
name="time-frame-of-reference"
|
||||
id="stream-time-frame-of-reference-utc"
|
||||
value="1"
|
||||
/>
|
||||
<label for="stream-time-frame-of-reference-utc">UTC</label>
|
||||
<input
|
||||
type="radio"
|
||||
name="time-frame-of-reference"
|
||||
id="stream-time-frame-of-reference-bus"
|
||||
value="2"
|
||||
/>
|
||||
<label for="stream-time-frame-of-reference-bus">Bus Time</label>
|
||||
<input
|
||||
type="radio"
|
||||
name="time-frame-of-reference"
|
||||
id="stream-time-frame-of-reference-ago"
|
||||
value="3"
|
||||
checked
|
||||
/>
|
||||
<label for="stream-time-frame-of-reference-ago">Time Ago</label>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<button id="stream-time-settings-submit" type="submit">Load Playlist</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<video id="video" class="video-js" controls preload="auto"></video>
|
||||
|
||||
<div id="editor-help">
|
||||
<a href="#" id="editor-help-link">Help</a>
|
||||
<div id="editor-help-box" class="hidden">
|
||||
<h2>Keyboard Shortcuts</h2>
|
||||
<ul>
|
||||
<li>Number keys (0-9): Jump to that 10% interval of the video (0% - 90%)</li>
|
||||
<li>K or Space: Toggle pause</li>
|
||||
<li>J: Back 10 seconds</li>
|
||||
<li>L: Forward 10 seconds</li>
|
||||
<li>Left arrow: Back 5 seconds</li>
|
||||
<li>Right arrow: Forward 5 seconds</li>
|
||||
<li>Comma (,): Back 1 frame</li>
|
||||
<li>Period (.): Forward 1 frame</li>
|
||||
<li>Equals (=): Increase playback speed one step</li>
|
||||
<li>Hyphen (-): Decrease playback speed one step</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<a href="#" id="download">Download Video</a>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -1,2 +0,0 @@
|
||||
/*! @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});
|
@ -1,7 +0,0 @@
|
||||
/**
|
||||
* 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}
|
@ -1,456 +0,0 @@
|
||||
/*! @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;
|
@ -1 +0,0 @@
|
||||
.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}
|
@ -1,452 +0,0 @@
|
||||
/*! @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;
|
@ -1,460 +0,0 @@
|
||||
/*! @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;
|
||||
|
||||
})));
|
@ -1,510 +0,0 @@
|
||||
let desertBusStart = new Date("1970-01-01T00:00:00Z");
|
||||
let timeFormat = "AGO";
|
||||
|
||||
function pageSetup(isEditor) {
|
||||
//Get values from ThrimShim
|
||||
if (isEditor && /id=/.test(document.location.search)) {
|
||||
const rowId = /id=(.*)(?:&|$)/.exec(document.location.search)[1];
|
||||
fetch(`/thrimshim/${rowId}`)
|
||||
.then(data => data.json())
|
||||
.then(function (data) {
|
||||
if (!data) {
|
||||
alert("No video available for stream.");
|
||||
return;
|
||||
}
|
||||
document.data = data;
|
||||
desertBusStart = new Date(data.bustime_start);
|
||||
document.getElementById("VideoTitlePrefix").value = data.title_prefix;
|
||||
document.getElementById("VideoTitle").setAttribute("maxlength", data.title_max_length);
|
||||
|
||||
document.getElementById("StreamName").value = data.video_channel;
|
||||
document.getElementById("hiddenSubmissionID").value = data.id;
|
||||
// for editor, switch to bustime since that's the default
|
||||
timeFormat = "BUSTIME";
|
||||
// Apply padding - start 1min early, finish 2min late because these times are generally
|
||||
// rounded down to the minute, so if something ends at "00:10" it might actually end
|
||||
// at 00:10:59 so we should pad to 00:12:00.
|
||||
const start = data.event_start
|
||||
? new Date(fromTimestamp(data.event_start).getTime() - 60 * 1000)
|
||||
: null;
|
||||
const end = data.event_end
|
||||
? new Date(fromTimestamp(data.event_end).getTime() + 2 * 60 * 1000)
|
||||
: null;
|
||||
setTimeRange(start, end);
|
||||
// title and description both default to row description
|
||||
document.getElementById("VideoTitle").value = data.video_title
|
||||
? data.video_title
|
||||
: data.description;
|
||||
document.getElementById("VideoDescription").value = data.video_description
|
||||
? data.video_description
|
||||
: data.description;
|
||||
// tags default to tags from sheet
|
||||
document.getElementById("VideoTags").value = tags_list_to_string(
|
||||
data.video_tags ? data.video_tags : data.tags
|
||||
);
|
||||
|
||||
// If any edit notes, show them
|
||||
if (data.notes.length > 0) {
|
||||
document.getElementById("EditNotes").value = data.notes;
|
||||
document.getElementById("EditNotesPane").style.display = "block";
|
||||
}
|
||||
|
||||
// Restore advanced options. If any of these are non-default, automatically expand the advanced options pane.
|
||||
setOptions("uploadLocation", data.upload_locations, data.upload_location);
|
||||
document.getElementById("AllowHoles").checked = data.allow_holes;
|
||||
document.getElementById("uploaderWhitelist").value = !!data.uploader_whitelist
|
||||
? data.uploader_whitelist.join(",")
|
||||
: "";
|
||||
if (
|
||||
(data.upload_locations.length > 0 &&
|
||||
data.upload_location != null &&
|
||||
data.upload_location != data.upload_locations[0]) ||
|
||||
data.allow_holes ||
|
||||
!!data.uploader_whitelist
|
||||
) {
|
||||
document.getElementById("wubloaderAdvancedInputTable").style.display = "block";
|
||||
}
|
||||
|
||||
const [ video_start, video_end ] = data.video_ranges === null ? [] : data.video_ranges[0];
|
||||
loadPlaylist(isEditor, video_start, video_end, data.video_quality);
|
||||
});
|
||||
} else {
|
||||
if (isEditor) {
|
||||
document.getElementById("SubmitButton").disabled = true;
|
||||
}
|
||||
|
||||
fetch("/thrimshim/defaults")
|
||||
.then(data => data.json())
|
||||
.then(function (data) {
|
||||
if (!data) {
|
||||
alert("Editor results call failed, is thrimshim running?");
|
||||
return;
|
||||
}
|
||||
desertBusStart = new Date(data.bustime_start);
|
||||
document.getElementById("StreamName").value = data.video_channel;
|
||||
if (isEditor) {
|
||||
document.getElementById("VideoTitlePrefix").value = data.title_prefix;
|
||||
document.getElementById("VideoTitle").setAttribute("maxlength", data.title_max_length);
|
||||
setOptions("uploadLocation", data.upload_locations);
|
||||
}
|
||||
|
||||
// Default time format changes depending on mode.
|
||||
// But in both cases the default input value is 10min ago / "",
|
||||
// it's just for editor we convert it before the user sees.
|
||||
if (isEditor) {
|
||||
toggleTimeInput("BUSTIME");
|
||||
}
|
||||
|
||||
loadPlaylist(isEditor);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Time-formatting functions
|
||||
|
||||
function parseDuration(duration) {
|
||||
let direction = 1;
|
||||
if (duration.startsWith("-")) {
|
||||
duration = duration.slice(1);
|
||||
direction = -1;
|
||||
}
|
||||
const [hours, mins, secs] = duration.split(":");
|
||||
return (3600 * parseInt(hours) + 60 * (parseInt(mins) || 0) + (parseFloat(secs) || 0)) * direction;
|
||||
}
|
||||
|
||||
function toBustime(date) {
|
||||
return (
|
||||
(date < desertBusStart ? "-" : "") +
|
||||
videojs.formatTime(Math.abs((date - desertBusStart) / 1000), 600.01).padStart(7, "0:")
|
||||
);
|
||||
}
|
||||
|
||||
function fromBustime(bustime) {
|
||||
return new Date(desertBusStart.getTime() + 1000 * parseDuration(bustime));
|
||||
}
|
||||
|
||||
function toTimestamp(date) {
|
||||
return date.toISOString().substring(0, 19);
|
||||
}
|
||||
|
||||
function fromTimestamp(ts) {
|
||||
return new Date(ts + "Z");
|
||||
}
|
||||
|
||||
function toAgo(date) {
|
||||
now = new Date();
|
||||
return (
|
||||
(date < now ? "" : "-") +
|
||||
videojs.formatTime(Math.abs((date - now) / 1000), 600.01).padStart(7, "0:")
|
||||
);
|
||||
}
|
||||
|
||||
function fromAgo(ago) {
|
||||
return new Date(new Date().getTime() - 1000 * parseDuration(ago));
|
||||
}
|
||||
|
||||
// Set the stream start/end range from a pair of Dates using the current format
|
||||
// If given null, sets to blank.
|
||||
function setTimeRange(start, end) {
|
||||
const toFunc = {
|
||||
UTC: toTimestamp,
|
||||
BUSTIME: toBustime,
|
||||
AGO: toAgo,
|
||||
}[timeFormat];
|
||||
document.getElementById("StreamStart").value = start ? toFunc(start) : "";
|
||||
document.getElementById("StreamEnd").value = end ? toFunc(end) : "";
|
||||
}
|
||||
|
||||
// Get the current start/end range as Dates using the current format
|
||||
// Returns an object containing 'start' and 'end' fields.
|
||||
// If either is empty / invalid, returns null.
|
||||
function getTimeRange() {
|
||||
const fromFunc = {
|
||||
UTC: fromTimestamp,
|
||||
BUSTIME: fromBustime,
|
||||
AGO: fromAgo,
|
||||
}[timeFormat];
|
||||
function convert(value) {
|
||||
if (!value) {
|
||||
return null;
|
||||
}
|
||||
const date = fromFunc(value);
|
||||
return isNaN(date) ? null : date;
|
||||
}
|
||||
return {
|
||||
start: convert(document.getElementById("StreamStart").value),
|
||||
end: convert(document.getElementById("StreamEnd").value),
|
||||
};
|
||||
}
|
||||
|
||||
function getTimeRangeAsTimestamp() {
|
||||
const range = getTimeRange();
|
||||
return {
|
||||
// if not null, format as timestamp
|
||||
start: range.start && toTimestamp(range.start),
|
||||
end: range.end && toTimestamp(range.end),
|
||||
};
|
||||
}
|
||||
|
||||
function toggleHiddenPane(paneID) {
|
||||
const pane = document.getElementById(paneID);
|
||||
pane.style.display = pane.style.display === "none" ? "block" : "none";
|
||||
}
|
||||
|
||||
function toggleUltrawide() {
|
||||
const body = document.getElementsByTagName("Body")[0];
|
||||
body.classList.contains("ultrawide")
|
||||
? body.classList.remove("ultrawide")
|
||||
: body.classList.add("ultrawide");
|
||||
}
|
||||
|
||||
function toggleTimeInput(toggleInput) {
|
||||
// Get times using current format, then change format, then write them back
|
||||
const range = getTimeRange();
|
||||
timeFormat = toggleInput;
|
||||
setTimeRange(range.start, range.end);
|
||||
}
|
||||
|
||||
// For a given select input element id, add the given list of options.
|
||||
// If selected is given, it should be the name of an option to select.
|
||||
// Otherwise the first one is used.
|
||||
function setOptions(element, options, selected) {
|
||||
if (!selected && options.length > 0) {
|
||||
selected = options[0];
|
||||
}
|
||||
options.forEach(option => {
|
||||
const maybeSelected = option == selected ? "selected" : "";
|
||||
const optionHTML = `<option value="${option}" ${maybeSelected}>${option}</option>`;
|
||||
document.getElementById(element).innerHTML += optionHTML;
|
||||
});
|
||||
}
|
||||
|
||||
function buildQuery(params) {
|
||||
return Object.keys(params)
|
||||
.filter(key => params[key] !== null)
|
||||
.map(key => encodeURIComponent(key) + "=" + encodeURIComponent(params[key]))
|
||||
.join("&");
|
||||
}
|
||||
|
||||
function loadPlaylist(isEditor, startTrim, endTrim, defaultQuality) {
|
||||
const stream = document.getElementById("StreamName").value;
|
||||
const playlist = `/playlist/${stream}.m3u8`;
|
||||
|
||||
const range = getTimeRangeAsTimestamp();
|
||||
const queryString = buildQuery(range);
|
||||
|
||||
// Preserve existing edit times
|
||||
if (player && player.trimmingControls && player.vhs.playlists.master) {
|
||||
const discontinuities = mapDiscontinuities();
|
||||
if (!startTrim) {
|
||||
startTrim = getRealTimeForPlayerTime(
|
||||
discontinuities,
|
||||
player.trimmingControls().options.startTrim
|
||||
);
|
||||
if (startTrim) {
|
||||
startTrim = startTrim.replace("Z", "");
|
||||
}
|
||||
}
|
||||
if (!endTrim) {
|
||||
endTrim = getRealTimeForPlayerTime(
|
||||
discontinuities,
|
||||
player.trimmingControls().options.endTrim
|
||||
);
|
||||
if (endTrim) {
|
||||
endTrim = endTrim.replace("Z", "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setupPlayer(isEditor, playlist + "?" + queryString, startTrim, endTrim);
|
||||
|
||||
//Get quality levels for advanced properties / download
|
||||
document.getElementById("qualityLevel").innerHTML = "";
|
||||
fetch(`/files/${stream}`)
|
||||
.then(data => data.json())
|
||||
.then(function (data) {
|
||||
if (!data.length) {
|
||||
console.log("Could not retrieve quality levels");
|
||||
return;
|
||||
}
|
||||
var qualityLevels = data.sort().reverse();
|
||||
setOptions("qualityLevel", qualityLevels, defaultQuality);
|
||||
if (!!defaultQuality && qualityLevels.length > 0 && defaultQuality != qualityLevels[0]) {
|
||||
document.getElementById("wubloaderAdvancedInputTable").style.display = "block";
|
||||
}
|
||||
});
|
||||
|
||||
// Get audio waveform. Note we assume "source" is a valid quality.
|
||||
const waveformURL = `/waveform/${stream}/source.png?${buildQuery(range)}`;
|
||||
document.getElementById("Waveform").setAttribute("src", waveformURL);
|
||||
}
|
||||
|
||||
function thrimbletrimmerSubmit(state, override_changes = false) {
|
||||
document.getElementById("SubmitButton").disabled = true;
|
||||
const discontinuities = mapDiscontinuities();
|
||||
|
||||
let start = getRealTimeForPlayerTime(
|
||||
discontinuities,
|
||||
player.trimmingControls().options.startTrim
|
||||
);
|
||||
if (start) {
|
||||
start = start.replace("Z", "");
|
||||
}
|
||||
let end = getRealTimeForPlayerTime(discontinuities, player.trimmingControls().options.endTrim);
|
||||
if (end) {
|
||||
end = end.replace("Z", "");
|
||||
}
|
||||
|
||||
const wubData = {
|
||||
video_ranges: [[start, end]],
|
||||
video_transitions: [],
|
||||
video_title: document.getElementById("VideoTitle").value,
|
||||
video_description: document.getElementById("VideoDescription").value,
|
||||
video_tags: tags_string_to_list(document.getElementById("VideoTags").value),
|
||||
allow_holes: document.getElementById("AllowHoles").checked,
|
||||
upload_location: document.getElementById("uploadLocation").value,
|
||||
video_channel: document.getElementById("StreamName").value,
|
||||
video_quality:
|
||||
document.getElementById("qualityLevel").options[
|
||||
document.getElementById("qualityLevel").options.selectedIndex
|
||||
].value,
|
||||
uploader_whitelist: document.getElementById("uploaderWhitelist").value
|
||||
? document.getElementById("uploaderWhitelist").value.split(",")
|
||||
: null,
|
||||
state: state,
|
||||
//pass back the sheet columns to check if any have changed
|
||||
sheet_name: document.data.sheet_name,
|
||||
event_start: document.data.event_start,
|
||||
event_end: document.data.event_end,
|
||||
category: document.data.category,
|
||||
description: document.data.description,
|
||||
notes: document.data.notes,
|
||||
tags: document.data.tags,
|
||||
};
|
||||
if (!!user) {
|
||||
wubData.token = user.getAuthResponse().id_token;
|
||||
}
|
||||
if (override_changes) {
|
||||
wubData.override_changes = true;
|
||||
}
|
||||
console.log("Submitting", wubData);
|
||||
|
||||
if (!wubData.video_ranges[0][0]) {
|
||||
alert("No start time set");
|
||||
return;
|
||||
}
|
||||
if (!wubData.video_ranges[0][1]) {
|
||||
alert("No end time set");
|
||||
return;
|
||||
}
|
||||
|
||||
//Submit to thrimshim
|
||||
const rowId = /id=(.*)(?:&|$)/.exec(document.location.search)[1];
|
||||
fetch(`/thrimshim/${rowId}`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(wubData),
|
||||
}).then(response =>
|
||||
response.text().then(text => {
|
||||
if (!response.ok) {
|
||||
if (response.status == 409) {
|
||||
dialogue = text + "\nClick Ok to submit anyway; Click Cancel to return to editing";
|
||||
if (confirm(dialogue)) {
|
||||
thrimbletrimmerSubmit(state, true);
|
||||
}
|
||||
} else {
|
||||
const error = `${response.statusText}: ${text}`;
|
||||
console.log("Failed to submit:", error);
|
||||
alert(error);
|
||||
}
|
||||
} else if (state == "EDITED") {
|
||||
alert(`Edit submitted for video from ${start} to ${end}`);
|
||||
} else {
|
||||
alert("Draft saved");
|
||||
}
|
||||
document.getElementById("SubmitButton").disabled = false;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
function thrimbletrimmerDownload(isEditor) {
|
||||
const range = getTimeRangeAsTimestamp();
|
||||
if (isEditor) {
|
||||
if (player.trimmingControls().options.startTrim >= player.trimmingControls().options.endTrim) {
|
||||
alert("End Time must be greater than Start Time");
|
||||
return;
|
||||
}
|
||||
const discontinuities = mapDiscontinuities();
|
||||
range.start = getRealTimeForPlayerTime(
|
||||
discontinuities,
|
||||
player.trimmingControls().options.startTrim
|
||||
);
|
||||
range.end = getRealTimeForPlayerTime(
|
||||
discontinuities,
|
||||
player.trimmingControls().options.endTrim
|
||||
);
|
||||
}
|
||||
|
||||
const stream = document.getElementById("StreamName").value;
|
||||
const quality =
|
||||
document.getElementById("qualityLevel").options[
|
||||
document.getElementById("qualityLevel").options.selectedIndex
|
||||
].value;
|
||||
const query = buildQuery({
|
||||
start: range.start,
|
||||
end: range.end,
|
||||
// In non-editor, always use rough cut. They don't have the edit controls to do
|
||||
// fine time selection anyway.
|
||||
type: isEditor
|
||||
? document.getElementById("DownloadType").options[
|
||||
document.getElementById("DownloadType").options.selectedIndex
|
||||
].value
|
||||
: "rough",
|
||||
// Always allow holes in non-editor, accidentially including holes isn't important
|
||||
allow_holes: isEditor ? String(document.getElementById("AllowHoles").checked) : "true",
|
||||
});
|
||||
const targetURL = `/cut/${stream}/${quality}.ts?${query}`;
|
||||
document.getElementById("DownloadLink").href = targetURL;
|
||||
document.getElementById("DownloadLink").style.display = "";
|
||||
}
|
||||
|
||||
function thrimbletrimmerManualLink() {
|
||||
document.getElementById("ManualButton").disabled = true;
|
||||
const rowId = /id=(.*)(?:&|$)/.exec(document.location.search)[1];
|
||||
const upload_location = document.getElementById("ManualYoutube").checked
|
||||
? "youtube-manual"
|
||||
: "manual";
|
||||
const body = {
|
||||
link: document.getElementById("ManualLink").value,
|
||||
upload_location: upload_location,
|
||||
};
|
||||
if (!!user) {
|
||||
body.token = user.getAuthResponse().id_token;
|
||||
}
|
||||
fetch(`/thrimshim/manual-link/${rowId}`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
})
|
||||
.then(response => response.text())
|
||||
.then(text => {
|
||||
if (!response.ok) {
|
||||
const error = `${response.statusText}: ${text}`;
|
||||
console.log("Failed to set manual link:", error);
|
||||
alert(error);
|
||||
document.getElementById("ManualButton").disabled = false;
|
||||
} else {
|
||||
alert(`Manual link set to ${body.link}`);
|
||||
setTimeout(() => {
|
||||
window.location.href = "/thrimbletrimmer/dashboard.html";
|
||||
}, 500);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function thrimbletrimmerResetLink(force) {
|
||||
const rowId = /id=(.*)(?:&|$)/.exec(document.location.search)[1];
|
||||
if (
|
||||
force &&
|
||||
!confirm(
|
||||
"Are you sure you want to reset this event? " +
|
||||
"This will set the row back to UNEDITED and forget about any video that already may exist. " +
|
||||
"It is intended as a last-ditch command to clear a malfunctioning cutter, " +
|
||||
"or if a video needs to be re-edited and replaced. " +
|
||||
"IT IS YOUR RESPONSIBILITY TO DEAL WITH ANY VIDEO THAT MAY HAVE ALREADY BEEN UPLOADED. "
|
||||
)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
document.getElementById("ResetButton").disabled = true;
|
||||
document.getElementById("CancelButton").disabled = true;
|
||||
const body = {};
|
||||
if (!!user) {
|
||||
body.token = user.getAuthResponse().id_token;
|
||||
}
|
||||
fetch(`/thrimshim/reset/${rowId}?force=${force}`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
})
|
||||
.then(response => response.text())
|
||||
.then(text => {
|
||||
if (!response.ok) {
|
||||
const error = `${response.statusText}: ${text}`;
|
||||
console.log("Failed to reset:", error);
|
||||
alert(error);
|
||||
document.getElementById("ResetButton").disabled = false;
|
||||
document.getElementById("CancelButton").disabled = true;
|
||||
} else {
|
||||
alert(`Row has been ${force ? "reset" : "cancelled"}. Reloading...`);
|
||||
setTimeout(() => {
|
||||
window.location.reload();
|
||||
}, 500);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function tags_list_to_string(tag_list) {
|
||||
return tag_list.join(", ");
|
||||
}
|
||||
|
||||
function tags_string_to_list(tag_string) {
|
||||
return tag_string
|
||||
.split(",")
|
||||
.map(tag => tag.trim())
|
||||
.filter(tag => tag.length > 0);
|
||||
}
|
||||
|
||||
function round_trip_tag_string() {
|
||||
const element = document.getElementById("VideoTags");
|
||||
element.value = tags_list_to_string(tags_string_to_list(element.value));
|
||||
}
|
@ -1,98 +0,0 @@
|
||||
function changeSpeed(direction) {
|
||||
const speeds = [0.5, 1, 1.25, 1.5, 2];
|
||||
const currentIndex = speeds.indexOf(player.playbackRate());
|
||||
if (currentIndex < 0) {
|
||||
// not present
|
||||
return;
|
||||
}
|
||||
const newIndex = currentIndex + direction;
|
||||
if (newIndex < 0 || newIndex >= speeds.length) {
|
||||
// out of range
|
||||
return;
|
||||
}
|
||||
player.playbackRate(speeds[newIndex]);
|
||||
}
|
||||
|
||||
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":
|
||||
case " ": // also pause on space
|
||||
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 "=":
|
||||
changeSpeed(1);
|
||||
break;
|
||||
case "-":
|
||||
changeSpeed(-1);
|
||||
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;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//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;
|
||||
}
|
||||
}
|
||||
});
|
@ -1,102 +0,0 @@
|
||||
let player = null;
|
||||
|
||||
function setupPlayer(isEditor, 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.
|
||||
const options = {
|
||||
sources: [{src: source}],
|
||||
liveui: true,
|
||||
controls: true,
|
||||
autoplay: false,
|
||||
width: 1280,
|
||||
height: 420,
|
||||
playbackRates: [0.5, 1, 1.25, 1.5, 2],
|
||||
inactivityTimeout: 0,
|
||||
controlBar: {
|
||||
fullscreenToggle: true,
|
||||
volumePanel: {
|
||||
inline: false,
|
||||
},
|
||||
},
|
||||
};
|
||||
if (player) {
|
||||
//Destroy and recreate the player if it already exists.
|
||||
player.dispose();
|
||||
document.getElementById("EditorContainer").innerHTML = `
|
||||
<video id="my-player" class="video-js" controls disablePictureInPicture preload="auto">
|
||||
<p class="vjs-no-js">To view this video please enable JavaScript, and consider upgrading to a web browser that <a href="http://videojs.com/html5-video-support/" target="_blank">supports HTML5 video</a></p>
|
||||
</video>
|
||||
`;
|
||||
}
|
||||
player = videojs("my-player", options, function onPlayerReady() {
|
||||
videojs.log("Video player is ready");
|
||||
|
||||
// Set player volume to 50% by default
|
||||
const defaultVolume = 0.5;
|
||||
this.volume(defaultVolume);
|
||||
|
||||
this.vhs.playlists.on("loadedmetadata", function () {
|
||||
player.hasStarted(true); //So it displays all the controls.
|
||||
if (isEditor) {
|
||||
const stream_start = player.vhs.playlists.master.playlists.filter(
|
||||
playlist => typeof playlist.discontinuityStarts !== "undefined"
|
||||
)[0].dateTimeObject;
|
||||
startTrim = startTrim ? (new Date(startTrim + "Z") - stream_start) / 1000 : 0;
|
||||
endTrim = endTrim ? (new Date(endTrim + "Z") - stream_start) / 1000 : player.duration();
|
||||
const trimmingControls = player.trimmingControls({startTrim: startTrim, endTrim: endTrim});
|
||||
}
|
||||
});
|
||||
|
||||
this.on("error", function () {
|
||||
videojs.log("Could not load video stream");
|
||||
alert("No video available for stream.");
|
||||
});
|
||||
});
|
||||
const hlsQS = player.hlsQualitySelector();
|
||||
}
|
||||
|
||||
function mapDiscontinuities() {
|
||||
const 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.
|
||||
const discontinuities = playlist.discontinuityStarts.map(segmentIndex => {
|
||||
return {
|
||||
segmentIndex: segmentIndex,
|
||||
segmentTimestamp: playlist.segments[segmentIndex].dateTimeObject,
|
||||
playbackIndex: null,
|
||||
};
|
||||
});
|
||||
const lastDiscontinuity = playlist.discontinuityStarts.slice(-1).pop(); //Assumes discontinuities are sorted in ascending order.
|
||||
|
||||
let durationMarker = 0;
|
||||
for (let index = 0; index <= lastDiscontinuity; index++) {
|
||||
const segment = playlist.segments[index];
|
||||
if (segment.discontinuity) {
|
||||
discontinuities.find(discontinuity => discontinuity.segmentIndex == index).playbackIndex =
|
||||
durationMarker;
|
||||
}
|
||||
durationMarker += segment.duration;
|
||||
}
|
||||
|
||||
return discontinuities;
|
||||
}
|
||||
|
||||
function getRealTimeForPlayerTime(discontinuities, playbackIndex) {
|
||||
let 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
|
||||
const lastDiscontinuity = discontinuities
|
||||
.filter(discontinuity => discontinuity.playbackIndex < playbackIndex)
|
||||
.slice(-1)
|
||||
.pop();
|
||||
if (lastDiscontinuity) {
|
||||
streamStart = lastDiscontinuity.segmentTimestamp;
|
||||
playbackIndex -= lastDiscontinuity.playbackIndex;
|
||||
}
|
||||
|
||||
const realTime = streamStart.getTime() + playbackIndex * 1000;
|
||||
|
||||
return isFinite(realTime) ? new Date(realTime).toISOString() : null;
|
||||
}
|
@ -1,82 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<title>VST Re-stream</title>
|
||||
<meta name="description" content="">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<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="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
|
||||
<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>
|
||||
|
||||
<link href="/thrimbletrimmer/styles/style.css" rel="stylesheet">
|
||||
</head>
|
||||
<body>
|
||||
<div style="max-width:1280px;margin:auto;padding-top:25px;">
|
||||
<table id="wubloaderInputTable">
|
||||
<tr>
|
||||
<th>Stream</th>
|
||||
<th>Start Time</th>
|
||||
<th>End Time (blank for live)</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input id="StreamName" value="desertbus" /></td>
|
||||
<td><input id="StreamStart" value="0:10:00" />
|
||||
<td><input id="StreamEnd" value="" />
|
||||
<td><input type="button" value="Load Playlist" onclick="loadPlaylist()" /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>
|
||||
<input type="radio" id="BusTimeToggleUTC" name="BusTimeToggle" value="UTC" onclick="toggleTimeInput(this.value)"> UTC
|
||||
<input type="radio" id="BusTimeToggleBus" name="BusTimeToggle" value="BUSTIME" onclick="toggleTimeInput(this.value)"> Bustime
|
||||
<input type="radio" id="BusTimeToggleDelay" name="BusTimeToggle" value="AGO" onclick="toggleTimeInput(this.value)" checked="checked"> Time Ago
|
||||
</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="InfoPane">
|
||||
<br/>
|
||||
When no end time is set, the stream will continue to play as it arrives.</br>
|
||||
Trying to watch live will result in buffering, as those segments haven't been captured yet.<br/>
|
||||
If you watch for a long time, it may become difficult to navigate on the video bar because there's too long a time loaded.
|
||||
To fix this, re-load the video in the desired time range (default: the last 10 minutes) by clicking Load Playlist.<br/>
|
||||
Download Quality: <select id="qualityLevel"></select>
|
||||
<input type="button" id="DownloadButton" value="Download this time range" onclick="thrimbletrimmerDownload()"/>
|
||||
<a id="DownloadLink" href="" style="display:none">Right click here and Save Link As to Download</a>
|
||||
<a id="HelpButton" style="float:right;" href="JavaScript:toggleHiddenPane('HelpPane');">Help</a>
|
||||
<a id="UltrawideButton" style="float:right;margin-right:10px;" href="JavaScript:toggleUltrawide();">Ultrawide</a>
|
||||
</div>
|
||||
<div id="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>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>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -1,59 +0,0 @@
|
||||
html, body {
|
||||
height:100%;
|
||||
margin:0px;
|
||||
background-color:darkgrey;
|
||||
}
|
||||
body.ultrawide > div { max-width:100% !important; }
|
||||
body.ultrawide .my-player-dimensions { width:100% !important; }
|
||||
|
||||
.video-js .vjs-control-bar {
|
||||
background-color:#2b333f;
|
||||
}
|
||||
.video-js .vjs-time-control {
|
||||
display: block;
|
||||
}
|
||||
.video-js .vjs-remaining-time {
|
||||
display: none;
|
||||
}
|
||||
.video-js .vjs-current-time.vjs-time-control, .video-js .vjs-duration.vjs-time-control {
|
||||
padding:0em;
|
||||
}
|
||||
.video-js .vjs-progress-control .vjs-mouse-display {
|
||||
z-index: 100;
|
||||
}
|
||||
.vjs-menu-button-popup .vjs-menu {
|
||||
bottom:-3px;
|
||||
}
|
||||
.video-js .vjs-time-display {
|
||||
width: 100px;
|
||||
}
|
||||
.video-js .vjs-picture-in-picture-control {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
#EditorDetailsPane {
|
||||
margin-top:100px;
|
||||
}
|
||||
#EditNotes {
|
||||
width: 100%;
|
||||
background-color: pink;
|
||||
color: black;
|
||||
border: none;
|
||||
}
|
||||
#VideoTitle {
|
||||
width:90%
|
||||
}
|
||||
#VideoTitlePrefix {
|
||||
width:5%;
|
||||
}
|
||||
#VideoDescription {
|
||||
width:98%;
|
||||
}
|
||||
#VideoTags {
|
||||
width:80%;
|
||||
}
|
||||
|
||||
*:focus {
|
||||
outline:none;
|
||||
}
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |