1import { Controller } from "@hotwired/stimulus" 2 3// Connects to data-controller="numiko--youtube-card" 4export default class extends Controller { 5 static targets = [ 6 'img', 7 'title', 8 'description', 9 ] 10 11 static values = { 12 apiUrl: String, 13 videoUrl: String, 14 imageOnly: { type: Boolean, default: false } 15 } 16 17 connect () { 18 this.#getVideoDetails() 19 .then((snippet) => { 20 this.#writeVideoDetails(snippet) 21 }) 22 .catch(error => console.error(error)); 23 } 24 25 async #getVideoDetails () { 26 try { 27 const response = await fetch(this.apiUrlValue); 28 const data = await response.json(); 29 30 if (data.items && data.items.length > 0) { 31 return data.items[0].snippet; 32 } else { 33 throw new Error('Video not found or invalid API key'); 34 } 35 } catch (error) { 36 console.error('Error fetching video description:', error); 37 throw error; 38 } 39 } 40 41 #writeVideoDetails (snippet) { 42 const thumbnailUrl=snippet.thumbnails.standard.url; 43 const title=snippet.title; 44 const description=snippet.description; 45 46 if (this.imageOnlyValue) { 47 this.imgTarget.src=thumbnailUrl 48 this.imgTarget.alt=title 49 } else { 50 this.imgTarget.src=thumbnailUrl 51 this.imgTarget.alt=title 52 if (this.hasTitleTarget) { 53 this.titleTarget.innerHTML=title 54 } 55 this.element.dataset.videoTitle=title 56 if (this.hasDescriptionTarget) { 57 this.descriptionTarget.innerHTML=this.#stripHtml(description).slice(0, 100) + '...'; 58 } 59 this.element.dataset.videoDescription=description 60 } 61 } 62 63 #stripHtml (text) { 64 return text.split(/<[^>]*>/).join(''); 65 } 66}
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.