├── .gitignore
├── Gruntfile.js
├── LICENSE
├── README.md
├── changelog.md
├── demo
├── fixed.html
├── fluid.html
├── grid.html
└── index.html
├── lazyYT.css
├── lazyYT.jquery.json
├── lazyYT.js
└── package.json
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | .project
4 | /demo/tmp*
--------------------------------------------------------------------------------
/Gruntfile.js:
--------------------------------------------------------------------------------
1 | module.exports = function(grunt) {
2 |
3 | grunt.initConfig({
4 | pkg: grunt.file.readJSON('package.json'),
5 | uglify: {
6 | options: {
7 | banner: '/*!\n' +
8 | '* <%= pkg.name %>\n' +
9 | '* v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>\n' +
10 | '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author %>; Licensed <%= pkg.license %> %>\n' +
11 | '*/'
12 | },
13 | dist: {
14 | files: {
15 | '<%= pkg.name %>.min.js': '<%= pkg.name %>.js'
16 | }
17 | }
18 | },
19 | jshint: {
20 | files: ['Gruntfile.js', '<%= pkg.name %>.js'],
21 | options: {
22 | globals: {
23 | jQuery: true,
24 | console: true,
25 | document: true
26 | }
27 | }
28 | },
29 | cssmin: {
30 | minify: {
31 | expand: true,
32 | cwd: './',
33 | src: ['*.css', '!*.min.css'],
34 | dest: './',
35 | ext: '.min.css'
36 | }
37 | }
38 | });
39 |
40 | grunt.loadNpmTasks('grunt-contrib-uglify');
41 | grunt.loadNpmTasks('grunt-contrib-jshint');
42 | grunt.loadNpmTasks('grunt-contrib-cssmin');
43 |
44 | grunt.registerTask('default', ['jshint', 'uglify', 'cssmin']);
45 |
46 | };
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | (CC) Creative Commons
2 | Attribution-ShareAlike 4.0 International (CC BY-SA 4.0)
3 |
4 | http://creativecommons.org/licenses/by-sa/4.0/
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # lazyYT.js
2 |
3 | ## Description
4 |
5 | This is a jQuery plugin to lazy load Youtube videos. On the initial load, the `div` will be appended by a preview `img` of the video. On click of the image, the preview `img` will be replaced by the autoplaying `iframe` Youtube video.
6 |
7 | Since 2015-07-08 it uses [Youtube API v3](https://developers.google.com/youtube/v3/).
8 |
9 |
10 | ## Demo
11 |
12 | 1. [Demo of v1.3.0](http://works.daugilas.com/lazyYT/demo/index.html)
13 |
14 | ## Setup
15 |
16 | ```html
17 |
loading...
18 | ```
19 |
20 | 1. Get Your [Youtube API_KEY](https://developers.google.com/youtube/v3/getting-started#before-you-start). It should look something like this: `AIzaSyCawA87g_pgTbSNPhiWAemy-mFKszJGl4M`.
21 | 2. Include the lazyYT JS and CSS files.
22 | 3. Add a `div` where you want the video to be located. Add the id of the Youtube video to the data attribute `youtube-id`.
23 | 4. Either add the video width and height to `data-width` and `data-height`, or add an ascpent ratio like `16:9` to `data-ratio`, none are required.
24 | 5. Any [optional parameters you wanted passed to the iframe url](https://developers.google.com/youtube/player_parameters) should be added to `data-parameters`.
25 | 6. Get it started with `$('.lazyYT').lazyYT(YOUR_YOUTUBE_API_KEY);`
26 |
27 | Note: make sure to create your own API_KEY, the one used in demo will not work for your domain for long.
28 |
29 | ### Parameters / Settings
30 |
31 | Default parameters:
32 |
33 | ```javascript
34 | $('.js-lazyYT').lazyYT({
35 | youtube_parameters: 'rel=0', // youtube URL parameters: https://developers.google.com/youtube/player_parameters#Parameters
36 | loading_text: 'Loading...', // displayed instead of video title while its loading
37 | display_title: true, // display title in video's info bar
38 | default_ratio: '16:9',
39 | display_duration: false, // display video duration in bottom right
40 | callback: function() {
41 | console.log(this);
42 | },
43 |
44 | // Advanced settings
45 | video_loaded_class: 'lazyYT-video-loaded', // adds this class after video loads into container
46 | container_class: 'lazyYT-container' // default CSS depends on this class
47 | });
48 | ```
49 |
50 | ## License
51 |
52 | (CC) [Creative Commons](http://creativecommons.org/licenses/by-sa/4.0/)
53 |
--------------------------------------------------------------------------------
/changelog.md:
--------------------------------------------------------------------------------
1 | Change Log
2 | ==========
3 |
4 | Version 1.3.0 *(2016-03-06)*
5 | ----------------------------
6 |
7 | * Fix: Thumbnail validation. Fallback to smaller images
8 | * Fix: minor fixes for FireFox and trivial updates
9 |
10 | Version 1.2.1 *(2015-09-04)*
11 | ----------------------------
12 |
13 | * Fix: Play button CSS
14 |
15 | Version 1.2 *(2015-08-30)*
16 | ----------------------------
17 |
18 | * Fix: updated YouTube UI
19 | * New: `callback` parameter
20 | * New: changelog.md
21 |
22 | Version 1.1.1 *(2015-07-09)*
23 | ----------------------------
24 |
25 | *Fix: update to work with Youtube API v3
26 |
27 | ----------------------------
28 |
29 | previous release. No changelog before :(
30 |
--------------------------------------------------------------------------------
/demo/fixed.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Fixed width - lazyYT jQuery plugin demo
11 |
12 |
13 |
14 |
15 |
30 |
31 |
32 |
33 | Fork me on GitHub
34 |
35 |
36 |
Fixed width video
37 |
38 |
39 |
40 |
41 |
42 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/demo/fluid.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Fluid width - lazyYT jQuery plugin demo
11 |
12 |
13 |
14 |
15 |
31 |
32 |
33 |
34 | Fork me on GitHub
35 |
36 |
37 |
Fluid width video
38 |
39 |
40 |
41 |
42 |
43 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/demo/grid.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Grid - lazyYT jQuery plugin demo
10 |
11 |
12 |
13 |
14 |
36 |
37 |
38 |
39 | Fork me on GitHub
40 |
41 |
42 |
Video grid
43 |
44 |
45 |
46 |
47 |
Loading video...
48 |
49 |
50 |
Loading video...
51 |
52 |
55 |
56 |
59 |
62 |
65 |
66 |
69 |
72 |
75 |
76 |
79 |
82 |
85 |
86 |
Just take a look how fast they all load!
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
114 |
115 |
116 |
--------------------------------------------------------------------------------
/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | lazyYT jQuery plugin demo
10 |
11 |
12 |
13 |
14 |
37 |
38 |
39 |
40 | Fork me on GitHub
41 |
42 |
43 |
lazyYT demo
44 |
v1.3.0 (2016-03-06)
45 |
46 |
51 |
52 |
53 |
54 |
55 |
56 |
65 |
66 |
67 |
--------------------------------------------------------------------------------
/lazyYT.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * lazyYT (lazy load YouTube videos)
3 | * v1.3.0 - 2016-03-06
4 | * (CC) This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
5 | * http://creativecommons.org/licenses/by-sa/4.0/
6 | * Contributors: https://github.com/tylerpearson/lazyYT/graphs/contributors || https://github.com/daugilas/lazyYT/graphs/contributors
7 | */
8 |
9 | .lazyYT-container {
10 | position: relative;
11 | display: block;
12 | height: 0;
13 | padding: 0 0 56.25% 0;
14 | overflow: hidden;
15 | background-color: #000000;
16 | }
17 |
18 | .lazyYT-container iframe {
19 | position: absolute;
20 | top: 0;
21 | bottom: 0;
22 | left: 0;
23 | width: 100%;
24 | height: 100%;
25 | border: 0;
26 | }
27 |
28 | /*
29 | * Video Title (YouTube style)
30 | */
31 |
32 | .ytp-gradient-top {
33 | top: 0;
34 | z-index: 21;
35 | width: 100%;
36 | height: 98px;
37 | position: absolute;
38 | pointer-events: none;
39 | background-repeat: repeat-x;
40 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAABiCAQAAAA7fHH2AAAAQUlEQVQYV22KQQoAIAzDyv7/Et/oVlGZVCfkkIYamsENXESyi8vc0u/PKZ6o8+7fZ0h8ShRYnD+BFKToRJkHFpkM2hZSxuyWpEYAAAAASUVORK5CYII=);
41 | -webkit-transition: opacity 0.25s cubic-bezier(0, 0, 0.2, 1);
42 | -moz-transition: opacity 0.25s cubic-bezier(0, 0, 0.2, 1);
43 | transition: opacity 0.25s cubic-bezier(0, 0, 0.2, 1);
44 | }
45 |
46 | .ytp-chrome-top {
47 | position: absolute;
48 | left: 12px;
49 | right: 10px;
50 | top: 0;
51 | font-family: Roboto,Arial,Helvetica,sans-serif;
52 | color: #eee;
53 | text-align: left;
54 | direction: ltr;
55 | font-size: 11px;
56 | line-height: 1.3;
57 | -webkit-font-smoothing: antialiased;
58 | text-shadow: 0 0 2px rgba(0,0,0,.5);
59 | z-index: 60;
60 | -moz-transition: opacity .25s cubic-bezier(0.0,0.0,0.2,1);
61 | -webkit-transition: opacity .25s cubic-bezier(0.0,0.0,0.2,1);
62 | transition: opacity .25s cubic-bezier(0.0,0.0,0.2,1);
63 | }
64 |
65 | .ytp-title {
66 | font-size: 150%;
67 | overflow: hidden;
68 | padding-right: 20px;
69 | white-space: nowrap;
70 | }
71 |
72 | .ytp-title-text {
73 | padding-top: 15px;
74 | display: inline-block;
75 | line-height: 1.1;
76 | vertical-align: top;
77 | max-width: 100%;
78 | margin-left: 4px;
79 | }
80 |
81 | .ytp-title-link {
82 | max-width: 100%;
83 | overflow: hidden;
84 | color: #eee;
85 | text-decoration: none;
86 | white-space: nowrap;
87 | word-wrap: normal;
88 | -o-text-overflow: ellipsis;
89 | text-overflow: ellipsis;
90 | float: left;
91 | }
92 |
93 | /*
94 | * Thumbnail
95 | */
96 |
97 | .ytp-thumbnail {
98 | position: absolute;
99 | width: 100%;
100 | height: 100%;
101 | top: 0;
102 | left: 0;
103 | z-index: 12;
104 | cursor: pointer;
105 | background-position: 50% 50%;
106 | background-repeat: no-repeat;
107 | -moz-transition: opacity .5s cubic-bezier(0.0,0.0,0.2,1);
108 | -webkit-transition: opacity .5s cubic-bezier(0.0,0.0,0.2,1);
109 | transition: opacity .5s cubic-bezier(0.0,0.0,0.2,1);
110 | -webkit-background-size: cover;
111 | -moz-background-size: cover;
112 | -o-background-size: cover;
113 | background-size: cover;
114 | }
115 |
116 |
117 | .lazyYT-image-loaded .ytp-spinner {
118 | display: none;
119 | }
120 | .ytp-thumbnail button.ytp-button {
121 | visibility: hidden;
122 | }
123 | .ytp-thumbnail.lazyYT-image-loaded button.ytp-button {
124 | visibility: visible;
125 | }
126 |
127 | /*
128 | * Spinner pre-loader
129 | */
130 | .ytp-spinner {
131 | position: absolute;
132 | left: 45%;
133 | top: 45%;
134 | width: 10%;
135 | height: 10%;
136 | z-index: 16;
137 | }
138 |
139 | .ytp-spinner-message {
140 | position: absolute;
141 | left: 50%;
142 | top: 100%;
143 | width: 300px;
144 | font-size: 127%;
145 | line-height: 182%;
146 | margin-left: -150px;
147 | display: none;
148 | text-align: center;
149 | background-color: black;
150 | opacity: .5
151 | }@keyframes ytp-spinner-dot-fade{0%{opacity:.5;-moz-transform:scale(1.2,1.2);-ms-transform:scale(1.2,1.2);-webkit-transform:scale(1.2,1.2);transform:scale(1.2,1.2)}50%{opacity:.15;-moz-transform:scale(.9,.9);-ms-transform:scale(.9,.9);-webkit-transform:scale(.9,.9);transform:scale(.9,.9)}
152 |
153 | to {
154 | opacity: .15;
155 | -moz-transform: scale(.85,.85);
156 | -ms-transform: scale(.85,.85);
157 | -webkit-transform: scale(.85,.85);
158 | transform: scale(.85,.85)
159 | }}@-moz-keyframes ytp-spinner-dot-fade{0%{opacity:.5;-moz-transform:scale(1.2,1.2);-ms-transform:scale(1.2,1.2);-webkit-transform:scale(1.2,1.2);transform:scale(1.2,1.2)}50%{opacity:.15;-moz-transform:scale(.9,.9);-ms-transform:scale(.9,.9);-webkit-transform:scale(.9,.9);transform:scale(.9,.9)}
160 |
161 | to {
162 | opacity: .15;
163 | -moz-transform: scale(.85,.85);
164 | -ms-transform: scale(.85,.85);
165 | -webkit-transform: scale(.85,.85);
166 | transform: scale(.85,.85)
167 | }}@-webkit-keyframes ytp-spinner-dot-fade{0%{opacity:.5;-moz-transform:scale(1.2,1.2);-ms-transform:scale(1.2,1.2);-webkit-transform:scale(1.2,1.2);transform:scale(1.2,1.2)}50%{opacity:.15;-moz-transform:scale(.9,.9);-ms-transform:scale(.9,.9);-webkit-transform:scale(.9,.9);transform:scale(.9,.9)}
168 |
169 | to {
170 | opacity: .15;
171 | -moz-transform: scale(.85,.85);
172 | -ms-transform: scale(.85,.85);
173 | -webkit-transform: scale(.85,.85);
174 | transform: scale(.85,.85)
175 | }}
176 |
177 | .ytp-spinner-dot {
178 | -moz-animation: ytp-spinner-dot-fade .8s ease infinite;
179 | -webkit-animation: ytp-spinner-dot-fade .8s ease infinite;
180 | animation: ytp-spinner-dot-fade .8s ease infinite;
181 | opacity: 0;
182 | fill: #ccc;
183 | -moz-transform-origin: 4px 4px;
184 | -ms-transform-origin: 4px 4px;
185 | -webkit-transform-origin: 4px 4px;
186 | transform-origin: 4px 4px
187 | }
188 |
189 | .ytp-spinner-dot-1 {
190 | -moz-animation-delay: .1s;
191 | -webkit-animation-delay: .1s;
192 | animation-delay: .1s
193 | }
194 |
195 | .ytp-spinner-dot-2 {
196 | -moz-animation-delay: .2s;
197 | -webkit-animation-delay: .2s;
198 | animation-delay: .2s
199 | }
200 |
201 | .ytp-spinner-dot-3 {
202 | -moz-animation-delay: .3s;
203 | -webkit-animation-delay: .3s;
204 | animation-delay: .3s
205 | }
206 |
207 | .ytp-spinner-dot-4 {
208 | -moz-animation-delay: .4s;
209 | -webkit-animation-delay: .4s;
210 | animation-delay: .4s
211 | }
212 |
213 | .ytp-spinner-dot-5 {
214 | -moz-animation-delay: .5s;
215 | -webkit-animation-delay: .5s;
216 | animation-delay: .5s
217 | }
218 |
219 | .ytp-spinner-dot-6 {
220 | -moz-animation-delay: .6s;
221 | -webkit-animation-delay: .6s;
222 | animation-delay: .6s
223 | }
224 |
225 | .ytp-spinner-dot-7 {
226 | -moz-animation-delay: .7s;
227 | -webkit-animation-delay: .7s;
228 | animation-delay: .7s
229 | }
230 |
231 | /*
232 | * Play button (YouTube style)
233 | */
234 | .ytp-button:focus,
235 | .ytp-button {
236 | border: none;
237 | outline: 0;
238 | color: inherit;
239 | text-align: inherit;
240 | font-size: 100%;
241 | font-family: inherit;
242 | cursor: default;
243 | line-height: inherit;
244 |
245 | /* margin: 0; */
246 | padding: 0;
247 | background: transparent;
248 | }
249 |
250 | .ytp-large-play-button {
251 | position: absolute;
252 | left: 50%;
253 | top: 50%;
254 | width: 68px;
255 | height: 48px;
256 | margin-left: -34px;
257 | margin-top: -24px;
258 | -moz-transition: opacity .25s cubic-bezier(0.0,0.0,0.2,1);
259 | -webkit-transition: opacity .25s cubic-bezier(0.0,0.0,0.2,1);
260 | transition: opacity .25s cubic-bezier(0.0,0.0,0.2,1);
261 | }
262 |
263 | .ytp-button:not([aria-disabled=true]):not([disabled]):not([aria-hidden=true]) {
264 | cursor: pointer;
265 | }
266 |
267 | .ytp-large-play-button-bg {
268 | -moz-transition: fill .1s cubic-bezier(0.4, 0.0, 1, 1), opacity .1s cubic-bezier(0.4, 0.0, 1, 1);
269 | -webkit-transition: fill .1s cubic-bezier(0.4, 0.0, 1, 1), opacity .1s cubic-bezier(0.4, 0.0, 1, 1);
270 | transition: fill .1s cubic-bezier(0.4, 0.0, 1, 1), opacity .1s cubic-bezier(0.4, 0.0, 1, 1);
271 | fill: #1f1f1f;
272 | opacity: .9
273 | }
274 |
275 | .ytp-thumbnail:hover .ytp-large-play-button-bg {
276 | -moz-transition: fill .1s cubic-bezier(0.0, 0.0, 0.2, 1), opacity .1s cubic-bezier(0.0, 0.0, 0.2, 1);
277 | -webkit-transition: fill .1s cubic-bezier(0.0, 0.0, 0.2, 1), opacity .1s cubic-bezier(0.0, 0.0, 0.2, 1);
278 | transition: fill .1s cubic-bezier(0.0, 0.0, 0.2, 1), opacity .1s cubic-bezier(0.0, 0.0, 0.2, 1);
279 | fill: #cc181e;
280 | opacity: 1
281 | }
282 |
283 | /*
284 | * Video time (YouTube style)
285 | */
286 |
287 | .video-time {
288 | position: absolute;
289 | right: 2px;
290 | bottom: 2px;
291 | height: 14px;
292 | padding: 0 4px;
293 | font-family: Arial, Helvetica, Sans-serif;
294 | font-size: 11px;
295 | font-weight: bold;
296 | line-height: 14px;
297 | color: #fff !important;
298 | background-color: #000;
299 | opacity: .75;
300 | filter: alpha(opacity=75);
301 | zoom: 1;
302 | }
303 |
--------------------------------------------------------------------------------
/lazyYT.jquery.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lazyYT",
3 | "title": "lazyYT",
4 | "description": "A jQuery plugin to lazy load those darn slow Youtube iframe videos",
5 | "keywords": [
6 | "jQuery",
7 | "lazy",
8 | "load",
9 | "youtube"
10 | ],
11 | "version": "1.3.0",
12 | "author": {
13 | },
14 | "maintainers": [
15 | {
16 | "name": "Daugilas Kakaras",
17 | "email": "daugilas@gmail.com",
18 | "url": "http://daugilas.com"
19 | }
20 | ]
21 | "licenses": [
22 | {
23 | "type": "CC",
24 | "url": "http://creativecommons.org/licenses/by-sa/4.0/"
25 | }
26 | ],
27 | "bugs": "https://github.com/tylerpearson/lazyYT/issues",
28 | "homepage": "https://github.com/tylerpearson/lazyYT",
29 | "docs": "https://github.com/tylerpearson/lazyYT",
30 | "download": "https://github.com/tylerpearson/lazyYT",
31 | "demo" : "http://tylerp.me/lazyYT/",
32 | "dependencies": {
33 | "jquery": ">=1.8"
34 | }
35 | }
--------------------------------------------------------------------------------
/lazyYT.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * lazyYT (lazy load YouTube videos)
3 | * v1.3.0 - 2016-03-06
4 | * (CC) This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.
5 | * http://creativecommons.org/licenses/by-sa/4.0/
6 | * Contributors: https://github.com/tylerpearson/lazyYT/graphs/contributors || https://github.com/daugilas/lazyYT/graphs/contributors
7 | *
8 | * Usage: loading...
9 | */
10 |
11 | ;(function ($) {
12 | 'use strict';
13 |
14 | function setUp($el, settings) {
15 | var width = $el.data('width'),
16 | height = $el.data('height'),
17 | title = $el.attr('title') || $el.data('title'),
18 | display_title = $el.data('display-title'),
19 | ratio = ($el.data('ratio')) ? $el.data('ratio') : settings.default_ratio,
20 | display_duration = $el.data('display-duration'),
21 | id = $el.data('youtube-id'),
22 | padding_bottom,
23 | innerHtml = [],
24 | $thumb,
25 | thumb_img,
26 | loading_text = $el.text() ? $el.text() : settings.loading_text,
27 | youtube_data_url = ['https://www.googleapis.com/youtube/v3/videos?id=', id, '&key=', settings.yt_api_key, '&part=snippet'].join(''),
28 | youtube_parameters = $el.data('parameters') || '';
29 |
30 | ratio = ratio.split(":");
31 |
32 | youtube_parameters += '&' + settings.youtube_parameters;
33 |
34 | if (typeof display_title != "boolean") {
35 | display_title = settings.display_title;
36 | }
37 |
38 | if (typeof display_duration != "boolean") {
39 | display_duration = settings.display_duration;
40 | }
41 |
42 | // width and height might override default_ratio value
43 | if (typeof width === 'number' && typeof height === 'number') {
44 | $el.width(width);
45 | padding_bottom = height + 'px';
46 | } else if (typeof width === 'number') {
47 | $el.width(width);
48 | padding_bottom = (width * ratio[1] / ratio[0]) + 'px';
49 | } else {
50 | width = $el.width();
51 |
52 | // no width means that container is fluid and will be the size of its parent
53 | if (width == 0) {
54 | width = $el.parent().width();
55 | }
56 |
57 | padding_bottom = (ratio[1] / ratio[0] * 100) + '%';
58 | }
59 |
60 | //
61 | // This HTML will be placed inside 'lazyYT' container
62 |
63 | innerHtml.push('');
64 |
65 | // Play button from YouTube (exactly as it is in YouTube)
66 | innerHtml.push('
');
74 | innerHtml.push('');
75 | innerHtml.push(' ');
76 | innerHtml.push(' ');
77 | innerHtml.push(' ');
78 | innerHtml.push(' ');
79 | innerHtml.push(' '); // end of .ytp-large-play-button
80 |
81 | innerHtml.push('
');
82 | innerHtml.push('
');
83 | innerHtml.push('');
84 | innerHtml.push(' ');
85 | innerHtml.push(' ');
86 | innerHtml.push(' ');
87 | innerHtml.push(' ');
88 | innerHtml.push(' ');
89 | innerHtml.push(' ');
90 | innerHtml.push(' ');
91 | innerHtml.push(' ');
92 | innerHtml.push(' ');
93 | innerHtml.push(' ');
94 | innerHtml.push('
If playback doesn\'t begin shortly, try restarting your device.
');
95 | innerHtml.push('
'); // end of .ytp-spinner
96 |
97 | // video time from YouTube (exactly as it is in YouTube)
98 | if (display_duration) {
99 | innerHtml.push('
');
100 | }
101 | innerHtml.push('
'); // end of .ytp-thumbnail
102 |
103 | // Video title (info bar)
104 | if (display_title) {
105 | innerHtml.push('
');
106 | innerHtml.push('');
107 | innerHtml.push('
');
108 | innerHtml.push('
'); // /.ytp-title-text
113 | innerHtml.push('
'); // /.ytp-title
114 | innerHtml.push('
'); // /.ytp-chrome-top
115 | }
116 |
117 | $el.css({
118 | 'padding-bottom': padding_bottom
119 | })
120 | .html(innerHtml.join(''));
121 |
122 | $thumb = $el.find('.ytp-thumbnail').on('click', function (e) {
123 | e.preventDefault();
124 | if (!$el.hasClass(settings.video_loaded_class)) {
125 | $el.html('VIDEO ')
126 | .addClass(settings.video_loaded_class);
127 |
128 | // execute callback
129 | if (typeof settings.callback == 'function') { // make sure the callback is a function
130 | settings.callback.call($el); // brings the scope to the callback
131 | }
132 | }
133 | });
134 | loadBackgroundImage(id, width, $thumb, youtube_data_url);
135 |
136 | if ((!title && display_title) || display_duration) {
137 | if (display_duration) youtube_data_url += ',contentDetails'; // this extra info now costs some quota points, so we retrieve it only when necessary. More on quota: https://developers.google.com/youtube/v3/getting-started#quota
138 |
139 | $.getJSON(youtube_data_url, function (data) {
140 | var item = data.items[0];
141 | // console.log(item.snippet.title);
142 |
143 | $el.find('#lazyYT-title-' + id).text(item.snippet.title);
144 |
145 | if (display_duration) {
146 | $el.find('.video-time')
147 | .text(parseDuration(item.contentDetails.duration, settings))
148 | .show();
149 | }
150 |
151 | });
152 | }
153 |
154 | };
155 |
156 | function loadBackgroundImage(id, width, $thumb, youtube_data_url) {
157 | var thumb_img,
158 | thumb_url,
159 | downloadingImage = new Image();
160 |
161 | if (width == 0) width = $thumb.width(); // sometimes (on fluid layout) it fails to get proper width immediately - so we try here again
162 | if (width > 640) {
163 | thumb_img = 'maxresdefault.jpg';
164 | } else if (width > 480) {
165 | thumb_img = 'sddefault.jpg';
166 | } else if (width > 320) {
167 | thumb_img = 'hqdefault.jpg';
168 | } else if (width > 120) {
169 | thumb_img = 'mqdefault.jpg';
170 | } else if (width == 0) { // sometimes it still might fail on fluid layout
171 | thumb_img = 'hqdefault.jpg';
172 | } else {
173 | thumb_img = 'default.jpg';
174 | }
175 |
176 | thumb_url = ['https://img.youtube.com/vi/', id, '/', thumb_img].join('');
177 |
178 | downloadingImage.onload = function(data) {
179 | var naturalWidth = getOnloadDataParam(data, 'naturalWidth');
180 |
181 | /*
182 | * Sometimes instead of an expected higher resolution image we get this 120x90 px
183 | * default img: https://img.youtube.com/vi/default.jpg
184 | * That sucks. So lets extract a proper thumbnail from YouTube API!
185 | */
186 | if (naturalWidth < width) {
187 | $.getJSON(youtube_data_url, function (data) {
188 | var item = data.items[0],
189 | thumbs = item.snippet.thumbnails;
190 | if (width == 0) width = $thumb.width(); // just to make sure we have width
191 | if (width > 640 && typeof thumbs.maxres == 'object') {
192 | thumb_url = thumbs.maxres.url;
193 | } else if (width > 480 && typeof thumbs.standard == 'object') {
194 | thumb_url = thumbs.standard.url;
195 | } else if (width > 320 && typeof thumbs.high == 'object') {
196 | thumb_url = thumbs.high.url;
197 | } else if (width > 120 && typeof thumbs.medium == 'object') {
198 | thumb_url = thumbs.medium.url;
199 | } else {
200 | thumb_url = thumbs['default'].url;
201 | }
202 | setBackgroundImage($thumb, thumb_url);
203 | });
204 | } else {
205 | setBackgroundImage($thumb, this.src);
206 | }
207 |
208 | };
209 |
210 | downloadingImage.src = thumb_url;
211 | }
212 |
213 | function setBackgroundImage($thumb, url) {
214 | $thumb.css({
215 | 'background-image': ['url(', url, ')'].join('')
216 | }).addClass('lazyYT-image-loaded');
217 | }
218 |
219 | function getOnloadDataParam(data, key) {
220 | var img_data;
221 | if (typeof data.path == 'object') {
222 | img_data = data.path[0];
223 | } else if(typeof data.target == 'object') {
224 | img_data = data.target;
225 | } else {
226 | img_data = data.originalTarget;
227 | }
228 | return img_data.naturalWidth;
229 | }
230 |
231 | function parseDuration(PT, settings) {
232 | var output = [];
233 | var durationInSec = 0;
234 | var matches = PT.match(/P(?:(\d*)Y)?(?:(\d*)M)?(?:(\d*)W)?(?:(\d*)D)?T(?:(\d*)H)?(?:(\d*)M)?(?:(\d*)S)?/i);
235 | var parts = [
236 | { // years
237 | pos: 1,
238 | multiplier: 86400 * 365
239 | },
240 | { // months
241 | pos: 2,
242 | multiplier: 86400 * 30
243 | },
244 | { // weeks
245 | pos: 3,
246 | multiplier: 604800
247 | },
248 | { // days
249 | pos: 4,
250 | multiplier: 86400
251 | },
252 | { // hours
253 | pos: 5,
254 | multiplier: 3600
255 | },
256 | { // minutes
257 | pos: 6,
258 | multiplier: 60
259 | },
260 | { // seconds
261 | pos: 7,
262 | multiplier: 1
263 | }
264 | ];
265 |
266 | for (var i = 0; i < parts.length; i++) {
267 | if (typeof matches[parts[i].pos] != 'undefined') {
268 | durationInSec += parseInt(matches[parts[i].pos]) * parts[i].multiplier;
269 | }
270 | }
271 |
272 | // Hours extraction
273 | if (durationInSec > 3599) {
274 | output.push(parseInt(durationInSec / 3600));
275 | durationInSec %= 3600;
276 | }
277 | // Minutes extraction with leading zero
278 | output.push(('0' + parseInt(durationInSec / 60)).slice(-2));
279 | // Seconds extraction with leading zero
280 | output.push(('0' + durationInSec % 60).slice(-2));
281 |
282 | return output.join(':');
283 | };
284 |
285 | $.fn.lazyYT = function (yt_api_key, newSettings) {
286 | var defaultSettings = {
287 | yt_api_key: yt_api_key,
288 |
289 | youtube_parameters: 'rel=0',
290 | loading_text: 'Loading...',
291 | display_title: true,
292 | default_ratio: '16:9',
293 | display_duration: false,
294 | callback: null,
295 |
296 | // Advanced settings
297 | video_loaded_class: 'lazyYT-video-loaded',
298 | container_class: 'lazyYT-container'
299 | };
300 | var settings = $.extend(defaultSettings, newSettings);
301 |
302 | return this.each(function () {
303 | var $el = $(this).addClass(settings.container_class);
304 | setUp($el, settings);
305 | });
306 | };
307 |
308 | }(jQuery));
309 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lazyyt",
3 | "version": "1.3.0",
4 | "description": "A jQuery plugin to lazy load those darn slow Youtube iframe videos",
5 | "main": "lazyyt.js",
6 | "repository": {
7 | "type": "git",
8 | "url": "git://github.com/Daugilas/lazyYT.git"
9 | },
10 | "keywords": [
11 | "jQuery",
12 | "lazy load",
13 | "youtube"
14 | ],
15 | "authors": [
16 | "Daugilas Kakaras (http://daugilas.com)",
17 | "Tyler Pearson (http://tylerp.me)"
18 | ],
19 | "license": "CC",
20 | "bugs": {
21 | "url": "https://github.com/Daugilas/lazyYT/issues"
22 | },
23 | "devDependencies": {
24 | "grunt": "~0.4.2",
25 | "grunt-contrib-jshint": "~0.6.3",
26 | "grunt-contrib-uglify": "~0.2.2",
27 | "grunt-contrib-cssmin": "~0.9.0"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------