videojs 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d48a634490554059c4ec9ffd3299da1f6f1a0e10
4
+ data.tar.gz: 4019947bedc5c89290e9b819d06feab677c3271a
5
+ SHA512:
6
+ metadata.gz: 63984d251c9ea2a11e3293fdf099cc32c4bb9714f0b7b0ab42563db14362005218a80e7396d539c7b2ccd4dfb1c3761765a98525d02454f1e9a0c224a16ea136
7
+ data.tar.gz: 5dbcd9f78ddc4dbeacd3c35b87ecc5f6cbf88c6edd3664cb7e1bbe898592124ba28324da8abf483afff15f533bbdd03c39c8243813b63414606b93fd34f574b5
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 JiriKolarik
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,29 @@
1
+ # Videojs
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'videojs'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install videojs
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
@@ -0,0 +1,4 @@
1
+ require 'videojs/engine' if defined? Rails
2
+
3
+ module Videojs
4
+ end
@@ -0,0 +1,4 @@
1
+ module Videojs
2
+ class Engine < ::Rails::Engine
3
+ end
4
+ end
@@ -0,0 +1,3 @@
1
+ module Videojs
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,65 @@
1
+ <?xml version="1.0" standalone="no"?>
2
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
3
+ <svg xmlns="http://www.w3.org/2000/svg">
4
+ <metadata>
5
+ This is a custom SVG font generated by IcoMoon.
6
+ <iconset grid="16"></iconset>
7
+ </metadata>
8
+ <defs>
9
+ <font id="VideoJS" horiz-adv-x="512" >
10
+ <font-face units-per-em="512" ascent="480" descent="-32" />
11
+ <missing-glyph horiz-adv-x="512" />
12
+ <glyph class="hidden" unicode="&#xf000;" d="M0,480L 512 -32L0 -32 z" horiz-adv-x="0" />
13
+ <glyph unicode="&#xe002;" d="M 64,416L 224,416L 224,32L 64,32zM 288,416L 448,416L 448,32L 288,32z" />
14
+ <glyph unicode="&#xe003;" d="M 200.666,440.666 C 213.5,453.5 224,449.15 224,431 L 224,17 C 224-1.15 213.5-5.499 200.666,7.335 L 80,128 L 0,128 L 0,320 L 80,320 L 200.666,440.666 Z" />
15
+ <glyph unicode="&#xe004;" d="M 274.51,109.49c-6.143,0-12.284,2.343-16.971,7.029c-9.373,9.373-9.373,24.568,0,33.941
16
+ c 40.55,40.55, 40.55,106.529,0,147.078c-9.373,9.373-9.373,24.569,0,33.941c 9.373,9.372, 24.568,9.372, 33.941,0
17
+ c 59.265-59.265, 59.265-155.696,0-214.961C 286.794,111.833, 280.652,109.49, 274.51,109.49zM 200.666,440.666 C 213.5,453.5 224,449.15 224,431 L 224,17 C 224-1.15 213.5-5.499 200.666,7.335 L 80,128 L 0,128 L 0,320 L 80,320 L 200.666,440.666 Z" />
18
+ <glyph unicode="&#xe005;" d="M 359.765,64.235c-6.143,0-12.284,2.343-16.971,7.029c-9.372,9.372-9.372,24.568,0,33.941
19
+ c 65.503,65.503, 65.503,172.085,0,237.588c-9.372,9.373-9.372,24.569,0,33.941c 9.372,9.371, 24.569,9.372, 33.941,0
20
+ C 417.532,335.938, 440,281.696, 440,224c0-57.695-22.468-111.938-63.265-152.735C 372.049,66.578, 365.907,64.235, 359.765,64.235zM 274.51,109.49c-6.143,0-12.284,2.343-16.971,7.029c-9.373,9.373-9.373,24.568,0,33.941
21
+ c 40.55,40.55, 40.55,106.529,0,147.078c-9.373,9.373-9.373,24.569,0,33.941c 9.373,9.372, 24.568,9.372, 33.941,0
22
+ c 59.265-59.265, 59.265-155.696,0-214.961C 286.794,111.833, 280.652,109.49, 274.51,109.49zM 200.666,440.666 C 213.5,453.5 224,449.15 224,431 L 224,17 C 224-1.15 213.5-5.499 200.666,7.335 L 80,128 L 0,128 L 0,320 L 80,320 L 200.666,440.666 Z" />
23
+ <glyph unicode="&#xe006;" d="M 445.020,18.98c-6.143,0-12.284,2.343-16.971,7.029c-9.372,9.373-9.372,24.568,0,33.941
24
+ C 471.868,103.771, 496.001,162.030, 496.001,224c0,61.969-24.133,120.229-67.952,164.049c-9.372,9.373-9.372,24.569,0,33.941
25
+ c 9.372,9.372, 24.569,9.372, 33.941,0c 52.885-52.886, 82.011-123.2, 82.011-197.99c0-74.791-29.126-145.104-82.011-197.99
26
+ C 457.304,21.323, 451.162,18.98, 445.020,18.98zM 359.765,64.235c-6.143,0-12.284,2.343-16.971,7.029c-9.372,9.372-9.372,24.568,0,33.941
27
+ c 65.503,65.503, 65.503,172.085,0,237.588c-9.372,9.373-9.372,24.569,0,33.941c 9.372,9.371, 24.569,9.372, 33.941,0
28
+ C 417.532,335.938, 440,281.696, 440,224c0-57.695-22.468-111.938-63.265-152.735C 372.049,66.578, 365.907,64.235, 359.765,64.235zM 274.51,109.49c-6.143,0-12.284,2.343-16.971,7.029c-9.373,9.373-9.373,24.568,0,33.941
29
+ c 40.55,40.55, 40.55,106.529,0,147.078c-9.373,9.373-9.373,24.569,0,33.941c 9.373,9.372, 24.568,9.372, 33.941,0
30
+ c 59.265-59.265, 59.265-155.696,0-214.961C 286.794,111.833, 280.652,109.49, 274.51,109.49zM 200.666,440.666 C 213.5,453.5 224,449.15 224,431 L 224,17 C 224-1.15 213.5-5.499 200.666,7.335 L 80,128 L 0,128 L 0,320 L 80,320 L 200.666,440.666 Z" horiz-adv-x="544" />
31
+ <glyph unicode="&#xe007;" d="M 256,480L 96,224L 256-32L 416,224 z" />
32
+ <glyph unicode="&#xe008;" d="M 0,480 L 687.158,480 L 687.158-35.207 L 0-35.207 L 0,480 z M 622.731,224.638 C 621.878,314.664 618.46,353.922 597.131,381.656 C 593.291,387.629 586.038,391.042 580.065,395.304 C 559.158,410.669 460.593,416.211 346.247,416.211 C 231.896,416.211 128.642,410.669 108.162,395.304 C 101.762,391.042 94.504,387.629 90.242,381.656 C 69.331,353.922 66.349,314.664 65.069,224.638 C 66.349,134.607 69.331,95.353 90.242,67.62 C 94.504,61.22 101.762,58.233 108.162,53.967 C 128.642,38.18 231.896,33.060 346.247,32.207 C 460.593,33.060 559.158,38.18 580.065,53.967 C 586.038,58.233 593.291,61.22 597.131,67.62 C 618.46,95.353 621.878,134.607 622.731,224.638 z M 331.179,247.952 C 325.389,318.401 287.924,359.905 220.901,359.905 C 159.672,359.905 111.54,304.689 111.54,215.965 C 111.54,126.859 155.405,71.267 227.907,71.267 C 285.79,71.267 326.306,113.916 332.701,184.742 L 263.55,184.742 C 260.81,158.468 249.843,138.285 226.69,138.285 C 190.136,138.285 183.435,174.462 183.435,212.92 C 183.435,265.854 198.665,292.886 223.951,292.886 C 246.492,292.886 260.81,276.511 262.939,247.952 L 331.179,247.952 z M 570.013,247.952 C 564.228,318.401 526.758,359.905 459.74,359.905 C 398.507,359.905 350.379,304.689 350.379,215.965 C 350.379,126.859 394.244,71.267 466.746,71.267 C 524.625,71.267 565.14,113.916 571.536,184.742 L 502.384,184.742 C 499.649,158.468 488.682,138.285 465.529,138.285 C 428.971,138.285 422.27,174.462 422.27,212.92 C 422.27,265.854 437.504,292.886 462.785,292.886 C 485.327,292.886 499.649,276.511 501.778,247.952 L 570.013,247.952 z " horiz-adv-x="687.158" />
33
+ <glyph unicode="&#xe009;" d="M 64,416L 448,416L 448,32L 64,32z" />
34
+ <glyph unicode="&#xe00a;" d="M 192,416A64,64 12780 1 1 320,416A64,64 12780 1 1 192,416zM 327.765,359.765A64,64 12780 1 1 455.765,359.765A64,64 12780 1 1 327.765,359.765zM 416,224A32,32 12780 1 1 480,224A32,32 12780 1 1 416,224zM 359.765,88.235A32,32 12780 1 1 423.765,88.23500000000001A32,32 12780 1 1 359.765,88.23500000000001zM 224.001,32A32,32 12780 1 1 288.001,32A32,32 12780 1 1 224.001,32zM 88.236,88.235A32,32 12780 1 1 152.236,88.23500000000001A32,32 12780 1 1 88.236,88.23500000000001zM 72.236,359.765A48,48 12780 1 1 168.236,359.765A48,48 12780 1 1 72.236,359.765zM 28,224A36,36 12780 1 1 100,224A36,36 12780 1 1 28,224z" />
35
+ <glyph unicode="&#xe00b;" d="M 224,192 L 224-16 L 144,64 L 48-32 L 0,16 L 96,112 L 16,192 ZM 512,432 L 416,336 L 496,256 L 288,256 L 288,464 L 368,384 L 464,480 Z" />
36
+ <glyph unicode="&#xe00c;" d="M 256,448 C 397.385,448 512,354.875 512,240 C 512,125.124 397.385,32 256,32 C 242.422,32 229.095,32.867 216.088,34.522 C 161.099-20.467 95.463-30.328 32-31.776 L 32-18.318 C 66.268-1.529 96,29.052 96,64 C 96,68.877 95.621,73.665 94.918,78.348 C 37.020,116.48 0,174.725 0,240 C 0,354.875 114.615,448 256,448 Z" />
37
+ <glyph unicode="&#xe00d;" d="M 256,480C 114.615,480,0,365.385,0,224s 114.615-256, 256-256s 256,114.615, 256,256S 397.385,480, 256,480z M 256,352
38
+ c 70.692,0, 128-57.308, 128-128s-57.308-128-128-128s-128,57.308-128,128S 185.308,352, 256,352z M 408.735,71.265
39
+ C 367.938,30.468, 313.695,8, 256,8c-57.696,0-111.938,22.468-152.735,63.265C 62.468,112.062, 40,166.304, 40,224
40
+ c0,57.695, 22.468,111.938, 63.265,152.735l 33.941-33.941c0,0,0,0,0,0c-65.503-65.503-65.503-172.085,0-237.588
41
+ C 168.937,73.475, 211.125,56, 256,56c 44.874,0, 87.062,17.475, 118.794,49.206c 65.503,65.503, 65.503,172.084,0,237.588l 33.941,33.941
42
+ C 449.532,335.938, 472,281.695, 472,224C 472,166.304, 449.532,112.062, 408.735,71.265z" />
43
+ <glyph unicode="&#xe01e;" d="M 512,224c-0.639,33.431-7.892,66.758-21.288,97.231c-13.352,30.5-32.731,58.129-56.521,80.96
44
+ c-23.776,22.848-51.972,40.91-82.492,52.826C 321.197,466.979, 288.401,472.693, 256,472c-32.405-0.641-64.666-7.687-94.167-20.678
45
+ c-29.524-12.948-56.271-31.735-78.367-54.788c-22.112-23.041-39.58-50.354-51.093-79.899C 20.816,287.104, 15.309,255.375, 16,224
46
+ c 0.643-31.38, 7.482-62.574, 20.067-91.103c 12.544-28.55, 30.738-54.414, 53.055-75.774c 22.305-21.377, 48.736-38.252, 77.307-49.36
47
+ C 194.988-3.389, 225.652-8.688, 256-8c 30.354,0.645, 60.481,7.277, 88.038,19.457c 27.575,12.141, 52.558,29.74, 73.183,51.322
48
+ c 20.641,21.57, 36.922,47.118, 47.627,74.715c 6.517,16.729, 10.94,34.2, 13.271,51.899c 0.623-0.036, 1.249-0.060, 1.881-0.060
49
+ c 17.673,0, 32,14.326, 32,32c0,0.898-0.047,1.786-0.119,2.666L 512,223.999 z M 461.153,139.026c-11.736-26.601-28.742-50.7-49.589-70.59
50
+ c-20.835-19.905-45.5-35.593-72.122-45.895C 312.828,12.202, 284.297,7.315, 256,8c-28.302,0.649-56.298,6.868-81.91,18.237
51
+ c-25.625,11.333-48.842,27.745-67.997,47.856c-19.169,20.099-34.264,43.882-44.161,69.529C 51.997,169.264, 47.318,196.729, 48,224
52
+ c 0.651,27.276, 6.664,54.206, 17.627,78.845c 10.929,24.65, 26.749,46.985, 46.123,65.405c 19.365,18.434, 42.265,32.935, 66.937,42.428
53
+ C 203.356,420.208, 229.755,424.681, 256,424c 26.25-0.653, 52.114-6.459, 75.781-17.017c 23.676-10.525, 45.128-25.751, 62.812-44.391
54
+ c 17.698-18.629, 31.605-40.647, 40.695-64.344C 444.412,274.552, 448.679,249.219, 448,224l 0.119,0 c-0.072-0.88-0.119-1.768-0.119-2.666
55
+ c0-16.506, 12.496-30.087, 28.543-31.812C 473.431,172.111, 468.278,155.113, 461.153,139.026z" />
56
+ <glyph unicode="&#xe01f;" d="M 256,480 C 116.626,480 3.271,368.619 0.076,230.013 C 3.036,350.945 94.992,448 208,448 C 322.875,448 416,347.712 416,224 C 416,197.49 437.49,176 464,176 C 490.51,176 512,197.49 512,224 C 512,365.385 397.385,480 256,480 ZM 256-32 C 395.374-32 508.729,79.381 511.924,217.987 C 508.964,97.055 417.008,0 304,0 C 189.125,0 96,100.288 96,224 C 96,250.51 74.51,272 48,272 C 21.49,272 0,250.51 0,224 C 0,82.615 114.615-32 256-32 Z" />
57
+ <glyph unicode="&#xe00e;" d="M 432,128c-22.58,0-42.96-9.369-57.506-24.415L 158.992,211.336C 159.649,215.462, 160,219.689, 160,224
58
+ s-0.351,8.538-1.008,12.663l 215.502,107.751C 389.040,329.369, 409.42,320, 432,320c 44.183,0, 80,35.817, 80,80S 476.183,480, 432,480
59
+ s-80-35.817-80-80c0-4.311, 0.352-8.538, 1.008-12.663L 137.506,279.585C 122.96,294.63, 102.58,304, 80,304c-44.183,0-80-35.818-80-80
60
+ c0-44.184, 35.817-80, 80-80c 22.58,0, 42.96,9.369, 57.506,24.414l 215.502-107.751C 352.352,56.538, 352,52.311, 352,48
61
+ c0-44.184, 35.817-80, 80-80s 80,35.816, 80,80C 512,92.182, 476.183,128, 432,128z" />
62
+ <glyph unicode="&#xe001;" d="M 96,416L 416,224L 96,32 z" />
63
+ <glyph unicode="&#xe000;" d="M 512,480 L 512,272 L 432,352 L 336,256 L 288,304 L 384,400 L 304,480 ZM 224,144 L 128,48 L 208-32 L 0-32 L 0,176 L 80,96 L 176,192 Z" />
64
+ <glyph unicode="&#x20;" horiz-adv-x="256" />
65
+ </font></defs></svg>
@@ -0,0 +1,432 @@
1
+ // Resolution switching support for videojs
2
+ //
3
+ // In this plugin I'm really going out of my way to *not* override the
4
+ // core videojs namespace and to *not* change the core API. As a
5
+ // result this plugin is not as efficient as it might be. It
6
+ // initializes itself *for each player* as scoped variables inside the
7
+ // plugin closure and grafts itself on to *the instance on which it was
8
+ // called* rather than on the videojs player prototype. I don't expect
9
+ // this to be a big deal for anybody.
10
+ videojs.plugin('resolutions', function(options) {
11
+ var player = this;
12
+
13
+ // 'reduce' utility method
14
+ // @param {Array} array to iterate over
15
+ // @param {Function} iterator function for collector
16
+ // @param {Array|Object|Number|String} initial collector
17
+ // @return collector
18
+ vjs.reduce = function(arr, fn, init, n) {
19
+ if (!arr || arr.length === 0) { return; }
20
+ for (var i=0,j=arr.length; i<j; i++) {
21
+ init = fn.call(arr, init, arr[i], i);
22
+ }
23
+ return init;
24
+ };
25
+
26
+ this.resolutions_ = {
27
+ options_: {},
28
+
29
+ // takes an existing stream and stops the download entirely
30
+ // without killing the player or disposing of the tech
31
+ stopStream: function(){
32
+ switch(player.techName){
33
+ case "Html5":
34
+ break;
35
+ case "Flash":
36
+ player.tech.el_.vjs_stop();
37
+ break;
38
+ }
39
+
40
+ // this may cause flash or the native player to emit errors but
41
+ // they are harmless
42
+ player.src("");
43
+ },
44
+
45
+ // it is necessary to remove the sources from the DOM after
46
+ // parsing them because otherwise the native player may be
47
+ // inclined to stream both sources
48
+ removeSources: function(el){
49
+ var videoEl = player.el_.getElementsByTagName("video")[0];
50
+
51
+ if (player.techName !== "Html5" || !videoEl) return;
52
+
53
+ var srcs = videoEl.getElementsByTagName("source");
54
+ for(var i=0;i<srcs.length;i++){
55
+ videoEl.removeChild(srcs[i]);
56
+ }
57
+ },
58
+
59
+ // buckets all parsed sources by their type ("video/mp4", for example)
60
+ // @param {Array} array of sources:
61
+ // [
62
+ // {
63
+ // "data-res": "HD",
64
+ // "type": "video/mp4",
65
+ // "src": "http://some_video_url_hd"
66
+ // },
67
+ // {
68
+ // "data-default": "true",
69
+ // "data-res": "SD",
70
+ // "type": "video/mp4",
71
+ // "src": "http://some_video_url_sd"
72
+ // },
73
+ // {
74
+ // "data-default": "true",
75
+ // "data-res": "SD",
76
+ // "type": "video/ogv",
77
+ // "src": "http://some_video_url_sd"
78
+ // }
79
+ // ]
80
+ // @return sources grouped by type:
81
+ // {
82
+ // "video/mp4": [
83
+ // {
84
+ // "data-res": "HD",
85
+ // "type": "video/mp4",
86
+ // "src": "http://some_video_url_hd"
87
+ // },
88
+ // {
89
+ // "data-default": "true",
90
+ // "data-res": "SD",
91
+ // "type": "video/mp4",
92
+ // "src": "http://some_video_url_sd"
93
+ // }
94
+ // ]
95
+ // "video/ogv": [
96
+ // {
97
+ // "data-res": "SD",
98
+ // "type": "video/ogv",
99
+ // "src": "http://some_video_url_sd"
100
+ // }
101
+ // ]
102
+ // }
103
+ bucketByTypes: function(sources){
104
+ return vjs.reduce(sources, function(init, val, i){
105
+ (init[val.type] = init[val.type] || []).push(val);
106
+ return init;
107
+ }, {}, player);
108
+ },
109
+
110
+ // takes parsed sources and selects the most appropriate source
111
+ // taking into account resolution, technology support, and the
112
+ // user's previous selections. also indexes the sources
113
+ // @param {Array} array of sources:
114
+ // [
115
+ // {
116
+ // "data-res": "HD",
117
+ // "type": "video/mp4",
118
+ // "src": "http://some_video_url_hd"
119
+ // },
120
+ // {
121
+ // "data-default": "true",
122
+ // "data-res": "SD",
123
+ // "type": "video/mp4",
124
+ // "src": "http://some_video_url_sd"
125
+ // },
126
+ // {
127
+ // "data-default": "true",
128
+ // "data-res": "SD",
129
+ // "type": "video/ogv",
130
+ // "src": "http://some_video_url_sd"
131
+ // }
132
+ // ]
133
+ // @return {Object} single source:
134
+ // {
135
+ // "data-res": "HD",
136
+ // "type": "video/mp4",
137
+ // "src": "http://some_video_url_jd",
138
+ // "index": 0
139
+ // }
140
+ selectSource: function(sources){
141
+ this.removeSources();
142
+
143
+ var sourcesByType = this.bucketByTypes(sources);
144
+ var typeAndTech = this.selectTypeAndTech(sources);
145
+
146
+ if (!typeAndTech) return false;
147
+
148
+ // even though we choose the best resolution for the user here, we
149
+ // should remember the resolutions so that we can potentially
150
+ // change resolution later
151
+ this.options_['sourceResolutions'] = sourcesByType[typeAndTech.type];
152
+
153
+ return this.selectResolution(this.options_['sourceResolutions']);
154
+ },
155
+
156
+ // takes parsed sources and returns the most appropriate
157
+ // technology and video type
158
+ // @param {Array} array of sources:
159
+ // [
160
+ // {
161
+ // "data-res": "HD",
162
+ // "type": "video/mp4",
163
+ // "src": "http://some_video_url_hd"
164
+ // },
165
+ // {
166
+ // "data-default": "true",
167
+ // "data-res": "SD",
168
+ // "type": "video/mp4",
169
+ // "src": "http://some_video_url_sd"
170
+ // },
171
+ // {
172
+ // "data-default": "true",
173
+ // "data-res": "SD",
174
+ // "type": "video/ogv",
175
+ // "src": "http://some_video_url_sd"
176
+ // }
177
+ // ]
178
+ // @return {Object} type/tech:
179
+ // {
180
+ // "type": "video/ogv",
181
+ // "tech": "Html5"
182
+ // }
183
+ selectTypeAndTech: function(sources) {
184
+ var techName;
185
+ var tech;
186
+
187
+ for (var i=0,j=player.options_['techOrder'];i<j.length;i++) {
188
+ techName = videojs.capitalize(j[i]);
189
+ tech = window['videojs'][techName];
190
+
191
+ // Check if the browser supports this technology
192
+ if (tech.isSupported()) {
193
+ // Loop through each source object
194
+ for (var a=0,b=sources;a<b.length;a++) {
195
+ var source = b[a];
196
+ // Check if source can be played with this technology
197
+ if (tech['canPlaySource'](source)) {
198
+ return { type: source.type, tech: techName };
199
+ }
200
+ }
201
+ }
202
+ }
203
+ },
204
+
205
+ // takes an array of sources of homogeneous type (ie. a complete
206
+ // "bucket" from the output of bucketByTypes) and returns the best
207
+ // source, taking into account the user's previous preferences
208
+ // stored in local storage
209
+ // @param {Array} homogeneous sources:
210
+ // [
211
+ // {
212
+ // "data-res": "HD",
213
+ // "type": "video/mp4",
214
+ // "src": "http://some_video_url_hd"
215
+ // },
216
+ // {
217
+ // "data-default": "true",
218
+ // "data-res": "SD",
219
+ // "type": "video/mp4",
220
+ // "src": "http://some_video_url_sd"
221
+ // }
222
+ // ]
223
+ // @return {Object} singular best source:
224
+ // {
225
+ // "data-default": "true",
226
+ // "data-res": "SD",
227
+ // "type": "video/mp4",
228
+ // "src": "http://some_video_url_sd"
229
+ // "index": 1
230
+ // }
231
+ selectResolution: function(typeSources) {
232
+ var defaultRes = 0;
233
+ var supportsLocalStorage = !!window.localStorage;
234
+
235
+ // check to see if any sources are marked as default
236
+ videojs.obj.each(typeSources, function(i, s){
237
+ // add the index here so we can reference it later
238
+ s.index = parseInt(i, 10);
239
+
240
+ if (s['data-default']) defaultRes = s.index;
241
+ }, player);
242
+
243
+ // if the user has previously selected a preference, check if
244
+ // that preference is available. if not, use the source marked
245
+ // default
246
+ var preferredRes = defaultRes;
247
+
248
+ // trying to follow the videojs code conventions of if statements
249
+ if (supportsLocalStorage){
250
+ var storedRes = parseInt(window.localStorage.getItem('videojs_preferred_res'), 10);
251
+
252
+ if (!isNaN(storedRes))
253
+ preferredRes = storedRes;
254
+ }
255
+
256
+ var maxRes = (typeSources.length - 1);
257
+ var actualRes = preferredRes > maxRes ? maxRes : preferredRes;
258
+
259
+ return typeSources[actualRes];
260
+ }
261
+ };
262
+
263
+ // convenience method
264
+ // @return {String} cached resolution label:
265
+ // "SD"
266
+ player.resolution = function(){
267
+ return this.cache_.src.res;
268
+ };
269
+
270
+ // takes a source and switches the player's stream to it on the fly
271
+ // @param {Object} singular source:
272
+ // {
273
+ // "data-default": "true",
274
+ // "data-res": "SD",
275
+ // "type": "video/mp4",
276
+ // "src": "http://some_video_url_sd"
277
+ // }
278
+ player.changeResolution = function(new_source){
279
+ // has the exact same source been chosen?
280
+ if (this.cache_.src === new_source.src){
281
+ this.trigger('resolutionchange');
282
+ return this; // basically a no-op
283
+ }
284
+
285
+ // remember our position and playback state
286
+ var curTime = this.currentTime();
287
+ var remainPaused = this.paused();
288
+
289
+ // pause playback
290
+ this.pause();
291
+
292
+ // attempts to stop the download of the existing video
293
+ this.resolutions_.stopStream();
294
+
295
+ // HTML5 tends to not recover from reloading the tech but it can
296
+ // generally handle changing src. Flash generally cannot handle
297
+ // changing src but can reload its tech.
298
+ if (this.techName === "Html5"){
299
+ this.src(new_source.src);
300
+ } else {
301
+ this.loadTech(this.techName, {src: new_source.src});
302
+ }
303
+
304
+ // when the technology is re-started, kick off the new stream
305
+ this.ready(function() {
306
+ this.one('loadeddata', vjs.bind(this, function() {
307
+ this.currentTime(curTime);
308
+ }));
309
+
310
+ this.trigger('resolutionchange');
311
+
312
+ if (!remainPaused) {
313
+ this.load();
314
+ this.play();
315
+ }
316
+
317
+ // remember this selection
318
+ vjs.setLocalStorage('videojs_preferred_res', parseInt(new_source.index, 10));
319
+ });
320
+ };
321
+
322
+ /* Resolution Menu Items
323
+ ================================================================================ */
324
+ var ResolutionMenuItem = videojs.MenuItem.extend({
325
+ init: function(player, options){
326
+ // Modify options for parent MenuItem class's init.
327
+ options['label'] = options.source['data-res'];
328
+ videojs.MenuItem.call(this, player, options);
329
+
330
+ this.source = options.source;
331
+ this.resolution = options.source['data-res'];
332
+
333
+ this.player_.one('loadstart', vjs.bind(this, this.update));
334
+ this.player_.on('resolutionchange', vjs.bind(this, this.update));
335
+ }
336
+ });
337
+
338
+ ResolutionMenuItem.prototype.onClick = function(){
339
+ videojs.MenuItem.prototype.onClick.call(this);
340
+ this.player_.changeResolution(this.source);
341
+ };
342
+
343
+ ResolutionMenuItem.prototype.update = function(){
344
+ var player = this.player_;
345
+ if ((player.cache_['src'] === this.source.src)) {
346
+ this.selected(true);
347
+ } else {
348
+ this.selected(false);
349
+ }
350
+ };
351
+
352
+ /* Resolutions Button
353
+ ================================================================================ */
354
+ var ResolutionButton = videojs.MenuButton.extend({
355
+ init: function(player, options) {
356
+ videojs.MenuButton.call(this, player, options);
357
+
358
+ if (this.items.length <= 1) {
359
+ this.hide();
360
+ }
361
+ }
362
+ });
363
+
364
+ ResolutionButton.prototype.sourceResolutions_;
365
+
366
+ ResolutionButton.prototype.sourceResolutions = function() {
367
+ return this.sourceResolutions_;
368
+ };
369
+
370
+ ResolutionButton.prototype.onClick = function(e){
371
+ // Only proceed if the target of the click was a DIV (just the button and its inner div, not the menu)
372
+ // This prevents the menu from opening and closing when one of the menu items is clicked.
373
+ if (e.target.className.match(/vjs-control-content/)) {
374
+
375
+ // Toggle the 'touched' class
376
+ this[this.el_.className.match(/touched/) ? "removeClass" : "addClass"]("touched");
377
+ } else {
378
+
379
+ // Remove the 'touched' class from all control bar buttons with menus to hide any already visible...
380
+ var buttons = document.getElementsByClassName('vjs-menu-button');
381
+ for(var i=0;i<buttons.length;i++){
382
+ videojs.removeClass(buttons[i], 'touched');
383
+ }
384
+
385
+ this.removeClass('touched');
386
+ }
387
+ };
388
+
389
+ ResolutionButton.prototype.createItems = function(){
390
+ var resolutions = this.sourceResolutions_ = this.player_.resolutions_.options_['sourceResolutions'];
391
+ var items = [];
392
+ for (var i = 0; i < resolutions.length; i++) {
393
+ items.push(new ResolutionMenuItem(this.player_, {
394
+ 'source': this.sourceResolutions_[i]
395
+ }));
396
+ }
397
+ return items;
398
+ };
399
+
400
+ /**
401
+ * @constructor
402
+ */
403
+ ResolutionsButton = ResolutionButton.extend({
404
+ /** @constructor */
405
+ init: function(player, options, ready){
406
+ ResolutionButton.call(this, player, options, ready);
407
+ this.el_.setAttribute('aria-label','Resolutions Menu');
408
+ this.el_.setAttribute('id',"vjs-resolutions-button");
409
+ }
410
+ });
411
+
412
+ ResolutionsButton.prototype.kind_ = 'resolutions';
413
+ ResolutionsButton.prototype.buttonText = 'Resolutions';
414
+ ResolutionsButton.prototype.className = 'vjs-resolutions-button';
415
+
416
+ // Add Button to controlBar
417
+ videojs.obj.merge(player.controlBar.options_['children'], {
418
+ 'resolutionsButton': {}
419
+ });
420
+
421
+ // let's get the party started!
422
+ // we have to grab the parsed sources and select the source with our
423
+ // resolution-aware source selector
424
+ var source = player.resolutions_.selectSource(player.options_['sources']);
425
+
426
+ // when the player is ready, add the resolution button to the control bar
427
+ player.ready(function(){
428
+ player.changeResolution(source);
429
+ var button = new ResolutionsButton(player);
430
+ player.controlBar.addChild(button);
431
+ });
432
+ });