Comparar commits

..

18 Commits

Autor SHA1 Mensagem Data
Gary Katsevman d2d8f8f45f v5.19.2 dist 2017-04-13 17:10:07 -04:00
Gary Katsevman eb05ff7f00 v5.19.2 2017-04-13 17:09:30 -04:00
Matthew Neil 207730ed6f fix: set IE_VERSION correctly for IE11 (#4280)
videojs.browser.IE_VERSION is null in IE11 because IE11 uses a different user agent string than other IE versions

Fixes #4278
2017-04-13 11:27:51 -04:00
Gary Katsevman 969d32551b v5.19.1 2017-03-27 15:29:19 -04:00
Matthew Neil ad770fb196 chore(package): update videojs-vtt.js to 0.12.3 (#4223) 2017-03-24 14:39:05 -04:00
Brandon Casey 3974944007 fix: removeCue should work with native passed in cue (#4209) 2017-03-23 14:32:01 -04:00
Brandon Casey 465392215c fix: not showing default text tracks over video (#4217)
This allows default tracks or tracks with a `mode`of `showing` to be seen
when they are added (as we would expect). Rather than only being seen
after the first `modechange` event (aka a selection from the menu). This is done by watching for `loadstart` on Player.
2017-03-23 14:30:50 -04:00
Gary Katsevman 6cf4ef8545 remove incorrect 5.19.0 changelog entry 2017-03-15 14:53:06 -04:00
Gary Katsevman c1ed22c39f fix CHANGELOG 2017-03-15 14:51:37 -04:00
Gary Katsevman aa7e94ba10 v5.19.0 2017-03-15 14:47:26 -04:00
Gary Katsevman c069655bc5 fix: make sure audio track hides with one item (#4203) 2017-03-15 11:27:59 -04:00
Gary Katsevman 398c6e9dd0 fix: make load progress buffered regions height 100% (#4191) 2017-03-13 11:53:01 -04:00
Brandon Casey 4ec3b56b45 feat: Make pause on open optional for ModalDialog via options (#4187)
* The new option is called pauseOnOpen, and defaults to true
* default pauseOnOpen to false in the `ErrorDisplay`
2017-03-13 11:27:00 -04:00
Gary Katsevman d2b4f1c5b9 v5.18.4 2017-03-08 11:29:38 -05:00
Gary Katsevman ad86eec723 fix(vttjs): wait till tech el in DOM before loading vttjs (#4176) 2017-03-08 11:27:44 -05:00
Gary Katsevman ed378986a5 v5.18.3 2017-03-06 12:14:42 -05:00
Gary Katsevman d2180b0ef8 v5.18.2 2017-03-03 17:20:50 -05:00
Gary Katsevman 841d135db8 fix(cues): only copy cue props that don't exist (#4146) 2017-03-03 17:07:28 -05:00
22 arquivos alterados com 711 adições e 598 exclusões
+41
Ver Arquivo
@@ -1,3 +1,44 @@
<a name="5.19.2"></a>
## [5.19.2](https://github.com/videojs/video.js/compare/v5.19.1...v5.19.2) (2017-04-13)
### Bug Fixes
* set IE_VERSION correctly for IE11 ([#4280](https://github.com/videojs/video.js/issues/4280)) ([207730e](https://github.com/videojs/video.js/commit/207730e)), closes [#4278](https://github.com/videojs/video.js/issues/4278)
<a name="5.19.1"></a>
## [5.19.1](https://github.com/videojs/video.js/compare/v5.19.0...v5.19.1) (2017-03-27)
### Bug Fixes
* not showing default text tracks over video ([#4217](https://github.com/videojs/video.js/issues/4217)) ([4653922](https://github.com/videojs/video.js/commit/4653922))
* removeCue should work with native passed in cue ([#4209](https://github.com/videojs/video.js/issues/4209)) ([3974944](https://github.com/videojs/video.js/commit/3974944))
### Chores
* **package:** update videojs-vtt.js to 0.12.3 ([#4223](https://github.com/videojs/video.js/issues/4223)) ([ad770fb](https://github.com/videojs/video.js/commit/ad770fb))
<a name="5.19.0"></a>
# [5.19.0](https://github.com/videojs/video.js/compare/v5.18.4...v5.19.0) (2017-03-15)
### Features
* Make pause on open optional for ModalDialog via options ([#4187](https://github.com/videojs/video.js/issues/4187)) ([4ec3b56](https://github.com/videojs/video.js/commit/4ec3b56))
### Bug Fixes
* make load progress buffered regions height 100% ([#4191](https://github.com/videojs/video.js/issues/4191)) ([398c6e9](https://github.com/videojs/video.js/commit/398c6e9))
* make sure audio track hides with one item ([#4203](https://github.com/videojs/video.js/issues/4203)) ([c069655](https://github.com/videojs/video.js/commit/c069655))
<a name="5.18.4"></a>
## [5.18.4](https://github.com/videojs/video.js/compare/v5.18.3...v5.18.4) (2017-03-08)
### Bug Fixes
* **vttjs:** wait till tech el in DOM before loading vttjs ([#4176](https://github.com/videojs/video.js/issues/4176)) ([ad86eec](https://github.com/videojs/video.js/commit/ad86eec))
<a name="5.18.3"></a>
## [5.18.3](https://github.com/videojs/video.js/compare/v5.18.2...v5.18.3) (2017-03-06)
<a name="5.18.1"></a>
## [5.18.1](https://github.com/videojs/video.js/compare/v5.18.0...v5.18.1) (2017-03-03)
+1 -1
Ver Arquivo
@@ -1,7 +1,7 @@
{
"name": "video.js",
"description": "An HTML5 and Flash video player with a common API and skin for both.",
"version": "5.18.1",
"version": "5.19.2",
"keywords": [
"videojs",
"html5",
+1 -1
Ver Arquivo
@@ -690,7 +690,7 @@ body.vjs-full-window {
.video-js .vjs-progress-holder .vjs-load-progress div {
position: absolute;
display: block;
height: 0.3em;
height: 100%;
margin: 0;
padding: 0;
width: 0;
+1 -1
Ver Arquivo
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
+58 -34
Ver Arquivo
@@ -1,6 +1,6 @@
/**
* @license
* Video.js 5.18.1 <http://videojs.com/>
* Video.js 5.19.2 <http://videojs.com/>
* Copyright Brightcove, Inc. <https://www.brightcove.com/>
* Available under Apache License Version 2.0
* <https://github.com/videojs/video.js/blob/master/LICENSE>
@@ -2611,6 +2611,9 @@ var AudioTrackButton = function (_TrackButton) {
AudioTrackButton.prototype.createItems = function createItems() {
var items = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
// if there's only one audio track, there no point in showing it
this.hideThreshold_ = 1;
var tracks = this.player_.audioTracks && this.player_.audioTracks();
if (!tracks) {
@@ -5776,6 +5779,7 @@ var TextTrackMenuItem = function (_MenuItem) {
if (tracks) {
var changeHandler = Fn.bind(_this, _this.handleTracksChange);
player.on(['loadstart', 'texttrackchange'], changeHandler);
tracks.addEventListener('change', changeHandler);
_this.on('dispose', function () {
tracks.removeEventListener('change', changeHandler);
@@ -7018,6 +7022,7 @@ var ErrorDisplay = function (_ModalDialog) {
ErrorDisplay.prototype.options_ = (0, _mergeOptions2['default'])(_modalDialog2['default'].prototype.options_, {
pauseOnOpen: false,
fillAlways: true,
temporary: false,
uncloseable: true
@@ -8543,7 +8548,7 @@ var ModalDialog = function (_Component) {
// playing state.
this.wasPlaying_ = !player.paused();
if (this.wasPlaying_) {
if (this.options_.pauseOnOpen && this.wasPlaying_) {
player.pause();
}
@@ -8610,7 +8615,7 @@ var ModalDialog = function (_Component) {
this.trigger('beforemodalclose');
this.opened_ = false;
if (this.wasPlaying_) {
if (this.wasPlaying_ && this.options_.pauseOnOpen) {
player.play();
}
@@ -8808,6 +8813,7 @@ var ModalDialog = function (_Component) {
ModalDialog.prototype.options_ = {
pauseOnOpen: true,
temporary: true
};
@@ -17246,7 +17252,7 @@ var Tech = function (_Component) {
// Initially, Tech.el_ is a child of a dummy-div wait until the Component system
// signals that the Tech is ready at which point Tech.el_ is part of the DOM
// before inserting the WebVTT script
if (this.el().parentNode !== null && this.el().parentNode !== undefined) {
if (_document2['default'].body.contains(this.el())) {
var vtt = {};
// load via require if available and vtt.js script location was not passed in
@@ -17261,7 +17267,7 @@ var Tech = function (_Component) {
// passed in
var script = _document2['default'].createElement('script');
script.src = this.options_['vtt.js'] || 'https://cdn.rawgit.com/gkatsev/vtt.js/vjs-v0.12.1/dist/vtt.min.js';
script.src = this.options_['vtt.js'] || 'https://vjs.zencdn.net/vttjs/0.12.3/vtt.min.js';
script.onload = function () {
/**
* Fired when vtt.js is loaded.
@@ -17341,11 +17347,15 @@ var Tech = function (_Component) {
textTracksChanges();
tracks.addEventListener('change', textTracksChanges);
tracks.addEventListener('addtrack', textTracksChanges);
tracks.addEventListener('removetrack', textTracksChanges);
this.on('dispose', function () {
remoteTracks.off('addtrack', handleAddTrack);
remoteTracks.off('removetrack', handleRemoveTrack);
tracks.removeEventListener('change', textTracksChanges);
tracks.removeEventListener('addtrack', textTracksChanges);
tracks.removeEventListener('removetrack', textTracksChanges);
for (var i = 0; i < tracks.length; i++) {
var track = tracks[i];
@@ -20318,11 +20328,14 @@ var TextTrack = function (_Track) {
cue = new _window2['default'].vttjs.VTTCue(originalCue.startTime, originalCue.endTime, originalCue.text);
for (var prop in originalCue) {
cue[prop] = originalCue[prop];
if (!(prop in cue)) {
cue[prop] = originalCue[prop];
}
}
// make sure that `id` is copied over
cue.id = originalCue.id;
cue.originalCue_ = originalCue;
}
var tracks = this.tech_.textTracks();
@@ -20348,20 +20361,17 @@ var TextTrack = function (_Track) {
TextTrack.prototype.removeCue = function removeCue(_removeCue) {
var removed = false;
var i = this.cues_.length;
for (var i = 0, l = this.cues_.length; i < l; i++) {
while (i--) {
var cue = this.cues_[i];
if (cue === _removeCue) {
if (cue === _removeCue || cue.originalCue_ && cue.originalCue_ === _removeCue) {
this.cues_.splice(i, 1);
removed = true;
this.cues.setCues_(this.cues_);
break;
}
}
if (removed) {
this.cues.setCues_(this.cues_);
}
};
return TextTrack;
@@ -21230,9 +21240,17 @@ var IS_FIREFOX = exports.IS_FIREFOX = /Firefox/i.test(USER_AGENT);
var IS_EDGE = exports.IS_EDGE = /Edge/i.test(USER_AGENT);
var IS_CHROME = exports.IS_CHROME = !IS_EDGE && /Chrome/i.test(USER_AGENT);
var IS_IE8 = exports.IS_IE8 = /MSIE\s8\.0/.test(USER_AGENT);
var IE_VERSION = exports.IE_VERSION = function (result) {
return result && parseFloat(result[1]);
}(/MSIE\s(\d+)\.\d/.exec(USER_AGENT));
var IE_VERSION = exports.IE_VERSION = function () {
var result = /MSIE\s(\d+)\.\d/.exec(USER_AGENT);
var version = result && parseFloat(result[1]);
if (!version && /Trident\/7.0/i.test(USER_AGENT) && /rv:11.0/.test(USER_AGENT)) {
// IE 11 has a different user agent string than other IE versions
version = 11.0;
}
return version;
}();
var IS_SAFARI = exports.IS_SAFARI = /Safari/i.test(USER_AGENT) && !IS_CHROME && !IS_ANDROID && !IS_EDGE;
var IS_ANY_SAFARI = exports.IS_ANY_SAFARI = IS_SAFARI || IS_IOS;
@@ -23898,7 +23916,7 @@ setup.autoSetupTimeout(1, videojs);
*
* @type {string}
*/
videojs.VERSION = '5.18.1';
videojs.VERSION = '5.19.2';
/**
* The global options object. These are the settings that take effect
@@ -24453,7 +24471,7 @@ function _createXHR(options) {
function readystatechange() {
if (xhr.readyState === 4) {
loadFunc()
setTimeout(loadFunc, 0)
}
}
@@ -24476,15 +24494,6 @@ function _createXHR(options) {
return body
}
var failureResponse = {
body: undefined,
headers: {},
statusCode: 0,
method: method,
url: uri,
rawRequest: xhr
}
function errorFunc(evt) {
clearTimeout(timeoutTimer)
if(!(evt instanceof Error)){
@@ -24540,18 +24549,26 @@ function _createXHR(options) {
var aborted
var uri = xhr.url = options.uri || options.url
var method = xhr.method = options.method || "GET"
var body = options.body || options.data || null
var body = options.body || options.data
var headers = xhr.headers = options.headers || {}
var sync = !!options.sync
var isJson = false
var timeoutTimer
var failureResponse = {
body: undefined,
headers: {},
statusCode: 0,
method: method,
url: uri,
rawRequest: xhr
}
if ("json" in options) {
if ("json" in options && options.json !== false) {
isJson = true
headers["accept"] || headers["Accept"] || (headers["Accept"] = "application/json") //Don't override existing accept header declared by user
if (method !== "GET" && method !== "HEAD") {
headers["content-type"] || headers["Content-Type"] || (headers["Content-Type"] = "application/json") //Don't override existing accept header declared by user
body = JSON.stringify(options.json)
body = JSON.stringify(options.json === true ? body : options.json)
}
}
@@ -24562,6 +24579,9 @@ function _createXHR(options) {
xhr.onprogress = function () {
// IE must die
}
xhr.onabort = function(){
aborted = true;
}
xhr.ontimeout = errorFunc
xhr.open(method, uri, !sync, options.username, options.password)
//has to be after open
@@ -24573,7 +24593,8 @@ function _createXHR(options) {
// both npm's request and jquery 1.x use this kind of timeout, so this is being consistent
if (!sync && options.timeout > 0 ) {
timeoutTimer = setTimeout(function(){
aborted=true//IE9 may still call readystatechange
if (aborted) return
aborted = true//IE9 may still call readystatechange
xhr.abort("timeout")
var e = new Error("XMLHttpRequest timeout")
e.code = "ETIMEDOUT"
@@ -24601,7 +24622,10 @@ function _createXHR(options) {
options.beforeSend(xhr)
}
xhr.send(body)
// Microsoft Edge browser sends "undefined" when send is called with undefined value.
// XMLHttpRequest spec says to pass null as body to indicate no body
// See https://github.com/naugtur/xhr/issues/100.
xhr.send(body || null)
return xhr
@@ -24612,7 +24636,7 @@ function getXml(xhr) {
if (xhr.responseType === "document") {
return xhr.responseXML
}
var firefoxBugTakenEffect = xhr.status === 204 && xhr.responseXML && xhr.responseXML.documentElement.nodeName === "parsererror"
var firefoxBugTakenEffect = xhr.responseXML && xhr.responseXML.documentElement.nodeName === "parsererror"
if (xhr.responseType === "" && !firefoxBugTakenEffect) {
return xhr.responseXML
}
+9 -9
Ver Arquivo
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
Arquivo binário não exibido.
+1 -1
Ver Arquivo
@@ -690,7 +690,7 @@ body.vjs-full-window {
.video-js .vjs-progress-holder .vjs-load-progress div {
position: absolute;
display: block;
height: 0.3em;
height: 100%;
margin: 0;
padding: 0;
width: 0;
+1 -1
Ver Arquivo
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
+483 -522
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+9 -9
Ver Arquivo
Diff do arquivo suprimido porque uma ou mais linhas são muito longas
+2 -2
Ver Arquivo
@@ -1,7 +1,7 @@
{
"name": "video.js",
"description": "An HTML5 and Flash video player with a common API and skin for both.",
"version": "5.18.1",
"version": "5.19.2",
"main": "./es5/video.js",
"style": "./dist/video-js.css",
"copyright": "Copyright Brightcove, Inc. <https://www.brightcove.com/>",
@@ -42,7 +42,7 @@
"videojs-font": "2.0.0",
"videojs-ie8": "1.1.2",
"videojs-swf": "5.3.0",
"videojs-vtt.js": "0.12.2",
"videojs-vtt.js": "0.12.3",
"xhr": "2.2.2"
},
"devDependencies": {
+1 -1
Ver Arquivo
@@ -54,7 +54,7 @@
.video-js .vjs-progress-holder .vjs-load-progress div {
position: absolute;
display: block;
height: 0.3em;
height: 100%;
margin: 0;
padding: 0;
// updated by javascript during playback
@@ -49,6 +49,9 @@ class AudioTrackButton extends TrackButton {
* An array of menu items
*/
createItems(items = []) {
// if there's only one audio track, there no point in showing it
this.hideThreshold_ = 1;
const tracks = this.player_.audioTracks && this.player_.audioTracks();
if (!tracks) {
@@ -38,6 +38,7 @@ class TextTrackMenuItem extends MenuItem {
if (tracks) {
const changeHandler = Fn.bind(this, this.handleTracksChange);
player.on(['loadstart', 'texttrackchange'], changeHandler);
tracks.addEventListener('change', changeHandler);
this.on('dispose', function() {
tracks.removeEventListener('change', changeHandler);
+1
Ver Arquivo
@@ -58,6 +58,7 @@ class ErrorDisplay extends ModalDialog {
* @private
*/
ErrorDisplay.prototype.options_ = mergeOptions(ModalDialog.prototype.options_, {
pauseOnOpen: false,
fillAlways: true,
temporary: false,
uncloseable: true
+3 -2
Ver Arquivo
@@ -180,7 +180,7 @@ class ModalDialog extends Component {
// playing state.
this.wasPlaying_ = !player.paused();
if (this.wasPlaying_) {
if (this.options_.pauseOnOpen && this.wasPlaying_) {
player.pause();
}
@@ -243,7 +243,7 @@ class ModalDialog extends Component {
this.trigger('beforemodalclose');
this.opened_ = false;
if (this.wasPlaying_) {
if (this.wasPlaying_ && this.options_.pauseOnOpen) {
player.play();
}
@@ -427,6 +427,7 @@ class ModalDialog extends Component {
* @private
*/
ModalDialog.prototype.options_ = {
pauseOnOpen: true,
temporary: true
};
+6 -2
Ver Arquivo
@@ -536,7 +536,7 @@ class Tech extends Component {
// Initially, Tech.el_ is a child of a dummy-div wait until the Component system
// signals that the Tech is ready at which point Tech.el_ is part of the DOM
// before inserting the WebVTT script
if (this.el().parentNode !== null && this.el().parentNode !== undefined) {
if (document.body.contains(this.el())) {
const vtt = require('videojs-vtt.js');
// load via require if available and vtt.js script location was not passed in
@@ -551,7 +551,7 @@ class Tech extends Component {
// passed in
const script = document.createElement('script');
script.src = this.options_['vtt.js'] || 'https://cdn.rawgit.com/gkatsev/vtt.js/vjs-v0.12.1/dist/vtt.min.js';
script.src = this.options_['vtt.js'] || 'https://vjs.zencdn.net/vttjs/0.12.3/vtt.min.js';
script.onload = () => {
/**
* Fired when vtt.js is loaded.
@@ -622,11 +622,15 @@ class Tech extends Component {
textTracksChanges();
tracks.addEventListener('change', textTracksChanges);
tracks.addEventListener('addtrack', textTracksChanges);
tracks.addEventListener('removetrack', textTracksChanges);
this.on('dispose', function() {
remoteTracks.off('addtrack', handleAddTrack);
remoteTracks.off('removetrack', handleRemoveTrack);
tracks.removeEventListener('change', textTracksChanges);
tracks.removeEventListener('addtrack', textTracksChanges);
tracks.removeEventListener('removetrack', textTracksChanges);
for (let i = 0; i < tracks.length; i++) {
const track = tracks[i];
+9 -9
Ver Arquivo
@@ -339,11 +339,14 @@ class TextTrack extends Track {
cue = new window.vttjs.VTTCue(originalCue.startTime, originalCue.endTime, originalCue.text);
for (const prop in originalCue) {
cue[prop] = originalCue[prop];
if (!(prop in cue)) {
cue[prop] = originalCue[prop];
}
}
// make sure that `id` is copied over
cue.id = originalCue.id;
cue.originalCue_ = originalCue;
}
const tracks = this.tech_.textTracks();
@@ -367,20 +370,17 @@ class TextTrack extends Track {
* The cue to remove from our internal list
*/
removeCue(removeCue) {
let removed = false;
let i = this.cues_.length;
for (let i = 0, l = this.cues_.length; i < l; i++) {
while (i--) {
const cue = this.cues_[i];
if (cue === removeCue) {
if (cue === removeCue || (cue.originalCue_ && cue.originalCue_ === removeCue)) {
this.cues_.splice(i, 1);
removed = true;
this.cues.setCues_(this.cues_);
break;
}
}
if (removed) {
this.cues.setCues_(this.cues_);
}
}
}
+11 -3
Ver Arquivo
@@ -63,9 +63,17 @@ export const IS_FIREFOX = (/Firefox/i).test(USER_AGENT);
export const IS_EDGE = (/Edge/i).test(USER_AGENT);
export const IS_CHROME = !IS_EDGE && (/Chrome/i).test(USER_AGENT);
export const IS_IE8 = (/MSIE\s8\.0/).test(USER_AGENT);
export const IE_VERSION = (function(result) {
return result && parseFloat(result[1]);
}((/MSIE\s(\d+)\.\d/).exec(USER_AGENT)));
export const IE_VERSION = (function() {
const result = (/MSIE\s(\d+)\.\d/).exec(USER_AGENT);
let version = result && parseFloat(result[1]);
if (!version && (/Trident\/7.0/i).test(USER_AGENT) && (/rv:11.0/).test(USER_AGENT)) {
// IE 11 has a different user agent string than other IE versions
version = 11.0;
}
return version;
}());
export const IS_SAFARI = (/Safari/i).test(USER_AGENT) && !IS_CHROME && !IS_ANDROID && !IS_EDGE;
export const IS_ANY_SAFARI = IS_SAFARI || IS_IOS;
+29
Ver Arquivo
@@ -208,6 +208,35 @@ QUnit.test('open() pauses playback, close() resumes', function(assert) {
assert.strictEqual(playSpy.callCount, 1, 'player is resumed when the modal closes');
});
QUnit.test('open() does not pause, close() does not play() with pauseOnOpen set to false', function(assert) {
const playSpy = sinon.spy();
const pauseSpy = sinon.spy();
// don't pause the video on modal open
this.modal.options_.pauseOnOpen = false;
// Quick and dirty; make it looks like the player is playing.
this.player.paused = function() {
return false;
};
this.player.play = function() {
playSpy();
};
this.player.pause = function() {
pauseSpy();
};
this.modal.open();
assert.expect(2);
assert.strictEqual(pauseSpy.callCount, 0, 'player remains playing when the modal opens');
this.modal.close();
assert.strictEqual(playSpy.callCount, 0, 'player is resumed when the modal closes');
});
QUnit.test('open() hides controls, close() shows controls', function(assert) {
this.modal.open();
+40
Ver Arquivo
@@ -205,6 +205,46 @@ QUnit.test('cues can be added and removed from a TextTrack', function(assert) {
assert.equal(cues.length, 3, 'we now have 3 cues');
});
QUnit.test('original cue can be used to remove cue from cues list', function(assert) {
const tt = new TextTrack({
tech: this.tech
});
const Cue = window.VTTCue ||
window.vttjs && window.vttjs.VTTCue ||
window.TextTrackCue;
const cue1 = new Cue(0, 1, 'some-cue');
assert.equal(tt.cues.length, 0, 'start with zero cues');
tt.addCue(cue1);
assert.equal(tt.cues.length, 1, 'we have one cue');
tt.removeCue(cue1);
assert.equal(tt.cues.length, 0, 'we have removed cue1');
});
QUnit.test('can only remove one cue at a time', function(assert) {
const tt = new TextTrack({
tech: this.tech
});
const Cue = window.VTTCue ||
window.vttjs && window.vttjs.VTTCue ||
window.TextTrackCue;
const cue1 = new Cue(0, 1, 'some-cue');
assert.equal(tt.cues.length, 0, 'start with zero cues');
tt.addCue(cue1);
tt.addCue(cue1);
assert.equal(tt.cues.length, 2, 'we have two cues');
tt.removeCue(cue1);
assert.equal(tt.cues.length, 1, 'we have removed one instance of cue1');
tt.removeCue(cue1);
assert.equal(tt.cues.length, 0, 'we have removed the other instance of cue1');
});
QUnit.test('fires cuechange when cues become active and inactive', function(assert) {
const player = TestHelpers.makePlayer();
let changes = 0;