videojs 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ });