1class LiteYTEmbed extends HTMLElement { 2 constructor() { 3 super(); 4 this.videoId = encodeURIComponent(this.getAttribute('videoid')); 5 this.posterUrl = `https://i.ytimg.com/vi_webp/${this.videoId}/maxresdefault.webp`; 6 this.fallbackPosterUrl = `https://i.ytimg.com/vi/${this.videoId}/hqdefault.jpg`; 7 } 8 9 async connectedCallback() { 10 11 // try and load the high resolution poster first, otherwise fall back to lower res. 12 // sometimes not all images exist 13 14 const validPosterUrl = await this.checkImageExists(this.posterUrl) 15 .then(() => this.posterUrl) 16 .catch(() => this.fallbackPosterUrl); 17 18 this.style.backgroundImage = `url("${validPosterUrl}")`; 19 20 if (!this.querySelector(".lty-playbtn")) { 21 const playBtn = document.createElement('div'); 22 playBtn.classList.add('lty-playbtn'); 23 this.append(playBtn); 24 25 // On hover (or tap), warm up the TCP connections we're (likely) about to use. 26 this.addEventListener('pointerover', LiteYTEmbed.warmConnections, { once: true }); 27 28 // Once the user clicks, add the real iframe and drop our play button 29 // TODO: In the future we could be like amp-youtube and silently swap in the iframe during idle time 30 // We'd want to only do this for in-viewport or near-viewport ones: https://github.com/ampproject/amphtml/pull/5003 31 this.addEventListener('click', e => this.addIframe()); 32 } 33 } 34 35 async checkImageExists(url) { 36 return fetch(url, { method: 'HEAD' }) 37 .then(response => { 38 if (!response.ok) { 39 console.log(response); 40 throw new Error('Image not found'); 41 } 42 43 return response; 44 }); 45 } 46 47 /** 48 * Add a <link rel={preload | preconnect} ...> to the head 49 */ 50 static addPrefetch(kind, url, as) { 51 const linkElem = document.createElement('link'); 52 linkElem.rel = kind; 53 linkElem.href = url; 54 if (as) { 55 linkElem.as = as; 56 } 57 linkElem.crossorigin = true; 58 document.head.append(linkElem); 59 } 60 61 /** 62 * Begin pre-connecting to warm up the iframe load 63 * Since the embed's network requests load within its iframe, 64 * preload/prefetch'ing them outside the iframe will only cause double-downloads. 65 * So, the best we can do is warm up a few connections to origins that are in the critical path. 66 * 67 * Maybe `<link rel=preload as=document>` would work, but it's unsupported: http://crbug.com/593267 68 * But TBH, I don't think it'll happen soon with Site Isolation and split caches adding serious complexity. 69 */ 70 static warmConnections() { 71 if (LiteYTEmbed.preconnected) return; 72 73 LiteYTEmbed.addPrefetch('preconnect', 'https://www.youtube.com'); 74 LiteYTEmbed.addPrefetch('preconnect', 'https://www.google.com'); 75 LiteYTEmbed.addPrefetch('preconnect', 'https://googleads.g.doubleclick.net'); 76 LiteYTEmbed.addPrefetch('preconnect', 'https://static.doubleclick.net'); 77 78 LiteYTEmbed.preconnected = true; 79 } 80 81 addIframe() { 82 const iframeHTML = ` 83<iframe width="560" height="315" frameborder="0" 84 allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen 85 src="https://www.youtube.com/embed/${this.videoId}?autoplay=1" 86></iframe>`; 87 this.insertAdjacentHTML('beforeend', iframeHTML); 88 this.classList.add('lyt-activated'); 89 } 90} 91// Register custom element 92customElements.define('lite-youtube', LiteYTEmbed);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.