--- /dev/null
+{
+ "language": {
+ "javascript": {
+ "linting.prefer": "JSHint",
+ "linting.usePreferredOnly": true
+ }
+ },
+ "jwolfe.file-tree-exclude.list": [
+ "node_modules",
+ "bower_components",
+ ".git",
+ "dist",
+ "vendor"
+ ]
+}
--- /dev/null
+# http://editorconfig.org
+root = true
+
+[*]
+indent_style = space
+indent_size = 2
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.md]
+trim_trailing_whitespace = false
--- /dev/null
+{
+ "browser" : true,
+ "curly": true,
+ "eqeqeq": true,
+ "quotmark" : "single",
+ "trailing" : true,
+ "undef" : true,
+ "predef" : [
+ "videojs"
+ ]
+}
--- /dev/null
+dist/
+test/
+*~
\ No newline at end of file
--- /dev/null
+language: node_js
+node_js:
+ - 4
+ - 0.12
+ - 0.10
+before_install: npm install -g grunt-cli
+install: npm install
+sudo: false
--- /dev/null
+'use strict';
+
+module.exports = function(grunt) {
+ grunt.initConfig({
+ pkg: grunt.file.readJSON('package.json'),
+ banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' +
+ '<%= grunt.template.today("yyyy-mm-dd") %>\n' +
+ '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author %>;' +
+ ' Licensed <%= pkg.license %> */\n',
+ clean: {
+ files: ['dist']
+ },
+ concat: {
+ options: {
+ banner: '<%= banner %>',
+ stripBanners: true
+ },
+ dist: {
+ src: 'lib/**/*.js',
+ dest: 'dist/<%= pkg.name %>.js'
+ }
+ },
+ uglify: {
+ options: {
+ banner: '<%= banner %>'
+ },
+ dist: {
+ src: '<%= concat.dist.dest %>',
+ dest: 'dist/<%= pkg.name %>.min.js'
+ }
+ },
+ qunit: {
+ files: 'test/**/*.html'
+ },
+ jshint: {
+ gruntfile: {
+ options: {
+ node: true
+ },
+ src: 'Gruntfile.js'
+ },
+ src: {
+ options: {
+ jshintrc: '.jshintrc'
+ },
+ src: ['lib/**/*.js']
+ },
+ test: {
+ options: {
+ jshintrc: '.jshintrc'
+ },
+ src: ['test/**/*.js']
+ }
+ },
+ watch: {
+ gruntfile: {
+ files: '<%= jshint.gruntfile.src %>',
+ tasks: ['jshint:gruntfile']
+ },
+ src: {
+ files: '<%= jshint.src.src %>',
+ tasks: ['jshint:src', 'qunit']
+ },
+ test: {
+ files: '<%= jshint.test.src %>',
+ tasks: ['jshint:test', 'qunit']
+ }
+ }
+ });
+
+ grunt.loadNpmTasks('grunt-contrib-clean');
+ grunt.loadNpmTasks('grunt-contrib-concat');
+ grunt.loadNpmTasks('grunt-contrib-uglify');
+ grunt.loadNpmTasks('grunt-contrib-qunit');
+ grunt.loadNpmTasks('grunt-contrib-jshint');
+ grunt.loadNpmTasks('grunt-contrib-watch');
+
+ grunt.registerTask('default',
+ ['clean',
+ 'jshint',
+ 'qunit',
+ 'concat',
+ 'uglify']);
+
+ grunt.registerTask('test', [
+ 'jshint'
+ ]);
+};
--- /dev/null
+Copyright 2013 Kasper Moskwiak
+
+Modified by Pierre Kraft
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
\ No newline at end of file
--- /dev/null
+# Video.js Resolution Switcher [![Build Status](https://travis-ci.org/kmoskwiak/videojs-resolution-switcher.svg?branch=master)](https://travis-ci.org/kmoskwiak/videojs-resolution-switcher)
+
+Resolution switcher for [video.js v5](https://github.com/videojs/video.js)
+
+## Example
+
+[Working examples](examples) of the plugin you can check out if you're having trouble. Or check out this [demo](https://kmoskwiak.github.io/videojs-resolution-switcher/).
+
+## Getting Started
+
+Install plugin with
+
+**npm**
+```
+npm i videojs-resolution-switcher
+```
+
+or **bower**
+```
+bower install videojs-resolution-switcher
+```
+
+
+### Setup sources dynamically:
+
+```html
+<video id='video' class="video-js vjs-default-skin"></video>
+<script src="video.js"></script>
+<script src="videojs-resolution-switcher.js"></script>
+<script>
+ videojs('video', {
+ controls: true,
+ plugins: {
+ videoJsResolutionSwitcher: {
+ default: 'high',
+ dynamicLabel: true
+ }
+ }
+ }, function(){
+
+ // Add dynamically sources via updateSrc method
+ player.updateSrc([
+ {
+ src: 'http://media.xiph.org/mango/tears_of_steel_1080p.webm',
+ type: 'video/webm',
+ label: '360'
+ },
+ {
+ src: 'http://mirrorblender.top-ix.org/movies/sintel-1024-surround.mp4',
+ type: 'video/mp4',
+ label: '720'
+ }
+ ])
+
+ player.on('resolutionchange', function(){
+ console.info('Source changed to %s', player.src())
+ })
+
+ })
+</script>
+```
+
+### Or use `<source>` tags:
+
+```html
+
+<video id="video" class="video-js vjs-default-skin" width="1000" controls data-setup='{}'>
+ <source src="http://mirrorblender.top-ix.org/movies/sintel-1024-surround.mp4" type='video/mp4' label='SD' />
+ <source src="http://media.xiph.org/mango/tears_of_steel_1080p.webm" type='video/webm' label='HD'/>
+</video>
+<script>
+ videojs('video').videoJsResolutionSwitcher()
+</script>
+
+```
+
+
+### YouTube tech
+
+YouTube tech form https://github.com/eXon/videojs-youtube
+
+```html
+<video id='video' class="video-js vjs-default-skin"></video>
+<script src="../lib/videojs-resolution-switcher.js"></script>
+<script>
+ videojs('video', {
+ controls: true,
+ techOrder: ["youtube"],
+ sources: [{ "type": "video/youtube", "src": "https://www.youtube.com/watch?v=iD_MyDbP_ZE"}],
+ plugins: {
+ videoJsResolutionSwitcher: {
+ default: 'low',
+ dynamicLabel: true
+ }
+ }
+ }, function(){
+ var player = this;
+ player.on('resolutionchange', function(){
+ console.info('Source changed')
+ })
+ });
+
+</script>
+
+```
+
+### Flash tech
+
+When using flash tech `preload="auto"` is required.
+
+## Source options
+
+Sources can passed to player using `updateSrc` method or `<source>` tag as shown above. Avalible options for each source are:
+* label - `String` (required) is shown in menu (ex. 'SD' or '360p')
+* res - `Number` is resolution of video used for sorting (ex. 360 or 1080)
+
+## Plugin options
+
+You can pass options to plugin like this:
+
+```javascript
+
+videojs('video', {
+ controls: true,
+ muted: true,
+ width: 1000,
+ plugins: {
+ videoJsResolutionSwitcher: {
+ default: 'low'
+ }
+ }
+ }, function(){
+ // this is player
+ })
+```
+### Avalible options:
+* default - `{Number}|'low'|'high'` - default resolution. If any `Number` is passed plugin will try to choose source based on `res` parameter. If `low` or `high` is passed, plugin will choose respectively worse or best resolution (if `res` parameter is specified). If `res` parameter is not specified plugin assumes that sources array is sorted from best to worse.
+* dynamicLabel - `{Boolean}` - if `true` current label will be displayed in control bar. By default gear icon is displayed.
+* customSourcePicker - `{Function}` - custom function for selecting source.
+
+
+## Methods
+
+
+### updateSrc([source])
+Returns video.js player object if used as setter. If `source` is not passed it acts like [player.src()](http://docs.videojs.com/docs/api/player.html#Methodssrc)
+```javascript
+
+// Update video sources
+player.updateSrc([
+ { type: "video/mp4", src: "http://www.example.com/path/to/video.mp4", label: 'SD' },
+ { type: "video/mp4", src: "http://www.example.com/path/to/video.mp4", label: 'HD' },
+ { type: "video/mp4", src: "http://www.example.com/path/to/video.mp4", label: '4k' }
+])
+
+```
+#### PARAMETERS:
+| name | type | required | description |
+|:----:|:----:|:--------:|:-----------:|
+| source| array| no | array of sources |
+
+### currentResolution([label], [customSourcePicker])
+If used as getter returns current resolution object:
+```javascript
+ {
+ label: 'SD', // current label
+ sources: [
+ { type: "video/webm", src: "http://www.example.com/path/to/video.webm", label: 'SD' },
+ { type: "video/mp4", src: "http://www.example.com/path/to/video.mp4", label: 'SD' }
+ ] // array of sources with current label
+ }
+```
+
+If used as setter returns video.js player object.
+
+
+```javascript
+
+// Get current resolution
+player.currentResolution(); // returns object {label '', sources: []}
+
+// Set resolution
+player.currentResolution('SD'); // returns videojs player object
+```
+#### PARAMETERS:
+| name | type | required | description |
+|:----:|:----:|:--------:|:-----------:|
+| label| string| no | label name |
+| customSourcePicker | function | no | cutom function to choose source |
+
+#### customSourcePicker
+If there is more than one source with the same label, player will choose source automatically. This behavior can be changed if `customSourcePicker` is passed.
+
+`customSourcePicker` must return `player` object.
+```javascript
+player.currentResolution('SD', function(_player, _sources, _label){
+ return _player.src(_sources[0]); \\ Always select first source in array
+});
+```
+`customSourcePicker` accepst 3 arguments.
+
+| name | type | required | description |
+|:----:|:----:|:--------:|:-----------:|
+| player| Object | yes | videojs player object |
+| sources | Array | no | array of sources |
+| label | String | no | name of label |
+
+`customSourcePicker` may be passed in options when player is initialized:
+```javascript
+
+var myCustomSrcPicker = function(_p, _s, _l){
+ // select any source you want
+ return _p.src(selectedSource);
+}
+
+videojs('video', {
+ controls: true,
+ muted: true,
+ width: 1000,
+ plugins: {
+ videoJsResolutionSwitcher: {
+ default: 'low',
+ customSourcePicker: myCustomSrcPicker
+ }
+ }
+ }, function(){
+ // this is player
+ })
+```
+
+
+### getGroupedSrc()
+Returns sources grouped by label, resolution and type.
+
+
+## Events
+
+### resolutionchange `EVENT`
+
+> Fired when resolution is changed
--- /dev/null
+{
+ "name": "vjs-resolution-switcher",
+ "version": "0.4.2",
+ "authors": [
+ "Kasper Moskwiak <kasper.moskwiak@gmail.com>"
+ ],
+ "description": "Resolution switcher for video.js 5",
+ "main": [
+ "lib/videojs-resolution-switcher.js",
+ "lib/videojs-resolution-switcher.css"
+ ],
+ "moduleType": [
+ "amd",
+ "globals",
+ "node"
+ ],
+ "keywords": [
+ "videojs",
+ "flash",
+ "video",
+ "player",
+ "resolution",
+ "sources",
+ "videojs-plugin"
+ ],
+ "license": "Apache-2.0",
+ "homepage": "https://github.com/kmoskwiak/videojs-resolution-switcher",
+ "ignore": [
+ "**/.*",
+ "node_modules",
+ "bower_components",
+ "test",
+ "tests"
+ ]
+}
--- /dev/null
+<!doctype html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Video.js Resolution Switcher</title>
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <link href="../node_modules/video.js/dist/video-js.css" rel="stylesheet">
+ <link href="../lib/videojs-resolution-switcher.css" rel="stylesheet">
+ <style>
+ body {
+ font-family: Arial, sans-serif;
+ background: #777;
+ }
+ .info {
+ background-color: #eee;
+ border: thin solid #333;
+ border-radius: 3px;
+ padding: 0 5px;
+ text-align: center;
+ }
+ .video-js {
+ margin: 40px auto;
+ }
+ </style>
+</head>
+<body>
+ <div class="info">
+ <p>
+ Use flash
+ </p>
+ </div>
+
+ <video id='video_flash' class="video-js vjs-default-skin"></video>
+
+ <script src="../node_modules/video.js/dist/video.js"></script>
+ <script>
+ videojs.options.flash.swf = "../node_modules/video.js/dist/video-js.swf"
+ </script>
+ <script src="../lib/videojs-resolution-switcher.js"></script>
+ <script>
+
+ // Use flash
+ videojs('video_flash', {
+ controls: true,
+ techOrder: ['flash'],
+ preload: 'auto',
+ width: 1000,
+ plugins: {
+ videoJsResolutionSwitcher: {
+ default: 'low', // Default resolution [{Number}, 'low', 'high'],
+ dynamicLabel: true // Display dynamic labels or gear symbol
+ }
+ }
+ }, function(){
+ var player = this;
+ window.player = player
+
+ player.updateSrc([
+ {
+ src: 'https://vjs.zencdn.net/v/oceans.mp4?sd',
+ type: 'video/mp4',
+ label: 'SD',
+ res: 360
+ },
+ {
+ src: 'https://vjs.zencdn.net/v/oceans.mp4?hd',
+ type: 'video/mp4',
+ label: 'HD',
+ res: 720
+ }
+ ])
+
+ player.on('resolutionchange', function(){
+ console.info('Source changed to %s', player.src())
+ })
+
+ })
+
+ </script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Video.js Resolution Switcher</title>
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <link href="../node_modules/video.js/dist/video-js.css" rel="stylesheet">
+ <link href="../lib/videojs-resolution-switcher.css" rel="stylesheet">
+ <style>
+ body {
+ font-family: Arial, sans-serif;
+ background: #777;
+ }
+ .info {
+ background-color: #eee;
+ border: thin solid #333;
+ border-radius: 3px;
+ padding: 0 5px;
+ text-align: center;
+ }
+ .video-js {
+ margin: 40px auto;
+ }
+ </style>
+</head>
+<body>
+ <div class="info">
+ <p>
+ Set sources dynamically
+ </p>
+ </div>
+
+ <video id='video' class="video-js vjs-default-skin"></video>
+
+ <div class="info">
+ <p>
+ Set sources inside <code><video></code> tag
+ </p>
+ </div>
+
+ <video id="video_1" class="video-js vjs-default-skin" width="1000" controls data-setup='{}' muted>
+ <source src="https://vjs.zencdn.net/v/oceans.mp4?480" type='video/mp4' label='SD' res='480' />
+ <source src="https://vjs.zencdn.net/v/oceans.mp4?1080" type='video/mp4' label='HD' res='1080'/>
+ <source src="https://vjs.zencdn.net/v/oceans.mp4?144" type='video/mp4' label='phone' res='144'/>
+ <source src="https://vjs.zencdn.net/v/oceans.mp4?2160" type='video/mp4' label='4k' res='2160'/>
+ </video>
+
+
+ <script src="../node_modules/video.js/dist/video.js"></script>
+ <script>
+ videojs.options.flash.swf = "../node_modules/video.js/dist/video-js.swf"
+ </script>
+ <script src="../lib/videojs-resolution-switcher.js"></script>
+ <script>
+ // fire up the plugin
+ videojs('video', {
+ controls: true,
+ muted: true,
+ width: 1000,
+ plugins: {
+ videoJsResolutionSwitcher: {
+ default: 'low', // Default resolution [{Number}, 'low', 'high'],
+ dynamicLabel: true // Display dynamic labels or gear symbol
+ }
+ }
+ }, function(){
+ var player = this;
+ window.player = player
+
+ player.updateSrc([
+ {
+ src: 'https://vjs.zencdn.net/v/oceans.mp4?sd',
+ type: 'video/mp4',
+ label: 'SD',
+ res: 360
+ },
+ {
+ src: 'https://vjs.zencdn.net/v/oceans.mp4?hd',
+ type: 'video/mp4',
+ label: 'HD',
+ res: 720
+ }
+ ])
+
+ player.on('resolutionchange', function(){
+ console.info('Source changed to %s', player.src())
+ })
+
+ })
+ </script>
+
+
+ <script>
+ videojs('video_1').videoJsResolutionSwitcher()
+ </script>
+</body>
+</html>
--- /dev/null
+<!doctype html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <title>Video.js Resolution Switcher</title>
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <link href="../node_modules/video.js/dist/video-js.css" rel="stylesheet">
+ <link href="../lib/videojs-resolution-switcher.css" rel="stylesheet">
+ <style>
+ body {
+ font-family: Arial, sans-serif;
+ background: #777;
+ }
+ .info {
+ background-color: #eee;
+ border: thin solid #333;
+ border-radius: 3px;
+ padding: 0 5px;
+ text-align: center;
+ }
+ .video-js {
+ margin: 40px auto;
+ }
+ </style>
+</head>
+<body>
+ <div class="info">
+ <p>
+ Youtube tech
+ </p>
+ </div>
+
+ <video id='video' class="video-js vjs-default-skin"></video>
+
+ <script src="../node_modules/video.js/dist/video.js"></script>
+ <script src="../node_modules/videojs-youtube/dist/Youtube.js"></script>
+ <script src="../lib/videojs-resolution-switcher.js"></script>
+ <script>
+ // fire up the plugin
+ videojs('video', {
+ controls: true,
+ muted: true,
+ techOrder: ["youtube"],
+ width: 500,
+ sources: [{ "type": "video/youtube", "src": "https://www.youtube.com/watch?v=iD_MyDbP_ZE"}],
+ plugins: {
+ videoJsResolutionSwitcher: {
+ default: 'low',
+ dynamicLabel: true
+ }
+ }
+ }, function(){
+ var player = this;
+ window.player = player;
+ player.on('resolutionchange', function(){
+ console.info('Source changed')
+ })
+ });
+
+ </script>
+
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+.vjs-resolution-button {
+ color: #ccc;
+ font-family: VideoJS;
+}
+
+.vjs-resolution-button .vjs-resolution-button-staticlabel:before {
+ content: '\f110';
+ font-size: 1.8em;
+ line-height: 1.67;
+}
+
+.vjs-resolution-button .vjs-resolution-button-label {
+ font-size: 1em;
+ line-height: 3em;
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ text-align: center;
+ box-sizing: inherit;
+ font-family: Arial, Helvetica, sans-serif;
+}
+
+.vjs-resolution-button ul.vjs-menu-content {
+ width: 4em !important;
+}
+
+.vjs-resolution-button .vjs-menu {
+ left: 0;
+}
+
+.vjs-resolution-button .vjs-menu li {
+ text-transform: none;
+ font-size: 1em;
+ font-family: Arial, Helvetica, sans-serif;
+}
--- /dev/null
+/*! videojs-resolution-switcher - 2015-7-26
+ * Copyright (c) 2016 Kasper Moskwiak
+ * Modified by Pierre Kraft
+ * Licensed under the Apache-2.0 license. */
+
+(function() {
+ /* jshint eqnull: true*/
+ /* global require */
+ 'use strict';
+ var videojs = null;
+ if(typeof window.videojs === 'undefined' && typeof require === 'function') {
+ videojs = require('video.js');
+ } else {
+ videojs = window.videojs;
+ }
+
+ (function(window, videojs) {
+
+
+ var defaults = {},
+ videoJsResolutionSwitcher,
+ currentResolution = {}, // stores current resolution
+ menuItemsHolder = {}; // stores menuItems
+
+ function setSourcesSanitized(player, sources, label, customSourcePicker) {
+ currentResolution = {
+ label: label,
+ sources: sources
+ };
+ if(typeof customSourcePicker === 'function'){
+ return customSourcePicker(player, sources, label);
+ }
+ return player.src(sources.map(function(src) {
+ return {src: src.src, type: src.type, res: src.res};
+ }));
+ }
+
+ /*
+ * Resolution menu item
+ */
+ var MenuItem = videojs.getComponent('MenuItem');
+ var ResolutionMenuItem = videojs.extend(MenuItem, {
+ constructor: function(player, options, onClickListener, label){
+ this.onClickListener = onClickListener;
+ this.label = label;
+ // Sets this.player_, this.options_ and initializes the component
+ MenuItem.call(this, player, options);
+ this.src = options.src;
+
+ this.on('click', this.onClick);
+ this.on('touchstart', this.onClick);
+
+ if (options.initialySelected) {
+ this.showAsLabel();
+ this.selected(true);
+
+ this.addClass('vjs-selected');
+ }
+ },
+ showAsLabel: function() {
+ // Change menu button label to the label of this item if the menu button label is provided
+ if(this.label) {
+ this.label.innerHTML = this.options_.label;
+ }
+ },
+ onClick: function(customSourcePicker){
+ this.onClickListener(this);
+ // Remember player state
+ var currentTime = this.player_.currentTime();
+ var isPaused = this.player_.paused();
+ this.showAsLabel();
+
+ // add .current class
+ this.addClass('vjs-selected');
+
+ // Hide bigPlayButton
+ if(!isPaused){
+ this.player_.bigPlayButton.hide();
+ }
+ if(typeof customSourcePicker !== 'function' &&
+ typeof this.options_.customSourcePicker === 'function'){
+ customSourcePicker = this.options_.customSourcePicker;
+ }
+ // Change player source and wait for loadeddata event, then play video
+ // loadedmetadata doesn't work right now for flash.
+ // Probably because of https://github.com/videojs/video-js-swf/issues/124
+ // If player preload is 'none' and then loadeddata not fired. So, we need timeupdate event for seek handle (timeupdate doesn't work properly with flash)
+ var handleSeekEvent = 'loadeddata';
+ if(this.player_.techName_ !== 'Youtube' && this.player_.preload() === 'none' && this.player_.techName_ !== 'Flash') {
+ handleSeekEvent = 'timeupdate';
+ }
+ setSourcesSanitized(this.player_, this.src, this.options_.label, customSourcePicker).one(handleSeekEvent, function() {
+ this.player_.currentTime(currentTime);
+ this.player_.handleTechSeeked_();
+ if(!isPaused){
+ // Start playing and hide loadingSpinner (flash issue ?)
+ this.player_.play().handleTechSeeked_();
+ }
+ this.player_.trigger('resolutionchange');
+ });
+ }
+ });
+
+
+ /*
+ * Resolution menu button
+ */
+ var MenuButton = videojs.getComponent('MenuButton');
+ var ResolutionMenuButton = videojs.extend(MenuButton, {
+ constructor: function(player, options, settings, label){
+ this.sources = options.sources;
+ this.label = label;
+ this.label.innerHTML = options.initialySelectedLabel;
+ // Sets this.player_, this.options_ and initializes the component
+ MenuButton.call(this, player, options, settings);
+ this.controlText('Quality');
+
+ if(settings.dynamicLabel){
+ this.el().appendChild(label);
+ }else{
+ var staticLabel = document.createElement('span');
+ videojs.addClass(staticLabel, 'vjs-resolution-button-staticlabel');
+ this.el().appendChild(staticLabel);
+ }
+ },
+ createItems: function(){
+ var menuItems = [];
+ var labels = (this.sources && this.sources.label) || {};
+ var onClickUnselectOthers = function(clickedItem) {
+ menuItems.map(function(item) {
+ item.selected(item === clickedItem);
+ item.removeClass('vjs-selected');
+ });
+ };
+
+ for (var key in labels) {
+ if (labels.hasOwnProperty(key)) {
+ menuItems.push(new ResolutionMenuItem(
+ this.player_,
+ {
+ label: key,
+ src: labels[key],
+ initialySelected: key === this.options_.initialySelectedLabel,
+ customSourcePicker: this.options_.customSourcePicker
+ },
+ onClickUnselectOthers,
+ this.label));
+ // Store menu item for API calls
+ menuItemsHolder[key] = menuItems[menuItems.length - 1];
+ }
+ }
+ return menuItems;
+ }
+ });
+
+ /**
+ * Initialize the plugin.
+ * @param {object} [options] configuration for the plugin
+ */
+ videoJsResolutionSwitcher = function(options) {
+ var settings = videojs.mergeOptions(defaults, options),
+ player = this,
+ label = document.createElement('span'),
+ groupedSrc = {};
+
+ videojs.addClass(label, 'vjs-resolution-button-label');
+
+ /**
+ * Updates player sources or returns current source URL
+ * @param {Array} [src] array of sources [{src: '', type: '', label: '', res: ''}]
+ * @returns {Object|String|Array} videojs player object if used as setter or current source URL, object, or array of sources
+ */
+ player.updateSrc = function(src){
+ //Return current src if src is not given
+ if(!src){ return player.src(); }
+ // Dispose old resolution menu button before adding new sources
+ if(player.controlBar.resolutionSwitcher){
+ player.controlBar.resolutionSwitcher.dispose();
+ delete player.controlBar.resolutionSwitcher;
+ }
+ //Sort sources
+ src = src.sort(compareResolutions);
+ groupedSrc = bucketSources(src);
+ var choosen = chooseSrc(groupedSrc, src);
+ var menuButton = new ResolutionMenuButton(player, { sources: groupedSrc, initialySelectedLabel: choosen.label , initialySelectedRes: choosen.res , customSourcePicker: settings.customSourcePicker}, settings, label);
+ videojs.addClass(menuButton.el(), 'vjs-resolution-button');
+ player.controlBar.resolutionSwitcher = player.controlBar.el_.insertBefore(menuButton.el_, player.controlBar.getChild('fullscreenToggle').el_);
+ player.controlBar.resolutionSwitcher.dispose = function(){
+ this.parentNode.removeChild(this);
+ };
+ return setSourcesSanitized(player, choosen.sources, choosen.label);
+ };
+
+ /**
+ * Returns current resolution or sets one when label is specified
+ * @param {String} [label] label name
+ * @param {Function} [customSourcePicker] custom function to choose source. Takes 3 arguments: player, sources, label. Must return player object.
+ * @returns {Object} current resolution object {label: '', sources: []} if used as getter or player object if used as setter
+ */
+ player.currentResolution = function(label, customSourcePicker){
+ if(label == null) { return currentResolution; }
+ if(menuItemsHolder[label] != null){
+ menuItemsHolder[label].onClick(customSourcePicker);
+ }
+ return player;
+ };
+
+ /**
+ * Returns grouped sources by label, resolution and type
+ * @returns {Object} grouped sources: { label: { key: [] }, res: { key: [] }, type: { key: [] } }
+ */
+ player.getGroupedSrc = function(){
+ return groupedSrc;
+ };
+
+ /**
+ * Method used for sorting list of sources
+ * @param {Object} a - source object with res property
+ * @param {Object} b - source object with res property
+ * @returns {Number} result of comparation
+ */
+ function compareResolutions(a, b){
+ if(!a.res || !b.res){ return 0; }
+ return (+b.res)-(+a.res);
+ }
+
+ /**
+ * Group sources by label, resolution and type
+ * @param {Array} src Array of sources
+ * @returns {Object} grouped sources: { label: { key: [] }, res: { key: [] }, type: { key: [] } }
+ */
+ function bucketSources(src){
+ var resolutions = {
+ label: {},
+ res: {},
+ type: {}
+ };
+ src.map(function(source) {
+ initResolutionKey(resolutions, 'label', source);
+ initResolutionKey(resolutions, 'res', source);
+ initResolutionKey(resolutions, 'type', source);
+
+ appendSourceToKey(resolutions, 'label', source);
+ appendSourceToKey(resolutions, 'res', source);
+ appendSourceToKey(resolutions, 'type', source);
+ });
+ return resolutions;
+ }
+
+ function initResolutionKey(resolutions, key, source) {
+ if(resolutions[key][source[key]] == null) {
+ resolutions[key][source[key]] = [];
+ }
+ }
+
+ function appendSourceToKey(resolutions, key, source) {
+ resolutions[key][source[key]].push(source);
+ }
+
+ /**
+ * Choose src if option.default is specified
+ * @param {Object} groupedSrc {res: { key: [] }}
+ * @param {Array} src Array of sources sorted by resolution used to find high and low res
+ * @returns {Object} {res: string, sources: []}
+ */
+ function chooseSrc(groupedSrc, src){
+ var selectedRes = settings['default']; // use array access as default is a reserved keyword
+ var selectedLabel = '';
+ if (selectedRes === 'high') {
+ selectedRes = src[0].res;
+ selectedLabel = src[0].label;
+ } else if (selectedRes === 'low' || selectedRes == null || !groupedSrc.res[selectedRes]) {
+ // Select low-res if default is low or not set
+ selectedRes = src[src.length - 1].res;
+ selectedLabel = src[src.length -1].label;
+ } else if (groupedSrc.res[selectedRes]) {
+ selectedLabel = groupedSrc.res[selectedRes][0].label;
+ }
+
+ return {res: selectedRes, label: selectedLabel, sources: groupedSrc.res[selectedRes]};
+ }
+
+ function initResolutionForYt(player){
+ // Init resolution
+ player.tech_.ytPlayer.setPlaybackQuality('default');
+
+ // Capture events
+ player.tech_.ytPlayer.addEventListener('onPlaybackQualityChange', function(){
+ player.trigger('resolutionchange');
+ });
+
+ // We must wait for play event
+ player.one('play', function(){
+ var qualities = player.tech_.ytPlayer.getAvailableQualityLevels();
+ // Map youtube qualities names
+ var _yts = {
+ highres: {res: 1080, label: '1080', yt: 'highres'},
+ hd1080: {res: 1080, label: '1080', yt: 'hd1080'},
+ hd720: {res: 720, label: '720', yt: 'hd720'},
+ large: {res: 480, label: '480', yt: 'large'},
+ medium: {res: 360, label: '360', yt: 'medium'},
+ small: {res: 240, label: '240', yt: 'small'},
+ tiny: {res: 144, label: '144', yt: 'tiny'},
+ auto: {res: 0, label: 'auto', yt: 'default'}
+ };
+
+ var _sources = [];
+
+ qualities.map(function(q){
+ _sources.push({
+ src: player.src().src,
+ type: player.src().type,
+ label: _yts[q].label,
+ res: _yts[q].res,
+ _yt: _yts[q].yt
+ });
+ });
+
+ groupedSrc = bucketSources(_sources);
+
+ // Overwrite defualt sourcePicer function
+ var _customSourcePicker = function(_player, _sources, _label){
+ player.tech_.ytPlayer.setPlaybackQuality(_sources[0]._yt);
+ return player;
+ };
+
+ var choosen = {label: 'auto', res: 0, sources: groupedSrc.label.auto};
+ var menuButton = new ResolutionMenuButton(player, {
+ sources: groupedSrc,
+ initialySelectedLabel: choosen.label,
+ initialySelectedRes: choosen.res,
+ customSourcePicker: _customSourcePicker
+ }, settings, label);
+
+ menuButton.el().classList.add('vjs-resolution-button');
+ player.controlBar.resolutionSwitcher = player.controlBar.addChild(menuButton);
+ });
+ }
+
+ player.ready(function(){
+ if(player.options_.sources.length > 1){
+ // tech: Html5 and Flash
+ // Create resolution switcher for videos form <source> tag inside <video>
+ player.updateSrc(player.options_.sources);
+ }
+
+ if(player.techName_ === 'Youtube'){
+ // tech: YouTube
+ initResolutionForYt(player);
+ }
+ });
+
+ };
+
+ // register the plugin
+ videojs.plugin('videoJsResolutionSwitcher', videoJsResolutionSwitcher);
+ })(window, videojs);
+})();
--- /dev/null
+{
+ "_args": [
+ [
+ {
+ "raw": "videojs-resolution-switcher",
+ "scope": null,
+ "escapedName": "videojs-resolution-switcher",
+ "name": "videojs-resolution-switcher",
+ "rawSpec": "",
+ "spec": "latest",
+ "type": "tag"
+ },
+ "/home/vijeth"
+ ]
+ ],
+ "_from": "videojs-resolution-switcher@latest",
+ "_id": "videojs-resolution-switcher@0.4.2",
+ "_inCache": true,
+ "_installable": true,
+ "_location": "/videojs-resolution-switcher",
+ "_nodeVersion": "5.3.0",
+ "_npmOperationalInternal": {
+ "host": "packages-12-west.internal.npmjs.com",
+ "tmp": "tmp/videojs-resolution-switcher-0.4.2.tgz_1459876920307_0.39970111404545605"
+ },
+ "_npmUser": {
+ "name": "cosma",
+ "email": "kasper.moskwiak@gmail.com"
+ },
+ "_npmVersion": "3.5.2",
+ "_phantomChildren": {},
+ "_requested": {
+ "raw": "videojs-resolution-switcher",
+ "scope": null,
+ "escapedName": "videojs-resolution-switcher",
+ "name": "videojs-resolution-switcher",
+ "rawSpec": "",
+ "spec": "latest",
+ "type": "tag"
+ },
+ "_requiredBy": [
+ "#USER"
+ ],
+ "_resolved": "https://registry.npmjs.org/videojs-resolution-switcher/-/videojs-resolution-switcher-0.4.2.tgz",
+ "_shasum": "53ef38c58e95b90a61a7452de8177ee838a26405",
+ "_shrinkwrap": null,
+ "_spec": "videojs-resolution-switcher",
+ "_where": "/home/vijeth",
+ "author": {
+ "name": "Kasper Moskwiak",
+ "email": "kasper.moskwiak@gmail.com",
+ "url": "http://kspr.pl"
+ },
+ "bugs": {
+ "url": "https://github.com/kmoskwiak/videojs-resolution-switcher/issues"
+ },
+ "contributors": [
+ {
+ "name": "Pierre Kraft"
+ }
+ ],
+ "dependencies": {},
+ "description": "Resolution switcher for video.js 5",
+ "devDependencies": {
+ "grunt": "^0.4.5",
+ "grunt-contrib-clean": "^1.0",
+ "grunt-contrib-concat": "^1.0",
+ "grunt-contrib-jshint": "^1.0",
+ "grunt-contrib-qunit": "^1.1",
+ "grunt-contrib-uglify": "^1.0",
+ "grunt-contrib-watch": "^1.0",
+ "qunitjs": "^1.22",
+ "video.js": "^5.8",
+ "videojs-youtube": "^2.0.8"
+ },
+ "directories": {},
+ "dist": {
+ "shasum": "53ef38c58e95b90a61a7452de8177ee838a26405",
+ "tarball": "https://registry.npmjs.org/videojs-resolution-switcher/-/videojs-resolution-switcher-0.4.2.tgz"
+ },
+ "gitHead": "56760f6314d6b7ac9bfa24c16dce33e736cd9a97",
+ "homepage": "https://github.com/kmoskwiak/videojs-resolution-switcher#readme",
+ "keywords": [
+ "videojs",
+ "html5",
+ "flash",
+ "video",
+ "player",
+ "resolution",
+ "source",
+ "videojs-plugin"
+ ],
+ "license": "Apache-2.0",
+ "main": "./lib/videojs-resolution-switcher.js",
+ "maintainers": [
+ {
+ "name": "cosma",
+ "email": "kasper.moskwiak@gmail.com"
+ }
+ ],
+ "name": "videojs-resolution-switcher",
+ "optionalDependencies": {},
+ "peerDependencies": {
+ "video.js": "^5.8"
+ },
+ "readme": "ERROR: No README data found!",
+ "repository": {
+ "type": "git",
+ "url": "git+ssh://git@github.com/kmoskwiak/videojs-resolution-switcher.git"
+ },
+ "scripts": {
+ "test": "grunt test"
+ },
+ "version": "0.4.2"
+}
--- /dev/null
+../../../extlib/videojs-resolution-switcher/lib/
\ No newline at end of file