Compare commits

..

No commits in common. "master" and "v1.1.0" have entirely different histories.

17 changed files with 56 additions and 10498 deletions

View File

@ -1,5 +1,5 @@
{
"extends": "@silvermine/eslint-config/node"
"extends": "eslint-config-silvermine/node"
}

1
.nvmrc
View File

@ -1 +0,0 @@
12.14.0

View File

@ -1,15 +1,12 @@
language: node_js
# 4.3.2 is what AWS Lambda currently uses
node_js:
- "node" # Latest node version
- "lts/*" # Latest LTS version
- "12"
- "10"
- "8"
- "5"
- "4.3.2"
before_install: npm i -g npm@6.13.4
before_install: if [[ `npm -v` != 3* ]]; then npm i -g npm@3; fi
script:
- npm run commitlint
- grunt standards
- npm test

View File

@ -3,45 +3,6 @@
In general, this project adheres to [Semantic Versioning](http://semver.org/). If for some
reason we do something that's not strictly semantic, it will be clearly called out below.
## 1.2.3
* Downgraded the `class.extend` dependency to 0.9.1. Version 0.9.2 introduces a call to
`new Function(someString)`, which [violates the Content Security Policy that blocks
`eval` and `eval`-like function
calls.](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src#Unsafe_eval_expressions)
(f9ca724 Fixes #36)
* Fixed a bug where the quality selection menu did not render when sources were set
sometime after the player was initially created and became ready (a3753dd Fixes #47).
* Support 'selected' as a value for the `selected` attribute on `source` tags (8702f4f
Fixes #39)
## 1.2.2
* Fixed a bug introduced in `1.2.0` where the quality selector menu did not show the
selected source as selected when it first rendered
## 1.2.1
* Fixed a bug introduced in 31a305d where the path to the built JS file in the `dist`
folder changed unintentionally
* Fixed a bug that prevented the quality selector menu from fading out smoothly in
Video.js 7.
* Included Video.js 7 in peer dependency range (21900e8 Fixes #26)
## 1.2.0
* Migrated NPM package to use `@silvermine` scope
## 1.1.2
* Fixed a bug where selecting a quality menu item while a video was playing did not resume
playback after the source changed. Affected Safari and players whose `preload` attribute
was `none` (8feeafb Fixes #16).
## 1.1.1
* Reference underscore as a dependency since we depend on it (931d8a4 See #12)
## 1.1.0
**NOTE:** Strictly speaking, this version breaks API backwards-compatibility, and thus
@ -52,8 +13,8 @@ depending on the specific reason they were using it, they may not need to make a
all.
If you were relying on the `QUALITY_SELECTED` event, it's possible that you will now need
to rely on the `QUALITY_REQUESTED` event instead, depending on why you were listening to
the event. See a682125 for details.
to release on the `QUALITY_REQUESTED` event instead, depending on why you were listening
to the event. See a682125 for details.
* Support quality selector buttons anywhere in the player's component hierarchy (a682125 Fixes #13)

View File

@ -8,8 +8,6 @@
var path = require('path'),
getCodeVersion = require('silvermine-serverless-utils/src/get-code-version');
const sass = require('node-sass');
module.exports = function(grunt) {
var DEBUG = !!grunt.option('debug'),
@ -28,13 +26,12 @@ module.exports = function(grunt) {
dist: {
base: path.join(__dirname, 'dist'),
jsFileName: 'silvermine-videojs-quality-selector',
},
};
config.dist.js = {
bundle: path.join(config.dist.base, 'js', '<%= config.dist.jsFileName %>.js'),
minified: path.join(config.dist.base, 'js', '<%= config.dist.jsFileName %>.min.js'),
bundle: path.join(config.dist.base, 'js', '<%= pkg.name %>.js'),
minified: path.join(config.dist.base, 'js', '<%= pkg.name %>.min.js'),
};
config.dist.css = {
@ -73,7 +70,6 @@ module.exports = function(grunt) {
sass: {
options: {
implementation: sass,
sourceMap: DEBUG,
indentWidth: 3,
outputStyle: DEBUG ? 'expanded' : 'compressed',
@ -105,17 +101,13 @@ module.exports = function(grunt) {
},
},
clean: {
dist: config.dist.base,
},
eslint: {
target: config.js.all,
},
sasslint: {
options: {
configFile: path.join(__dirname, 'node_modules', '@silvermine/sass-lint-config', 'sass-lint.yml'),
configFile: path.join(__dirname, 'node_modules', 'sass-lint-config-silvermine', 'sass-lint.yml'),
},
target: config.sass.all,
},
@ -144,7 +136,6 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-browserify');
grunt.loadNpmTasks('grunt-eslint');
grunt.loadNpmTasks('grunt-postcss');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-sass');
grunt.loadNpmTasks('grunt-sass-lint');

View File

@ -38,12 +38,11 @@ There is an example of this in
<script src="./path/to/silvermine-videojs-quality-selector.min.js"></script>
```
##### From [`unpkg`](https://unpkg.com/@silvermine/videojs-quality-selector/):
##### From [`unpkg`](https://unpkg.com/silvermine-videojs-quality-selector/):
```js
<link href="https://unpkg.com/@silvermine/videojs-quality-selector/dist/css/quality-selector.css" rel="stylesheet">
<script src="./path/to/video.min.js"></script>
<script src="https://unpkg.com/@silvermine/videojs-quality-selector/dist/js/silvermine-videojs-quality-selector.min.js"></script>
<script src="https://unpkg.com/silvermine-videojs-quality-selector/dist/js/silvermine-videojs-quality-selector.min.js"></script>
```
#### Using `require`
@ -51,7 +50,7 @@ There is an example of this in
When using NPM/Browserify, first install the plugin.
```
npm install --save @silvermine/videojs-quality-selector
npm install --save silvermine-videojs-quality-selector
```
For `videojs` to use the plug-in, the plugin needs to register itself with the instance of
@ -61,7 +60,7 @@ For `videojs` to use the plug-in, the plugin needs to register itself with the i
var videojs = require('videojs');
// The following registers the plugin with `videojs`
require('@silvermine/videojs-quality-selector')(videojs);
require('silvermine-videojs-quality-selector')(videojs);
```
### Providing video sources

View File

@ -1,5 +0,0 @@
'use strict';
module.exports = {
extends: [ '@silvermine/eslint-config/commitlint.js' ],
};

View File

@ -3,8 +3,8 @@
<head>
<meta charset=utf-8 />
<title>videojs-quality-selector Demo</title>
<link href="https://unpkg.com/video.js@7.5.4/dist/video-js.css" rel="stylesheet">
<script src="https://unpkg.com/video.js@7.5.4/dist/video.js"></script>
<link href="https://unpkg.com/video.js@6.1.0/dist/video-js.css" rel="stylesheet">
<script src="https://unpkg.com/video.js@6.1.0/dist/video.js"></script>
<script src="../../dist/js/silvermine-videojs-quality-selector.min.js"></script>
<link href="../../dist/css/quality-selector.css" rel="stylesheet">
</head>

10257
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,11 @@
{
"name": "@silvermine/videojs-quality-selector",
"version": "1.2.4",
"name": "silvermine-videojs-quality-selector",
"version": "1.1.0",
"description": "video.js plugin for selecting a video quality or resolution",
"main": "src/js/index.js",
"scripts": {
"prepare": "grunt build",
"test": "check-node-version --npm 6.13.4 && ./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha -- -R spec 'tests/**/*.test.js'",
"commitlint": "commitlint --from ad805e8"
"prepublish": "grunt build",
"test": "./node_modules/.bin/istanbul cover ./node_modules/.bin/_mocha -- -R spec 'tests/**/*.test.js'"
},
"author": "Jeremy Thomerson",
"license": "MIT",
@ -26,36 +25,30 @@
},
"homepage": "https://github.com/silvermine/videojs-quality-selector#readme",
"devDependencies": {
"@commitlint/cli": "8.3.5",
"@commitlint/travis-cli": "8.3.5",
"@silvermine/eslint-config": "3.0.0-rc.0",
"@silvermine/sass-lint-config": "1.1.0",
"autoprefixer": "9.5.1",
"check-node-version": "4.0.3",
"coveralls": "3.0.3",
"autoprefixer": "7.1.1",
"class.extend": "0.9.2",
"coveralls": "2.13.1",
"eslint": "4.0.0",
"eslint-config-silvermine": "1.3.0",
"expect.js": "0.3.1",
"grunt": "1.0.4",
"grunt-browserify": "5.3.0",
"grunt-contrib-clean": "2.0.0",
"grunt-contrib-uglify": "4.0.1",
"grunt-contrib-watch": "1.1.0",
"grunt-eslint": "22.0.0",
"grunt-postcss": "0.9.0",
"grunt-sass": "3.0.2",
"grunt-sass-lint": "0.2.4",
"grunt": "1.0.1",
"grunt-browserify": "5.0.0",
"grunt-contrib-uglify": "3.0.1",
"grunt-contrib-watch": "1.0.0",
"grunt-eslint": "20.0.0",
"grunt-postcss": "0.8.0",
"grunt-sass": "2.0.0",
"grunt-sass-lint": "0.2.2",
"istanbul": "0.4.5",
"mocha": "6.1.4",
"mocha": "3.4.2",
"mocha-lcov-reporter": "1.3.0",
"node-sass": "4.12.0",
"rewire": "4.0.1",
"rewire": "2.5.2",
"sass-lint-config-silvermine": "1.0.1",
"silvermine-serverless-utils": "git+https://github.com/silvermine/serverless-utils.git#910f1149af824fc8d0fa840878079c7d3df0f414",
"sinon": "7.3.2"
"sinon": "2.3.5",
"underscore": "1.8.3"
},
"peerDependencies": {
"video.js": ">=6.0.0"
},
"dependencies": {
"class.extend": "0.9.1",
"underscore": "1.9.1"
"video.js": "6.x"
}
}

View File

@ -1,5 +1,5 @@
{
"extends": "@silvermine/eslint-config/browser"
"extends": "eslint-config-silvermine/browser"
}

View File

@ -34,11 +34,6 @@ module.exports = function(videojs) {
});
}.bind(this));
// Update the list of menu items only when the list of sources change
player.on(events.PLAYER_SOURCES_CHANGED, function() {
this.update();
}.bind(this));
player.on(events.QUALITY_SELECTED, function(event, newSource) {
// Update the selected source with the source that was actually selected
this.setSelectedSource(newSource);
@ -64,9 +59,7 @@ module.exports = function(videojs) {
if (this.selectedSrc !== src) {
this.selectedSrc = src;
_.each(this.items, function(item) {
item.selected(item.source.src === src);
});
this.update();
}
},
@ -76,10 +69,10 @@ module.exports = function(videojs) {
createItems: function() {
var player = this.player(),
sources = player.currentSources();
sources = sources.filter(function(element) {
return element.hidequalityoption == undefined;
});
if (!sources || sources.length < 2) {
return [];
}
return _.map(sources, function(source) {
return new QualityOption(player, {

View File

@ -4,6 +4,5 @@ module.exports = {
QUALITY_REQUESTED: 'qualityRequested',
QUALITY_SELECTED: 'qualitySelected',
PLAYER_SOURCES_CHANGED: 'playerSourcesChanged',
};

View File

@ -3,8 +3,7 @@
var _ = require('underscore'),
events = require('./events'),
qualitySelectorFactory = require('./components/QualitySelector'),
sourceInterceptorFactory = require('./middleware/SourceInterceptor'),
SafeSeek = require('./util/SafeSeek');
sourceInterceptorFactory = require('./middleware/SourceInterceptor');
module.exports = function(videojs) {
videojs = videojs || window.videojs;
@ -13,10 +12,10 @@ module.exports = function(videojs) {
sourceInterceptorFactory(videojs);
videojs.hook('setup', function(player) {
function changeQuality(event, newSource) {
// Add handler to switch sources when the user requests a change
player.on(events.QUALITY_REQUESTED, function(event, newSource) {
var sources = player.currentSources(),
currentTime = player.currentTime(),
currentPlaybackRate = player.playbackRate(),
isPaused = player.paused(),
selectedSource;
@ -30,37 +29,15 @@ module.exports = function(videojs) {
// following updates the original object in `sources`.
selectedSource.selected = true;
if (player._qualitySelectorSafeSeek) {
player._qualitySelectorSafeSeek.onQualitySelectionChange();
}
player.src(sources);
player.ready(function() {
if (!player._qualitySelectorSafeSeek || player._qualitySelectorSafeSeek.hasFinished()) {
// Either we don't have a pending seek action or the one that we have is no
// longer applicable. This block must be within a `player.ready` callback
// because the call to `player.src` above is asynchronous, and so not
// having it within this `ready` callback would cause the SourceInterceptor
// to execute after this block instead of before.
//
// We save the `currentTime` within the SafeSeek instance because if
// multiple QUALITY_REQUESTED events are received before the SafeSeek
// operation finishes, the player's `currentTime` will be `0` if the
// player's `src` is updated but the player's `currentTime` has not yet
// been set by the SafeSeek operation.
player._qualitySelectorSafeSeek = new SafeSeek(player, currentTime);
player.playbackRate(currentPlaybackRate);
}
player.one('loadeddata', function() {
player.currentTime(currentTime);
if (!isPaused) {
player.play();
}
});
}
// Add handler to switch sources when the user requests a change
player.on(events.QUALITY_REQUESTED, changeQuality);
});
});
};

View File

@ -13,15 +13,6 @@ module.exports = function(videojs) {
var sources = player.currentSources(),
userSelectedSource, chosenSource;
if (player._qualitySelectorSafeSeek) {
player._qualitySelectorSafeSeek.onPlayerSourcesChange();
}
if (!_.isEqual(sources, player._qualitySelectorPreviousSources)) {
player.trigger(events.PLAYER_SOURCES_CHANGED, sources);
player._qualitySelectorPreviousSources = sources;
}
// There are generally two source options, the one that videojs
// auto-selects and the one that a "user" of this plugin has
// supplied via the `selected` property. `selected` can come from
@ -29,10 +20,10 @@ module.exports = function(videojs) {
// videojs using `src()`.
userSelectedSource = _.find(sources, function(source) {
// Must check for boolean values as well as either the string 'true' or
// 'selected'. When sources are set programmatically, the value will be a
// boolean, but those coming from a `<source>` tag will be a string.
return source.selected === true || source.selected === 'true' || source.selected === 'selected';
// Must check for both boolean and string 'true' as sources set
// programmatically should use a boolean, but those coming from
// a `<source>` tag will use a string.
return source.selected === true || source.selected === 'true';
});
chosenSource = userSelectedSource || playerSelectedSource;

View File

@ -1,80 +0,0 @@
'use strict';
var Class = require('class.extend');
module.exports = Class.extend({
init: function(player, seekToTime) {
this._player = player;
this._seekToTime = seekToTime;
this._hasFinished = false;
this._keepThisInstanceWhenPlayerSourcesChange = false;
this._seekWhenSafe();
},
_seekWhenSafe: function() {
var HAVE_FUTURE_DATA = 3;
// `readyState` in Video.js is the same as the HTML5 Media element's `readyState`
// property.
//
// `readyState` is an enum of 5 values (0-4), each of which represent a state of
// readiness to play. The meaning of the values range from HAVE_NOTHING (0), meaning
// no data is available to HAVE_ENOUGH_DATA (4), meaning all data is loaded and the
// video can be played all the way through.
//
// In order to seek successfully, the `readyState` must be at least HAVE_FUTURE_DATA
// (3).
//
// @see http://docs.videojs.com/player#readyState
// @see https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/readyState
// @see https://dev.w3.org/html5/spec-preview/media-elements.html#seek-the-media-controller
if (this._player.readyState() < HAVE_FUTURE_DATA) {
this._seekFn = this._seek.bind(this);
// The `canplay` event means that the `readyState` is at least HAVE_FUTURE_DATA.
this._player.one('canplay', this._seekFn);
} else {
this._seek();
}
},
onPlayerSourcesChange: function() {
if (this._keepThisInstanceWhenPlayerSourcesChange) {
// By setting this to `false`, we know that if the player sources change again
// the change did not originate from a quality selection change, the new sources
// are likely different from the old sources, and so this pending seek no longer
// applies.
this._keepThisInstanceWhenPlayerSourcesChange = false;
} else {
this.cancel();
}
},
onQualitySelectionChange: function() {
// `onPlayerSourcesChange` will cancel this pending seek unless we tell it not to.
// We need to reuse this same pending seek instance because when the player is
// paused, the `preload` attribute is set to `none`, and the user selects one
// quality option and then another, the player cannot seek until the player has
// enough data to do so (and the `canplay` event is fired) and thus on the second
// selection the player's `currentTime()` is `0` and when the video plays we would
// seek to `0` instead of the correct time.
if (!this.hasFinished()) {
this._keepThisInstanceWhenPlayerSourcesChange = true;
}
},
_seek: function() {
this._player.currentTime(this._seekToTime);
this._keepThisInstanceWhenPlayerSourcesChange = false;
this._hasFinished = true;
},
hasFinished: function() {
return this._hasFinished;
},
cancel: function() {
this._player.off('canplay', this._seekFn);
this._keepThisInstanceWhenPlayerSourcesChange = false;
this._hasFinished = true;
},
});

View File

@ -1,5 +1,5 @@
{
"extends": "@silvermine/eslint-config/node-tests"
"extends": "eslint-config-silvermine/node-tests"
}