1// services/MediaService.js 2import { AppConfig } from "../config/AppConfig.js"; 3 4class MediaService { 5 // Imagen de fallback por si falla algo 6 fallbackImage = "/assets/soleado.jpg"; 7 8 /** 9 * Extrae de forma segura la URL de cualquier estructura de imagen de Strapi. 10 * GARANTÃA: Siempre devuelve un String (La URL final o vacÃo). 11 * * @param {any} imagePayload - El objeto de imagen, array o string. 12 * @param {string} format - 'thumbnail', 'small', 'medium', 'large' 13 * @returns {string} - La URL absoluta de la imagen. 14 */ 15 getImageUrl(imagePayload, format = "medium") { 16 // 1. Manejo de nulos o vacÃos 17 if (!imagePayload) { 18 return ''; 19 } 20 21 // 2. Si ya es un texto (Ruta o URL directa) 22 if (typeof imagePayload === 'string') { 23 return this._formatFullUrl(imagePayload); 24 } 25 26 // 3. Si es un Array (GalerÃa de múltiples fotos) 27 // Extraemos solo la primera foto automáticamente para no romper el <img> 28 if (Array.isArray(imagePayload)) { 29 if (imagePayload.length === 0) return ''; 30 return this.getImageUrl(imagePayload[0], format); 31 } 32 33 // 4. Si es un Objeto (Estructura de Strapi) 34 if (typeof imagePayload === 'object') { 35 let targetUrl = ''; 36 37 // Caso A: Objeto directo (Strapi 5 Sanitizado) 38 if (imagePayload.url) { 39 targetUrl = imagePayload.formats?.[format]?.url || imagePayload.url; 40 } 41 // Caso B: Envuelto en 'data' (Strapi sin sanitizar) 42 else if (imagePayload.data && imagePayload.data.url) { 43 targetUrl = imagePayload.data.formats?.[format]?.url || imagePayload.data.url; 44 } 45 // Caso C: Legacy (Strapi 4 con attributes) 46 else if (imagePayload.data && imagePayload.data.attributes?.url) { 47 const attrs = imagePayload.data.attributes; 48 targetUrl = attrs.formats?.[format]?.url || attrs.url; 49 } 50 51 // Si encontramos la URL, la formateamos 52 if (targetUrl) { 53 return this._formatFullUrl(targetUrl); 54 } 55 } 56 57 // Si el payload no encaja en nada de lo anterior, devolvemos string vacÃo 58 return ''; 59 } 60 61 /** 62 * Helper privado para formatear la URL final concatenando el dominio de la API 63 */ 64 _formatFullUrl(path) { 65 if (!path) return ''; 66 if (path.startsWith('http')) return path; 67 68 if (path.startsWith('/uploads/')) { 69 return AppConfig.API_BASE_URL.concat('', path); 70 } 71 72 return path; 73 } 74 75 getEmbedUrl(url) { 76 if (!url) return ''; 77 78 // Extraer el ID del video (funciona con links normales, cortos de youtu.be y de shorts) 79 const regExp = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/; 80 const match = url.match(regExp); 81 const videoId = (match && match[2].length === 11) ? match[2] : null; 82 83 if (videoId) { 84 return `https://www.youtube-nocookie.com/embed/${videoId.trim()}?rel=0`; 85 } 86 87 return url; // Si no es de YouTube, devuelve la original 88 } 89} 90 91export const mediaService = new MediaService();
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.