PageSourceSearch

https://www.ciudaddelaluz.com/services/MediaService.js

js ciudaddelaluz.com collected 2026-09-25 00:46:23 UTC 3,302 bytes, 91 lines download raw bytes

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.