This demo shows the player in a responsive template.
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
Responsive Demo
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum pretium varius gravida. Aliquam faucibus ex eget nunc semper, sit amet aliquet diam egestas. Nunc ultricies egestas augue. Aenean cursus, magna vel porttitor interdum, nisi nunc ultricies orci, quis rhoncus diam nisi sed massa. Sed tempor eros eget aliquet porttitor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum eget maximus sapien. Nam sed ligula lectus. Donec a nunc elit.
28 |
29 |
30 |
31 |
32 |
← Resize the window to see how the player adjusts. →
This demo shows the player in a test template for new features.
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
Testing Demo
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum pretium varius gravida. Aliquam faucibus ex eget nunc semper, sit amet aliquet diam egestas. Nunc ultricies egestas augue. Aenean cursus, magna vel porttitor interdum, nisi nunc ultricies orci, quis rhoncus diam nisi sed massa. Sed tempor eros eget aliquet porttitor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum eget maximus sapien. Nam sed ligula lectus. Donec a nunc elit.
34 |
This demo shows the multiple players in a responsive template.
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
Multi-Responsive Demo
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum pretium varius gravida. Aliquam faucibus ex eget nunc semper, sit amet aliquet diam egestas. Nunc ultricies egestas augue. Aenean cursus, magna vel porttitor interdum, nisi nunc ultricies orci, quis rhoncus diam nisi sed massa. Sed tempor eros eget aliquet porttitor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum eget maximus sapien. Nam sed ligula lectus. Donec a nunc elit.
28 |
29 |
30 |
31 |
32 |
← Resize the window to see how the player adjusts. →
This demo shows the player in a test template for new features.
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
Testing Demo
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum pretium varius gravida. Aliquam faucibus ex eget nunc semper, sit amet aliquet diam egestas. Nunc ultricies egestas augue. Aenean cursus, magna vel porttitor interdum, nisi nunc ultricies orci, quis rhoncus diam nisi sed massa. Sed tempor eros eget aliquet porttitor. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum eget maximus sapien. Nam sed ligula lectus. Donec a nunc elit.
34 |
35 |
36 |
37 |
38 |
39 |
40 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/src/ytv.css:
--------------------------------------------------------------------------------
1 | /* YouTube TV */
2 |
3 | /* Base Canvas */
4 | .ytv-canvas{
5 | display: block;
6 | background: #282828;
7 | overflow: hidden;
8 | font-family: arial, sans-serif;
9 | }
10 | .ytv-canvas ::-webkit-scrollbar{
11 | border-left: 1px solid #000;
12 | width: 10px;
13 | }
14 | .ytv-canvas ::-webkit-scrollbar-thumb{
15 | background: rgba(255,255,255,0.1);
16 | }
17 |
18 | /* Video */
19 | .ytv-video{
20 | position: absolute;
21 | top: 0;
22 | right: 300px;
23 | bottom: 0;
24 | left: 0;
25 | height: 100%;
26 | }
27 | .ytv-video iframe{
28 | width: 100%;
29 | height: 100%;
30 | border: none;
31 | outline: none;
32 | display: block;
33 | }
34 |
35 | /* List */
36 | .ytv-list{
37 | position: absolute;
38 | top: 0;
39 | right: 0;
40 | bottom: 0;
41 | height: 100%;
42 | width: 300px;
43 | }
44 | .ytv-list-inner{
45 | overflow: auto;
46 | position: absolute;
47 | top: 52px;
48 | right: 0;
49 | bottom: 0;
50 | left: 0;
51 | -webkit-overflow-scrolling: touch;
52 | }
53 | .ytv-list ul{
54 | margin: 0;
55 | padding: 0;
56 | list-style-type: none;
57 | }
58 | .ytv-list .ytv-active a{
59 | border-left: 2px solid #fff;
60 | background: rgba(255,255,255,0.05);;
61 | }
62 | .ytv-list a{
63 | display: block;
64 | text-decoration: none;
65 | font-size: 11px;
66 | color: #FEFEFE;
67 | padding: 10px;
68 | padding-left: 8px;
69 | border-top: 1px solid rgba(255,255,255,0.1);
70 | border-bottom: 1px solid rgba(0,0,0,0.5);
71 | border-left: 2px solid transparent;
72 | }
73 | .ytv-list a b{
74 | max-height: 45px;
75 | overflow: hidden;
76 | display: block;
77 | text-overflow: ellipsis;
78 | }
79 | .ytv-list li:first-child a{ border-top: none; }
80 | .ytv-list li:last-child a{ border-bottom: none; }
81 | .ytv-list a:hover,
82 | .ytv-list-header .ytv-playlists a:hover{ background: rgba(255,255,255,0.05); }
83 | .ytv-list a:active,
84 | .ytv-list-header .ytv-playlists a:active{ background: rgba(0,0,0,0.05); }
85 |
86 | .ytv-list .ytv-content{ padding-left: 125px; }
87 | .ytv-list .ytv-thumb-stroke{
88 | position: absolute;
89 | top: 1px;
90 | left: 1px;
91 | bottom: 1px;
92 | right: 1px;
93 | z-index: 2;
94 | outline: 1px solid rgba(255,255,255,0.1);
95 | }
96 | .ytv-list .ytv-thumb{
97 | float: left;
98 | position: relative;
99 | outline: 1px solid rgba(0,0,0,0.5);
100 | }
101 | .ytv-list .ytv-thumb img{
102 | width: 120px;
103 | display: block;
104 | }
105 | .ytv-list .ytv-thumb span{
106 | position: absolute;
107 | bottom: 5px;
108 | right: 5px;
109 | color: #eee;
110 | background: rgba(0,0,0,0.7);
111 | font-size: 11px;
112 | font-weight: bold;
113 | padding: 0px 4px;
114 |
115 | -webkit-border-radius: 3px;
116 | -moz-border-radius: 3px;
117 | border-radius: 3px;
118 | }
119 | .ytv-views{
120 | display: block;
121 | margin-top: 5px;
122 | font-size: 10px;
123 | font-weight: normal;
124 | opacity: 0.3;
125 | }
126 |
127 | .ytv-list-header{
128 | height: 52px;
129 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
130 | -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
131 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
132 | }
133 | .ytv-list-header a{
134 | background: rgba(255,255,255,0.05);
135 | position: relative;
136 | z-index: 10;
137 | }
138 | .ytv-list-header img,
139 | .ytv-list .ytv-playlists .ytv-thumb img{
140 | width: 30px;
141 | vertical-align: middle;
142 | }
143 | .ytv-list-header span{
144 | padding-left: 10px;
145 | font-size: 12px;
146 | font-weight: bold;
147 | }
148 |
149 | /* Playlists */
150 | .ytv-playlists{
151 | z-index: 9;
152 | position: absolute;
153 | background: #282828;
154 | top:52px;
155 | left: 0;
156 | right: 0;
157 | bottom: 0;
158 | overflow: auto;
159 | display: none;
160 | }
161 | .ytv-playlists img,
162 | .ytv-list-header img{
163 | float: left;
164 | }
165 | .ytv-playlists a span,
166 | .ytv-list-header a span{
167 | white-space: nowrap;
168 | padding-left: 10px;
169 | display: block;
170 | overflow: hidden;
171 | text-overflow: ellipsis;
172 | }
173 | .ytv-list-header > a span{
174 | line-height: 30px;
175 | }
176 | .ytv-list-header .ytv-playlists a{
177 | background: none;
178 | }
179 | .ytv-playlist-open .ytv-playlists{
180 | display: block;
181 | }
182 |
183 | /* Modifiers */
184 | .ytv-relative{
185 | position: relative;
186 | width: 100%;
187 | height: 100%;
188 | }
189 | .ytv-full{
190 | position: fixed;
191 | top: 0;
192 | left: 0;
193 | width: 100% !important;
194 | height: 100% !important;
195 | margin: 0 !important;
196 | }
197 | .ytv-arrow {
198 | height: 10px;
199 | width: 0;
200 | position: relative;
201 | top: 10px;
202 | right: 5px;
203 | border: 10px solid transparent;
204 | float: right;
205 | border-top-color: rgba(0,0,0,0.4);
206 | display: none;
207 | }
208 | .ytv-has-playlists .ytv-arrow{
209 | display: inline-block;
210 | }
211 | .ytv-playlist-open .ytv-arrow{
212 | border-color: transparent;
213 | border-bottom-color: rgba(0,0,0,0.4);
214 | top: -10px;
215 | }
216 |
217 | .ytv-list-header a:after,
218 | .ytv-clear:after {
219 | content: ".";
220 | display: block;
221 | clear: both;
222 | visibility: hidden;
223 | line-height: 0;
224 | height: 0;
225 | }
--------------------------------------------------------------------------------
/demos/assets/ytv.css:
--------------------------------------------------------------------------------
1 | /* YouTube TV */
2 |
3 | /* Base Canvas */
4 | .ytv-canvas{
5 | display: block;
6 | background: #282828;
7 | overflow: hidden;
8 | font-family: arial, sans-serif;
9 | }
10 | .ytv-canvas ::-webkit-scrollbar{
11 | border-left: 1px solid #000;
12 | width: 10px;
13 | }
14 | .ytv-canvas ::-webkit-scrollbar-thumb{
15 | background: rgba(255,255,255,0.1);
16 | }
17 |
18 | /* Video */
19 | .ytv-video{
20 | position: absolute;
21 | top: 0;
22 | right: 300px;
23 | bottom: 0;
24 | left: 0;
25 | height: 100%;
26 | }
27 | .ytv-video iframe{
28 | width: 100%;
29 | height: 100%;
30 | border: none;
31 | outline: none;
32 | display: block;
33 | }
34 |
35 | /* List */
36 | .ytv-list{
37 | position: absolute;
38 | top: 0;
39 | right: 0;
40 | bottom: 0;
41 | height: 100%;
42 | width: 300px;
43 | }
44 | .ytv-list-inner{
45 | overflow: auto;
46 | position: absolute;
47 | top: 52px;
48 | right: 0;
49 | bottom: 0;
50 | left: 0;
51 | -webkit-overflow-scrolling: touch;
52 | }
53 | .ytv-list ul{
54 | margin: 0;
55 | padding: 0;
56 | list-style-type: none;
57 | }
58 | .ytv-list .ytv-active a{
59 | border-left: 2px solid #fff;
60 | background: rgba(255,255,255,0.05);;
61 | }
62 | .ytv-list a{
63 | display: block;
64 | text-decoration: none;
65 | font-size: 11px;
66 | color: #FEFEFE;
67 | padding: 10px;
68 | padding-left: 8px;
69 | border-top: 1px solid rgba(255,255,255,0.1);
70 | border-bottom: 1px solid rgba(0,0,0,0.5);
71 | border-left: 2px solid transparent;
72 | }
73 | .ytv-list a b{
74 | max-height: 45px;
75 | overflow: hidden;
76 | display: block;
77 | text-overflow: ellipsis;
78 | }
79 | .ytv-list li:first-child a{ border-top: none; }
80 | .ytv-list li:last-child a{ border-bottom: none; }
81 | .ytv-list a:hover,
82 | .ytv-list-header .ytv-playlists a:hover{ background: rgba(255,255,255,0.05); }
83 | .ytv-list a:active,
84 | .ytv-list-header .ytv-playlists a:active{ background: rgba(0,0,0,0.05); }
85 |
86 | .ytv-list .ytv-content{ padding-left: 125px; }
87 | .ytv-list .ytv-thumb-stroke{
88 | position: absolute;
89 | top: 1px;
90 | left: 1px;
91 | bottom: 1px;
92 | right: 1px;
93 | z-index: 2;
94 | outline: 1px solid rgba(255,255,255,0.1);
95 | }
96 | .ytv-list .ytv-thumb{
97 | float: left;
98 | position: relative;
99 | outline: 1px solid rgba(0,0,0,0.5);
100 | }
101 | .ytv-list .ytv-thumb img{
102 | width: 120px;
103 | display: block;
104 | }
105 | .ytv-list .ytv-thumb span{
106 | position: absolute;
107 | bottom: 5px;
108 | right: 5px;
109 | color: #eee;
110 | background: rgba(0,0,0,0.7);
111 | font-size: 11px;
112 | font-weight: bold;
113 | padding: 0px 4px;
114 |
115 | -webkit-border-radius: 3px;
116 | -moz-border-radius: 3px;
117 | border-radius: 3px;
118 | }
119 | .ytv-views{
120 | display: block;
121 | margin-top: 5px;
122 | font-size: 10px;
123 | font-weight: normal;
124 | opacity: 0.3;
125 | }
126 |
127 | .ytv-list-header{
128 | height: 52px;
129 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
130 | -moz-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
131 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
132 | }
133 | .ytv-list-header a{
134 | background: rgba(255,255,255,0.05);
135 | position: relative;
136 | z-index: 10;
137 | }
138 | .ytv-list-header img,
139 | .ytv-list .ytv-playlists .ytv-thumb img{
140 | width: 30px;
141 | vertical-align: middle;
142 | }
143 | .ytv-list-header span{
144 | padding-left: 10px;
145 | font-size: 12px;
146 | font-weight: bold;
147 | }
148 |
149 | /* Playlists */
150 | .ytv-playlists{
151 | z-index: 9;
152 | position: absolute;
153 | background: #282828;
154 | top:52px;
155 | left: 0;
156 | right: 0;
157 | bottom: 0;
158 | overflow: auto;
159 | display: none;
160 | }
161 | .ytv-playlists img,
162 | .ytv-list-header img{
163 | float: left;
164 | }
165 | .ytv-playlists a span,
166 | .ytv-list-header a span{
167 | white-space: nowrap;
168 | padding-left: 10px;
169 | display: block;
170 | overflow: hidden;
171 | text-overflow: ellipsis;
172 | }
173 | .ytv-list-header > a span{
174 | line-height: 30px;
175 | }
176 | .ytv-list-header .ytv-playlists a{
177 | background: none;
178 | }
179 | .ytv-playlist-open .ytv-playlists{
180 | display: block;
181 | }
182 |
183 | /* Modifiers */
184 | .ytv-relative{
185 | position: relative;
186 | width: 100%;
187 | height: 100%;
188 | }
189 | .ytv-full{
190 | position: fixed;
191 | top: 0;
192 | left: 0;
193 | width: 100% !important;
194 | height: 100% !important;
195 | margin: 0 !important;
196 | }
197 | .ytv-arrow {
198 | height: 10px;
199 | width: 0;
200 | position: relative;
201 | top: 10px;
202 | right: 5px;
203 | border: 10px solid transparent;
204 | float: right;
205 | border-top-color: rgba(0,0,0,0.4);
206 | display: none;
207 | }
208 | .ytv-has-playlists .ytv-arrow{
209 | display: inline-block;
210 | }
211 | .ytv-playlist-open .ytv-arrow{
212 | border-color: transparent;
213 | border-bottom-color: rgba(0,0,0,0.4);
214 | top: -10px;
215 | }
216 |
217 | .ytv-list-header a:after,
218 | .ytv-clear:after {
219 | content: ".";
220 | display: block;
221 | clear: both;
222 | visibility: hidden;
223 | line-height: 0;
224 | height: 0;
225 | }
--------------------------------------------------------------------------------
/src/ie8/es5-sham.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * https://github.com/es-shims/es5-shim
3 | * @license es5-shim Copyright 2009-2015 by contributors, MIT License
4 | * see https://github.com/es-shims/es5-shim/blob/v4.1.7/LICENSE
5 | */
6 | (function(e,t){"use strict";if(typeof define==="function"&&define.amd){define(t)}else if(typeof exports==="object"){module.exports=t()}else{e.returnExports=t()}})(this,function(){var e=Function.prototype.call;var t=Object.prototype;var r=e.bind(t.hasOwnProperty);var n;var o;var c;var i;var f=r(t,"__defineGetter__");if(f){n=e.bind(t.__defineGetter__);o=e.bind(t.__defineSetter__);c=e.bind(t.__lookupGetter__);i=e.bind(t.__lookupSetter__)}if(!Object.getPrototypeOf){Object.getPrototypeOf=function x(e){var r=e.__proto__;if(r||r===null){return r}else if(e.constructor){return e.constructor.prototype}else{return t}}}var l=function z(e){try{e.sentinel=0;return Object.getOwnPropertyDescriptor(e,"sentinel").value===0}catch(t){return false}};if(Object.defineProperty){var a=l({});var u=typeof document==="undefined"||l(document.createElement("div"));if(!u||!a){var p=Object.getOwnPropertyDescriptor}}if(!Object.getOwnPropertyDescriptor||p){var b="Object.getOwnPropertyDescriptor called on a non-object: ";Object.getOwnPropertyDescriptor=function S(e,n){if(typeof e!=="object"&&typeof e!=="function"||e===null){throw new TypeError(b+e)}if(p){try{return p.call(Object,e,n)}catch(o){}}var l;if(!r(e,n)){return l}l={enumerable:true,configurable:true};if(f){var a=e.__proto__;var u=e!==t;if(u){e.__proto__=t}var s=c(e,n);var O=i(e,n);if(u){e.__proto__=a}if(s||O){if(s){l.get=s}if(O){l.set=O}return l}}l.value=e[n];l.writable=true;return l}}if(!Object.getOwnPropertyNames){Object.getOwnPropertyNames=function D(e){return Object.keys(e)}}if(!Object.create){var s;var O=!({__proto__:null}instanceof Object);var j=function k(){if(!document.domain){return false}try{return!!new ActiveXObject("htmlfile")}catch(e){return false}};var d=function F(){var e;var t;t=new ActiveXObject("htmlfile");t.write("");t.close();e=t.parentWindow.Object.prototype;t=null;return e};var y=function G(){var e=document.createElement("iframe");var t=document.body||document.documentElement;var r;e.style.display="none";t.appendChild(e);e.src="javascript:";r=e.contentWindow.Object.prototype;t.removeChild(e);e=null;return r};if(O||typeof document==="undefined"){s=function(){return{__proto__:null}}}else{s=function(){var e=j()?d():y();delete e.constructor;delete e.hasOwnProperty;delete e.propertyIsEnumerable;delete e.isPrototypeOf;delete e.toLocaleString;delete e.toString;delete e.valueOf;e.__proto__=null;var t=function r(){};t.prototype=e;s=function(){return new t};return new t}}Object.create=function A(e,t){var r;var n=function o(){};if(e===null){r=s()}else{if(typeof e!=="object"&&typeof e!=="function"){throw new TypeError("Object prototype may only be an Object or null")}n.prototype=e;r=new n;r.__proto__=e}if(t!==void 0){Object.defineProperties(r,t)}return r}}var _=function C(e){try{Object.defineProperty(e,"sentinel",{});return"sentinel"in e}catch(t){return false}};if(Object.defineProperty){var v=_({});var w=typeof document==="undefined"||_(document.createElement("div"));if(!v||!w){var h=Object.defineProperty,m=Object.defineProperties}}if(!Object.defineProperty||h){var P="Property description must be an object: ";var E="Object.defineProperty called on non-object: ";var g="getters & setters can not be defined on this javascript engine";Object.defineProperty=function N(e,r,l){if(typeof e!=="object"&&typeof e!=="function"||e===null){throw new TypeError(E+e)}if(typeof l!=="object"&&typeof l!=="function"||l===null){throw new TypeError(P+l)}if(h){try{return h.call(Object,e,r,l)}catch(a){}}if("value"in l){if(f&&(c(e,r)||i(e,r))){var u=e.__proto__;e.__proto__=t;delete e[r];e[r]=l.value;e.__proto__=u}else{e[r]=l.value}}else{if(!f){throw new TypeError(g)}if("get"in l){n(e,r,l.get)}if("set"in l){o(e,r,l.set)}}return e}}if(!Object.defineProperties||m){Object.defineProperties=function W(e,t){if(m){try{return m.call(Object,e,t)}catch(r){}}Object.keys(t).forEach(function(r){if(r!=="__proto__"){Object.defineProperty(e,r,t[r])}});return e}}if(!Object.seal){Object.seal=function X(e){if(Object(e)!==e){throw new TypeError("Object.seal can only be called on Objects.")}return e}}if(!Object.freeze){Object.freeze=function I(e){if(Object(e)!==e){throw new TypeError("Object.freeze can only be called on Objects.")}return e}}try{Object.freeze(function(){})}catch(T){Object.freeze=function(e){return function t(r){if(typeof r==="function"){return r}else{return e(r)}}}(Object.freeze)}if(!Object.preventExtensions){Object.preventExtensions=function L(e){if(Object(e)!==e){throw new TypeError("Object.preventExtensions can only be called on Objects.")}return e}}if(!Object.isSealed){Object.isSealed=function q(e){if(Object(e)!==e){throw new TypeError("Object.isSealed can only be called on Objects.")}return false}}if(!Object.isFrozen){Object.isFrozen=function B(e){if(Object(e)!==e){throw new TypeError("Object.isFrozen can only be called on Objects.")}return false}}if(!Object.isExtensible){Object.isExtensible=function H(e){if(Object(e)!==e){throw new TypeError("Object.isExtensible can only be called on Objects.")}var t="";while(r(e,t)){t+="?"}e[t]=true;var n=r(e,t);delete e[t];return n}}});
7 | //# sourceMappingURL=es5-sham.map
8 |
--------------------------------------------------------------------------------
/demos/assets/ie8/es5-sham.min.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * https://github.com/es-shims/es5-shim
3 | * @license es5-shim Copyright 2009-2015 by contributors, MIT License
4 | * see https://github.com/es-shims/es5-shim/blob/v4.1.7/LICENSE
5 | */
6 | (function(e,t){"use strict";if(typeof define==="function"&&define.amd){define(t)}else if(typeof exports==="object"){module.exports=t()}else{e.returnExports=t()}})(this,function(){var e=Function.prototype.call;var t=Object.prototype;var r=e.bind(t.hasOwnProperty);var n;var o;var c;var i;var f=r(t,"__defineGetter__");if(f){n=e.bind(t.__defineGetter__);o=e.bind(t.__defineSetter__);c=e.bind(t.__lookupGetter__);i=e.bind(t.__lookupSetter__)}if(!Object.getPrototypeOf){Object.getPrototypeOf=function x(e){var r=e.__proto__;if(r||r===null){return r}else if(e.constructor){return e.constructor.prototype}else{return t}}}var l=function z(e){try{e.sentinel=0;return Object.getOwnPropertyDescriptor(e,"sentinel").value===0}catch(t){return false}};if(Object.defineProperty){var a=l({});var u=typeof document==="undefined"||l(document.createElement("div"));if(!u||!a){var p=Object.getOwnPropertyDescriptor}}if(!Object.getOwnPropertyDescriptor||p){var b="Object.getOwnPropertyDescriptor called on a non-object: ";Object.getOwnPropertyDescriptor=function S(e,n){if(typeof e!=="object"&&typeof e!=="function"||e===null){throw new TypeError(b+e)}if(p){try{return p.call(Object,e,n)}catch(o){}}var l;if(!r(e,n)){return l}l={enumerable:true,configurable:true};if(f){var a=e.__proto__;var u=e!==t;if(u){e.__proto__=t}var s=c(e,n);var O=i(e,n);if(u){e.__proto__=a}if(s||O){if(s){l.get=s}if(O){l.set=O}return l}}l.value=e[n];l.writable=true;return l}}if(!Object.getOwnPropertyNames){Object.getOwnPropertyNames=function D(e){return Object.keys(e)}}if(!Object.create){var s;var O=!({__proto__:null}instanceof Object);var j=function k(){if(!document.domain){return false}try{return!!new ActiveXObject("htmlfile")}catch(e){return false}};var d=function F(){var e;var t;t=new ActiveXObject("htmlfile");t.write("");t.close();e=t.parentWindow.Object.prototype;t=null;return e};var y=function G(){var e=document.createElement("iframe");var t=document.body||document.documentElement;var r;e.style.display="none";t.appendChild(e);e.src="javascript:";r=e.contentWindow.Object.prototype;t.removeChild(e);e=null;return r};if(O||typeof document==="undefined"){s=function(){return{__proto__:null}}}else{s=function(){var e=j()?d():y();delete e.constructor;delete e.hasOwnProperty;delete e.propertyIsEnumerable;delete e.isPrototypeOf;delete e.toLocaleString;delete e.toString;delete e.valueOf;e.__proto__=null;var t=function r(){};t.prototype=e;s=function(){return new t};return new t}}Object.create=function A(e,t){var r;var n=function o(){};if(e===null){r=s()}else{if(typeof e!=="object"&&typeof e!=="function"){throw new TypeError("Object prototype may only be an Object or null")}n.prototype=e;r=new n;r.__proto__=e}if(t!==void 0){Object.defineProperties(r,t)}return r}}var _=function C(e){try{Object.defineProperty(e,"sentinel",{});return"sentinel"in e}catch(t){return false}};if(Object.defineProperty){var v=_({});var w=typeof document==="undefined"||_(document.createElement("div"));if(!v||!w){var h=Object.defineProperty,m=Object.defineProperties}}if(!Object.defineProperty||h){var P="Property description must be an object: ";var E="Object.defineProperty called on non-object: ";var g="getters & setters can not be defined on this javascript engine";Object.defineProperty=function N(e,r,l){if(typeof e!=="object"&&typeof e!=="function"||e===null){throw new TypeError(E+e)}if(typeof l!=="object"&&typeof l!=="function"||l===null){throw new TypeError(P+l)}if(h){try{return h.call(Object,e,r,l)}catch(a){}}if("value"in l){if(f&&(c(e,r)||i(e,r))){var u=e.__proto__;e.__proto__=t;delete e[r];e[r]=l.value;e.__proto__=u}else{e[r]=l.value}}else{if(!f){throw new TypeError(g)}if("get"in l){n(e,r,l.get)}if("set"in l){o(e,r,l.set)}}return e}}if(!Object.defineProperties||m){Object.defineProperties=function W(e,t){if(m){try{return m.call(Object,e,t)}catch(r){}}Object.keys(t).forEach(function(r){if(r!=="__proto__"){Object.defineProperty(e,r,t[r])}});return e}}if(!Object.seal){Object.seal=function X(e){if(Object(e)!==e){throw new TypeError("Object.seal can only be called on Objects.")}return e}}if(!Object.freeze){Object.freeze=function I(e){if(Object(e)!==e){throw new TypeError("Object.freeze can only be called on Objects.")}return e}}try{Object.freeze(function(){})}catch(T){Object.freeze=function(e){return function t(r){if(typeof r==="function"){return r}else{return e(r)}}}(Object.freeze)}if(!Object.preventExtensions){Object.preventExtensions=function L(e){if(Object(e)!==e){throw new TypeError("Object.preventExtensions can only be called on Objects.")}return e}}if(!Object.isSealed){Object.isSealed=function q(e){if(Object(e)!==e){throw new TypeError("Object.isSealed can only be called on Objects.")}return false}}if(!Object.isFrozen){Object.isFrozen=function B(e){if(Object(e)!==e){throw new TypeError("Object.isFrozen can only be called on Objects.")}return false}}if(!Object.isExtensible){Object.isExtensible=function H(e){if(Object(e)!==e){throw new TypeError("Object.isExtensible can only be called on Objects.")}var t="";while(r(e,t)){t+="?"}e[t]=true;var n=r(e,t);delete e[t];return n}}});
7 | //# sourceMappingURL=es5-sham.map
8 |
--------------------------------------------------------------------------------
/APIv2-3_Reference.md:
--------------------------------------------------------------------------------
1 | #APIv2 to APIv3 Reference Notes
2 |
3 | Notes to reference for the conversion for a better understanding on what has changed for myself and others.
4 |
5 | ## Youtube-TV Elements Chart
6 |
7 | Currently used elements in `ytv.js` and their new APIv3 counterparts.
8 |
9 | #### User (channel) Playlists
10 |
11 | playlists = | res.feed.entry
12 | ----------- | --------------
13 | | **res.feed.items**
14 |
15 | `playlists[i]`
16 |
17 | Element | Old Value | New Value
18 | ------- | --------- | ---------
19 | title | .title.$t | .snippet.title
20 | plid | .yt$playlistId.$t | .id
21 | thumb | .media$group.media$thumbnail[1].url | .snippet.thumbnails.medium.url
22 |
23 | #### User (channel) Info
24 |
25 | user = | userInfo.entry
26 | ------ | --------------
27 | | **userInfo.items[0]**
28 |
29 | Element | Old Value | New Value
30 | ------- | --------- | ---------
31 | title | .title.$t | .snippet.title
32 | url | .yt$username.$t | .id
33 | thumb | .media$thumbnail.url | .snippet.thumbnails.default.url
34 | summary | .summary.$t | .snippet.description
35 | subscribers | .yt$statistics.subscriberCount | .statistics.subscriberCount
36 | views | .yt$statistics.totalUploadViews | .statistics.viewCount
37 | **`NEW`** | - | -
38 | uploads | n/a | .contentDetails.relatedPlaylists.uploads
39 |
40 | To support newer accounts by using channel ID instead of user ID.
41 | **Old:** `url: local+'//youtube.com/user/'+userInfo.entry.yt$username.$t`
42 | **New:** `url: 'https://youtube.com/channel/'+userInfo.id`
43 |
44 | #### `NEW` Playlist Videos
45 |
46 | playlistVideos = | n/a
47 | ---------------- | ---
48 | | **res.feed.items**
49 |
50 | `plistlistVideos[i]`
51 |
52 | Element | Old Value | New Value
53 | ------- | --------- | ---------
54 | slug | n/a | .contentDetails.videoId
55 |
56 | #### Video Info
57 |
58 | videos = | data.feed.entry
59 | -------- | ---------------
60 | | **data.feed.items**
61 |
62 | `videos[i]`
63 |
64 | Element | Old Value | New Value
65 | ------- | --------- | ---------
66 | title | .title.$t | .snippet.title
67 | *slug | .media$group.yt$videoid.$t | .id
68 | link | .link[0].href | n/a *use slug
69 | published | .published.$t | .snippet.publishedAt
70 | rating | .yt$rating | n/a *see statistics
71 | stats | .yt$statistics | .statistics
72 | duration | ( .media$group.yt$duration.seconds) | .contentDetails.duration
73 | thumb | .media$group.media$thumbnail[1].url | .snippet.thumbnails.medium.url
74 | **`NEW`** | - | -
75 | embed | n/a | .status.embeddable
76 |
77 | ## Updated URLs
78 | #### base
79 |
80 | base = | `local+'//gdata.youtube.com/'`
81 | ------ | ----------------------------
82 | | **`'https://www.googleapis.com/youtube/v3/'`**
83 |
84 | * *https required for APIv3*
85 |
86 | #### userInfo
87 | ```
88 | Before:
89 | utils.endpoints.base+'feeds/api/users/'+settings.user+'?v=2&alt=json';
90 | After:
91 | utils.endpoints.base+'channels?'+settings.cid+'&key='+apiKey+'&part=snippet,contentDetails,statistics';
92 | ```
93 | **Required in Build**
94 | ```javascript
95 | if (settings.channelId){
96 | settings.cid = 'id='+settings.channelId;
97 | } else if(settings.user){
98 | settings.cid = 'forUsername='+settings.user;
99 | }
100 | ```
101 |
102 | #### userVids
103 | ```
104 | Before:
105 | utils.endpoints.base+'feeds/api/users/'+settings.user+'/uploads/?v=2&alt=json&format=5&max-results=50';
106 | After: n/a pulled playlistId pulled from userInfo
107 | ```
108 | **Replaced with:**
109 | ```javascript
110 | userUploads: function(userInfo){
111 | if (userInfo && userInfo.items){
112 | settings.playlist = userInfo.items[0].contentDetails.relatedPlaylists.uploads;
113 | utils.ajax.get( utils.endpoints.playlistVids(), prepare.compileVideos );
114 | }
115 | }
116 | ```
117 |
118 | #### userPlaylists
119 | ```
120 | Before:
121 | utils.endpoints.base+'feeds/api/users/'+settings.user+'/playlists/?v=2&alt=json&format=5&max-results=50';
122 | After:
123 | utils.endpoints.base+'playlists?channelId='+settings.channelId+'&key='+apiKey+'&maxResults=50&part=snippet';
124 | ```
125 |
126 | #### playlistVids
127 | ```
128 | Before:
129 | utils.endpoints.base+'feeds/api/playlists/'+(settings.playlist)+'?v=2&alt=json&format=5&max-results=50';
130 | After:
131 | utils.endpoints.base+'playlistItems?playlistId='+settings.playlist+'&key='+apiKey+'&maxResults=50&part=contentDetails';
132 | ```
133 |
134 | #### `NEW` playlistInfo
135 | `utils.endpoints.base+'playlists?id='+settings.playlist+'&key='+apiKey+'&maxResults=50&part=snippet';`
136 | ```javascript
137 | selectedPlaylist: function(playlistInfo){
138 | if (playlistInfo && playlistInfo.items) {
139 | settings.currentPlaylist = playlistInfo.items[0].snippet.title;
140 | utils.ajax.get( utils.endpoints.playlistVids(), prepare.compileVideos );
141 | }
142 | }
143 | ```
144 |
145 | #### `NEW` videoInfo
146 | `utils.endpoints.base+'videos?id='+settings.videoString+'&key='+apiKey+'&maxResults=50&part=snippet,contentDetails,status,statistics';`
147 | ```javascript
148 | compileVideos: function(res){
149 | if (res && res.items){
150 | var playlists = res.items,
151 | i;
152 | settings.videoString = '';
153 | for(i=0; i 9 ? '' + amount : '0' + amount); break;
174 | case 'M': m = (amount > 9 ? '' + amount : '0' + amount); break;
175 | case 'S': s = (amount > 9 ? '' + amount : '0' + amount); break;
176 | default: // ??? profit
177 | }
178 | });
179 | if (h){ time += h+':';}
180 | if (m){ time += m+':';} else { time += '00:';}
181 | if (s){ time += s;} else { time += '00';}
182 |
183 | return time;
184 | }
185 | ```
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # YoutubeTV
2 | **NOW with API Version 3 Support!!**
3 | A small, slick, library independent YouTube User/Playlist player
4 |
5 |
6 |
7 | ## Features
8 | * Library Independent
9 | * Customizable via CSS
10 | * Autoplay
11 | * Remove YouTube Chrome
12 | * Supports Playlists and Users
13 | * jQuery Support
14 | * Module Support
15 | * Responsive Support
16 | * Alternative color scheme
17 |
18 | ## Demos
19 | * [Default Player Options](http://giorgio003.github.io/Youtube-TV/demos/default.html)
20 | * [Chromeless Player](http://giorgio003.github.io/Youtube-TV/demos/chromeless.html)
21 | * [Playlist Support](http://giorgio003.github.io/Youtube-TV/demos/playlists.html)
22 | * [Full Screen Player](http://giorgio003.github.io/Youtube-TV/demos/fullscreen.html) (Good for a .tv website?)
23 | * [jQuery Support](http://giorgio003.github.io/Youtube-TV/demos/jquery.html)
24 | * [Responsive Support](http://giorgio003.github.io/Youtube-TV/demos/responsive.html)
25 | * [Multiple Players](http://giorgio003.github.io/Youtube-TV/demos/multiplayer.html)
26 |
27 | ## Obtaining Youtube API Key
28 |
29 | As part of the update to [Youtube's API version 3](https://developers.google.com/youtube/v3/), it is required to obtain an API Key from [Google's Developer Console](https://console.developers.google.com/).
30 |
31 | To obtain your API Key you can follow this guide using steps 1 to 3.
32 | [https://developers.google.com/youtube/v3/getting-started](https://developers.google.com/youtube/v3/getting-started)
33 |
34 | Then:
35 | 4. under APIs & auth > Credentials > Create new Key > (Select) Browser Key
36 | 5. (Recommended) Set any referrers to your domain to prevent unauthorized use of your key.
37 | 6. (Optional) Additionally disabling any other unused APIs that are enabled.
38 |
39 | ## Installation
40 |
41 | After obtaining your API Key, fill it in `ytv.js` near the top via this line:
42 | `var apiKey = 'YOUR_API_KEY_HERE';`
43 |
44 | Include both the `ytv.css` and `ytv.js` in your HTML file and you are good to go.
45 |
46 | ```html
47 |
48 |
49 | ```
50 |
51 | ## Usage
52 |
53 | After your page has loaded, you may call the script like so:
54 | ```html
55 |
56 | ```
57 | ```javascript
58 | document.addEventListener("DOMContentLoaded", function(event) {
59 | var controller = new YTV('YourPlayerID', {
60 | user: 'YoutubeUsername'
61 | });
62 | });
63 | ```
64 | **Technical Note:** Above `DOMContentLoaded` is preferred for speed on modern browsers (additionally works down to IE9). However the demos are mostly using `window.onload` which is a slower option but compatible with older browsers (IE8 or older). Good examples of this difference can be found [here (microsoft.com)](http://ie.microsoft.com/Testdrive/HTML5/DOMContentLoaded/Default.html) and [here (jspref.com)](http://jsperf.com/onload-vs-domcontentloaded/3)
65 |
66 | **`Note:`** If you are using a newer YouTube channel you may have a **Channel ID** which may look similar to this: `UCXXXXXXXXXXXXXXXXXXXXXX`
67 | If so, use `channelId: 'UCXXXXXXXXXXXXXXXXXXXXXX'` to replace user!
68 |
69 | #### User vs Channel ID
70 | By visiting the intended channel's Youtube home page. The URL should look like one of the following.
71 | ##### User ID `user: ''`
72 |
73 |
74 | ##### Channel ID `channelId: ''`
75 |
76 |
77 | #### Additional Options
78 |
79 | Additional options you may wish to add to get started.
80 |
81 | In addition to `user` and `channelId` you can also use `playlist` ID's which can also replace `user` and `channelId` or work along side them.
82 | `playlist: 'PLAYLIST_ID_HERE'`
83 | To chain multiple playlists together, separate them by comma's. Example:
84 | `playlist: 'PLAYLIST_ID1,PLAYLIST_ID2,PLAYLIST_ID3'`
85 |
86 | Add this to enable the responsive Youtube-TV player allowing the player to adjust from desktop resolution all the way to mobile devices.
87 | `responsive: true`
88 |
89 | Accent colour will appear beside the active video in the list. This will accept any CSS value from `#FFF` to `orange`.
90 | `accent: '#008D54'`
91 |
92 | If you prefer the `light` theme over the dark, add these 2 options (or mix 'n match if desired).
93 | `playerTheme: 'light'`
94 | `listTheme: 'light'`
95 |
96 | **Don't forget comma's between each option!**
97 |
98 | `YTV` accepts two parameters. The first is a string of the element ID you want to use as the player, OR it may the element itself. The second parameter is an object of options defined below:
99 |
100 | ## Settings, Defaults and Details
101 | ```javascript
102 | settings = {
103 | element: null,
104 | user: null,
105 | channelId: null,
106 | playlist: '',
107 | fullscreen: false,
108 | accent: '#fff',
109 | controls: true,
110 | annotations: false,
111 | autoplay: false,
112 | chainVideos: true,
113 | browsePlaylists: false,
114 | playerTheme: 'dark',
115 | listTheme: 'dark',
116 | responsive: false,
117 | playId:'',
118 | sortList: false,
119 | reverseList: false,
120 | shuffleList: false,
121 | wmode: 'opaque',
122 | events: {
123 | videoReady: function(){},
124 | stateChange: function(){}
125 | }
126 | }
127 | ```
128 |
129 | * `element`: The element or element ID to apply the YouTube TV Player to
130 | * `user`: (String) The Username of the YouTube user you want to display videos from
131 | * `channelId`: (String) The Channel ID of the YouTube channel you want to display videos from (for newer accounts)
132 | * `playlist`: (String) The Playlist ID(s) you would like to load separated by comma's (Overrides `user`)
133 | * `browsePlaylists`: (Boolean) If `true` and the specified `user` has YouTube playlists, they will be accessible in the player by clicking the users Username
134 | * `fullscreen`: (Boolean) If `true`, the player will take up all the available space on the users browser screen
135 | * `accent`: (String) A CSS color string to apply to the accents of the player
136 | * `controls`: (Boolean) If `false`, the normal YouTube controls will be hidden.
137 | * `annotations`: (Boolean) If `false`, the annotations from the YouTube video will be hidden
138 | * `autoplay`: (Boolean) If `true`, the first video in the list will automatically play once the player has loaded
139 | * `chainVideos`: (Boolean) If `true`, the next video in que will automatically play after the current video has completed
140 | * `playerTheme`: (String) Sets the youtube player theme. Default is `dark` with an alterative `light` color scheme.
141 | * `listTheme`: (String) Sets the playlist theme. Default is `dark` with a `light` theme to match the alternative player theme.
142 | * `responsive`: (Boolean) If `true`, it enables a responsive design to support various resolutions including mobile devices. Default currently `false`.
143 | * `playId`: (String) On load this option will allow you to select the first video to play/display. Enter the id of the video you want to display. (ie. `.../watch?v=VIDEOID` to `playId: 'VIDEOID'`).
144 | * `sortList`: (Boolean) If `true`, this option will sort the video list by date uploaded.
145 | * `reverseList`: (Boolean) If `true`, this option will reverse order of the videos. (Can be combined with other sorting option to reverse after sorting).
146 | * `shuffleList`: (Boolean) If `true`, this option will shuffle the video list. (Useful for music playlists).
147 | * `wmode`: (String) Sets the Window Mode property for transparency, layering, and positioning in the browser. Values can be: `window` - movie plays in its own rectangular window on a web page. `opaque` - the movie hides everything on the page behind it. `transparent` - the background of the HTML page shows through all transparent portions of the movie, this may slow animation performance.
148 | * `events`: The respective events will fire when key actions in the player have been called
149 |
150 |
151 | ## Responsive Design
152 | Youtube-TV can now adapt to various changes in resolution based on it's parent canvas/container. Currently set to `max-width:992px` to match Bootstrap's responsive transitions, but can be modified to match any other responsive boilerplate.
153 |
154 | #### Playlist beside
155 | *(image resized on github don't be fooled >_<)*
156 |
157 | #### Playlist on bottom
158 | *Better for mobile devices*
159 |
160 |
161 | ## Public Methods
162 |
163 | ### `destroy`
164 | Destroys the YouTube TV Player and all associated elements/events
165 |
166 | ```javascript
167 | controller.destroy();
168 | ```
169 |
170 | ### `fullscreen.state()`
171 | Returns `true` if in Fullscreen Mode
172 |
173 | ```javascript
174 | controller.fullscreen.state();
175 | ```
176 |
177 | ### `fullscreen.enter()`
178 | Enters into Fullscreen Mode
179 |
180 | ```javascript
181 | controller.fullscreen.enter();
182 | ```
183 |
184 | ### `fullscreen.exit()`
185 | Exits Fullscreen Mode
186 |
187 | ```javascript
188 | controller.fullscreen.exit();
189 | ```
190 |
191 | ## jQuery Support
192 |
193 | YTV may be used as a jQuery plugin in the following fashion:
194 |
195 | ```javascript
196 | $('#frame').ytv({opts});
197 | ```
198 |
199 |
200 |
201 | ## Licensing
202 | **MIT Licensing**
203 |
Copyright (c) 2013 Jacob Kelley
204 |
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
205 |
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
206 |
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.