diff --git a/package-lock.json b/package-lock.json index af2108b..d6ee046 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,8 @@ "express-fileupload": "^1.3.1", "express-myconnection": "^1.0.4", "express-session": "^1.17.3", + "ffmpeg-static": "^5.2.0", + "fluent-ffmpeg": "^2.1.3", "jsonwebtoken": "^9.0.2", "morgan": "^1.10.0", "mysql": "^2.18.1", @@ -146,6 +148,20 @@ "node": ">=6.9.0" } }, + "node_modules/@derhuerst/http-basic": { + "version": "8.2.4", + "resolved": "https://registry.npmjs.org/@derhuerst/http-basic/-/http-basic-8.2.4.tgz", + "integrity": "sha512-F9rL9k9Xjf5blCz8HsJRO4diy111cayL2vkY2XE4r4t3n0yPXVYy3KD3nJ1qbrSn9743UWSXH4IwuCa/HWlGFw==", + "dependencies": { + "caseless": "^0.12.0", + "concat-stream": "^2.0.0", + "http-response-object": "^3.0.1", + "parse-cache-control": "^1.0.1" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.8", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", @@ -380,7 +396,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, "dependencies": { "debug": "4" }, @@ -392,7 +407,6 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", - "dev": true, "dependencies": { "ms": "^2.1.3" }, @@ -408,8 +422,7 @@ "node_modules/agent-base/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/ansi-regex": { "version": "5.0.1", @@ -745,6 +758,11 @@ "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -804,6 +822,11 @@ "node": ">=6" } }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -901,6 +924,33 @@ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "engines": [ + "node >= 6.0" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -1453,6 +1503,21 @@ "pend": "~1.2.0" } }, + "node_modules/ffmpeg-static": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ffmpeg-static/-/ffmpeg-static-5.2.0.tgz", + "integrity": "sha512-WrM7kLW+do9HLr+H6tk7LzQ7kPqbAgLjdzNE32+u3Ff11gXt9Kkkd2nusGFrlWMIe+XaA97t+I8JS7sZIrvRgA==", + "hasInstallScript": true, + "dependencies": { + "@derhuerst/http-basic": "^8.2.0", + "env-paths": "^2.2.0", + "https-proxy-agent": "^5.0.0", + "progress": "^2.0.3" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/filelist": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", @@ -1509,6 +1574,24 @@ "node": ">= 0.8" } }, + "node_modules/fluent-ffmpeg": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fluent-ffmpeg/-/fluent-ffmpeg-2.1.3.tgz", + "integrity": "sha512-Be3narBNt2s6bsaqP6Jzq91heDgOEaDCJAXcE3qcma/EJBSy5FB4cvO31XBInuAuKBx8Kptf8dkhjK0IOru39Q==", + "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", + "dependencies": { + "async": "^0.2.9", + "which": "^1.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/fluent-ffmpeg/node_modules/async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha512-eAkdoKxU6/LkKDBzLpT+t6Ff5EtfSF4wx1WfJiPEEV7WNLnDaRXk0oVysiEPm262roaachGexwUv94WhSgN5TQ==" + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -1852,11 +1935,23 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, + "node_modules/http-response-object": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/http-response-object/-/http-response-object-3.0.2.tgz", + "integrity": "sha512-bqX0XTF6fnXSQcEJ2Iuyr75yVakyjIDCqroJQ/aHfSdlM743Cwqoi2nDYMzLGWUcuTWGWy8AAvOKXTfiv6q9RA==", + "dependencies": { + "@types/node": "^10.0.3" + } + }, + "node_modules/http-response-object/node_modules/@types/node": { + "version": "10.17.60", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.60.tgz", + "integrity": "sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw==" + }, "node_modules/https-proxy-agent": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, "dependencies": { "agent-base": "6", "debug": "4" @@ -1869,7 +1964,6 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", - "dev": true, "dependencies": { "ms": "^2.1.3" }, @@ -1885,8 +1979,7 @@ "node_modules/https-proxy-agent/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/iconv-lite": { "version": "0.4.24", @@ -2083,6 +2176,11 @@ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, "node_modules/jake": { "version": "10.9.1", "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.1.tgz", @@ -2827,6 +2925,11 @@ "node": ">=6" } }, + "node_modules/parse-cache-control": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-cache-control/-/parse-cache-control-1.0.1.tgz", + "integrity": "sha512-60zvsJReQPX5/QP0Kzfd/VrpjScIQ7SHBW6bFCYfEP+fp0Eppr1SHhIO5nd1PjZtvclzSzES9D/p5nFJurwfWg==" + }, "node_modules/parse-json": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", @@ -3980,6 +4083,11 @@ "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.0.tgz", "integrity": "sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==" }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + }, "node_modules/typegram": { "version": "3.12.0", "resolved": "https://registry.npmjs.org/typegram/-/typegram-3.12.0.tgz", @@ -4080,6 +4188,17 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, "node_modules/wrap-ansi": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", diff --git a/package.json b/package.json index 2c5a006..9e8468c 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,8 @@ "express-fileupload": "^1.3.1", "express-myconnection": "^1.0.4", "express-session": "^1.17.3", + "ffmpeg-static": "^5.2.0", + "fluent-ffmpeg": "^2.1.3", "jsonwebtoken": "^9.0.2", "morgan": "^1.10.0", "mysql": "^2.18.1", diff --git a/src/controladores/controlador_Apps.js b/src/controladores/controlador_Apps.js index d15b822..70850fe 100644 --- a/src/controladores/controlador_Apps.js +++ b/src/controladores/controlador_Apps.js @@ -1,5 +1,7 @@ const controlador = {}; + + controlador.app_restaurant = (req, res) => { res.render('app_restaurant'); }; @@ -30,15 +32,8 @@ controlador.speedtest = (req, res) => { res.render('test_velocidad') }; -//videos de ayuda sigma -controlador.videos = (req, res) => { - //res.render('speedtest'); - res.render('videos') -}; -controlador.upload = (req, res) => { - //res.render('speedtest'); - res.render('video_upload') -}; + + /** aqui iniciamo la vista de ejs **/ controlador.config = (req, res) => { diff --git a/src/controladores/controlador_Clientes.js b/src/controladores/controlador_Clientes.js index aa4d2df..7a0cdda 100644 --- a/src/controladores/controlador_Clientes.js +++ b/src/controladores/controlador_Clientes.js @@ -176,7 +176,7 @@ controlador.app_pedidos_clientes = (req, res) => { /** * @function consulta_clientesApps * @description Consulta clientes por nombre, RUC o cédula para el autocomplete en aplicaciones. - * Espera un parámetro de consulta en la URL: /consultaClientesJson?consulta=dato + * Espera un parámetro de consulta en la URL: /consulta_clientesApps?consulta=dato * Donde 'dato' puede ser parte del nombre, RUC o cédula. * @param {Object} req - Objeto de solicitud de Express (req.query.consulta). * @param {Object} res - Objeto de respuesta de Express. @@ -497,7 +497,7 @@ controlador.app_pedidos_clientes = (req, res) => { return res.status(500).json({ mensaje: 'Error de conexión', error: err.message }); } // Incluir client_id en la selección - conn.query(`SELECT client_id, client_rucCed,client_nombre,client_direccion,client_celular,client_email FROM clientes WHERE client_nombre like ? or client_rucCed like ?`, [consulta, consulta], (err, rows) => { + conn.query(`SELECT client_id, client_rucCed,client_nombre,client_direccion,client_celular,client_email FROM clientes WHERE client_nombre like ? or client_rucCed like ? LIMIT 50`, [consulta, consulta], (err, rows) => { if (err) { console.error('Error en app_pedidos_clientes:', err); return res.status(500).json({ mensaje: 'Error al consultar clientes.', error: err.message }); diff --git a/src/controladores/controlador_videos.js b/src/controladores/controlador_videos.js new file mode 100644 index 0000000..59a083e --- /dev/null +++ b/src/controladores/controlador_videos.js @@ -0,0 +1,181 @@ +controlador_videos = {}; +const path = require('path'); +const { v4: uuidv4 } = require('uuid'); +const fs = require('fs').promises; +const ffmpeg = require('fluent-ffmpeg'); +ffmpeg.setFfmpegPath(require('ffmpeg-static')); + +controlador_videos.video_v1 = async (req, res) => { // Función para mostrar la galería V1 + const videosDir = path.join(__dirname, '..', 'public', 'videos_v1'); + const thumbnailsDir = path.join(videosDir, 'thumbnails'); + + try { + await fs.mkdir(thumbnailsDir, { recursive: true }); + + const allFiles = await fs.readdir(videosDir); + const videoFiles = allFiles.filter(file => { + try { + // Asegurarse de que es un archivo y tiene una extensión de video + return fs.statSync(path.join(videosDir, file)).isFile() && /\.(mp4|webm|ogg|mov)$/i.test(file); + } catch { + return false; + } + }); + + const videosData = await Promise.all(videoFiles.map(async (file) => { // Usar Promise.all para eficiencia + const videoName = path.parse(file).name; + const thumbnailUrl = `/videos_v1/thumbnails/${videoName}.png`; + const thumbAbsolutePath = path.join(__dirname, '..', 'public', thumbnailUrl); + + let finalThumbnailUrl = '/img/placeholder-video.png'; // Placeholder por defecto + try { + await fs.access(thumbAbsolutePath); // Comprobar si la miniatura existe + finalThumbnailUrl = thumbnailUrl; // La miniatura existe + } catch (e) { + // La miniatura no existe, se usará el placeholder (no hacer nada, ya está asignado) + } + + return { + name: videoName, + videoUrl: `/videos_v1/${file}`, + thumbnailUrl: finalThumbnailUrl + }; + })); + + res.render('video_v1', { videos: videosData, error: null }); // Renderizar con los datos + + } catch (error) { + console.error("Error al leer el directorio de videos V1:", error); + res.render('video_v1', { videos: [], error: "No se pudieron cargar los videos." }); + } + }; + + controlador_videos.upload_v1 = (req, res) => { // Muestra el formulario de subida V1 (GET) + res.render('video_upload_v1') + }; + + controlador_videos.uploadVideoV1 = async (req, res) => { // Procesa la subida del formulario V1 (POST) + if (!req.files || !req.files.video) { // 'video' debe coincidir con el name del input file + return res.status(400).json({ success: false, message: 'No se ha subido ningún archivo de video.' }); + } + + const videoFile = req.files.video; + const videosDir = path.join(__dirname, '..', 'public', 'videos_v1'); + const thumbnailsDir = path.join(videosDir, 'thumbnails'); + const videoAbsolutePath = path.join(videosDir, videoFile.name); + + try { + await fs.mkdir(thumbnailsDir, { recursive: true }); + await videoFile.mv(videoAbsolutePath); + + // Generar miniatura usando FFmpeg + await new Promise((resolve, reject) => { + ffmpeg(videoAbsolutePath) + .on('end', () => resolve()) + .on('error', (err) => reject(new Error(`Error al generar la miniatura: ${err.message}`))) + .screenshots({ + count: 1, + timemarks: ['1'], // Tomar captura en el segundo 1 + folder: thumbnailsDir, + filename: `${path.parse(videoFile.name).name}.png`, + size: '320x240' + }); + }); + + res.json({ success: true, message: 'Video y miniatura subidos correctamente.' }); + } catch (error) { + console.error("Error en la subida V1:", error); + res.status(500).json({ success: false, message: error.message }); + } + }; + + //videos de ayuda sigma + controlador_videos.videos_v2 = (req, res) => { // Muestra la galería V2 (desde la BD) + req.getConnection((err, conn) => { + if (err) { + console.error("Error al obtener conexión para videos V2:", err); + // Renderiza la página de error o una vista con un mensaje de error + return res.status(500).render('videos_v2', { videos: [], error: "Error de conexión con la base de datos." }); + } + + const query = "SELECT video_id, video_nombre, video_descripcion, video_path_url, video_origen FROM videos WHERE video_estado = 'ACTIVO' ORDER BY video_reg DESC"; + + conn.query(query, (err, videos) => { + if (err) { + console.error("Error al consultar videos V2:", err); + return res.status(500).render('videos_v2', { videos: [], error: "Error al consultar los videos." }); + } + res.render('videos_v2', { videos: videos, error: null }); + }); + }); + }; + controlador_videos.upload_v2 = (req, res) => { + // Renderiza la vista correcta para la subida de videos V2 + res.render('videos_upload_v2') + }; + + /** Helper para obtener la fecha y hora actual en formato para la BD */ + const reg_DB = () => { + const today = new Date(); + const year = today.getFullYear(); + const month = String(today.getMonth() + 1).padStart(2, '0'); + const day = String(today.getDate()).padStart(2, '0'); + const hora = `${String(today.getHours()).padStart(2, '0')}:${String(today.getMinutes()).padStart(2, '0')}:${String(today.getSeconds()).padStart(2, '0')}`; + return `${year}-${month}-${day} ${hora}`; + }; + + /** + * @function uploadVideo + * @description Procesa la subida de un video, lo guarda en el servidor y registra en la BD. + * @param {Object} req - Objeto de solicitud de Express. + * @param {Object} res - Objeto de respuesta de Express. + */ + controlador_videos.uploadVideo = async (req, res) => { + try { + const { nombre, descripcion, origen } = req.body; + const urlExterna = req.body.url; + + if (!nombre || !descripcion || !origen) { + return res.status(400).json({ success: false, message: 'Faltan campos obligatorios (nombre, descripción, origen).' }); + } + + let videoPathUrl = ''; + let videoObservacion = ''; + + if (origen === 'Local') { + if (!req.files || !req.files.archivo) { + return res.status(400).json({ success: false, message: 'No se ha subido ningún archivo de video.' }); + } + + const videoFile = req.files.archivo; + const fileExtension = path.extname(videoFile.name); + const newFileName = `${uuidv4()}${fileExtension}`; + const uploadPath = path.join(__dirname, '..', 'public', 'videos', newFileName); + + await videoFile.mv(uploadPath); + videoPathUrl = `/videos/${newFileName}`; // Ruta pública para acceder al video + videoObservacion = `Archivo local original: ${videoFile.name}`; + } else { + if (!urlExterna) { + return res.status(400).json({ success: false, message: 'La URL del video es obligatoria para orígenes externos.' }); + } + videoPathUrl = urlExterna; + videoObservacion = `Video externo de ${origen}`; + } + + req.getConnection((err, conn) => { + if (err) return res.status(500).json({ success: false, message: 'Error de conexión con la base de datos.' }); + + const nuevoVideo = { video_nombre: nombre, video_descripcion: descripcion, video_path_url: videoPathUrl, video_estado: 'ACTIVO', video_reg: reg_DB(), video_observacion: videoObservacion, video_origen: origen }; + conn.query('INSERT INTO videos SET ?', [nuevoVideo], (err, result) => { + if (err) return res.status(500).json({ success: false, message: 'Error al registrar el video en la base de datos.' }); + res.status(201).json({ success: true, message: 'Video subido y registrado exitosamente.', videoId: result.insertId }); + }); + }); + } catch (error) { + console.error("Error al subir el video:", error); + res.status(500).json({ success: false, message: 'Error interno del servidor al procesar la subida.' }); + } + }; + + module.exports = controlador_videos; // Exporta el controlador para que pueda ser utilizado en las rutas \ No newline at end of file diff --git a/src/public/css/app_videos.css b/src/public/css/app_videos.css index 47ab63c..0a7b20b 100644 --- a/src/public/css/app_videos.css +++ b/src/public/css/app_videos.css @@ -1,160 +1,185 @@ body { - font-family: Arial, sans-serif; - margin: 0; - padding: 0; - background-color: #121212; - color: #e0e0e0; - } - .banner { - display: flex; - align-items: center; - justify-content: space-between; - background-color: #1f1f1f; - color: #e0e0e0; - padding: 10px 20px; - position: fixed; - width: 96%; - top: 0; - z-index: 1000; - } - .banner .logo { - font-size: 24px; - font-weight: bold; - } - .banner .logo img { - height: 40px; - } - .banner .search-bar { - flex-grow: 1; - display: flex; - align-items: center; - margin: 0 20px; - } - .banner input[type="text"] { - width: 100%; - padding: 5px; - border: none; - border-radius: 3px; - margin-right: 10px; - background-color: #333; - color: #e0e0e0; - } - .banner .search-bar button { - background: url('https://cdn.jsdelivr.net/npm/uix@1.1.0/dist/icons/search.svg') no-repeat center; - background-size: 20px; - border: none; - width: 30px; - height: 30px; - cursor: pointer; - } - .banner .menu { - position: relative; - } - .banner .menu button { - background: url('https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR5nhCKmVjqZVfc19KXRTIXpeT6mweVBNeAmw&s') no-repeat center; - background-size: 30px; - border: none; - width: 40px; - height: 40px; - cursor: pointer; - color: #e0e0e0; - } - .banner .menu ul { - display: none; - position: absolute; - top: 35px; - right: 0; - background: #1f1f1f; - border: 1px solid #333; - border-radius: 5px; - list-style: none; - padding: 0; - margin: 0; - z-index: 1000; - } - .banner .menu ul li { - padding: 10px; - border-bottom: 1px solid #333; - color: #e0e0e0; - cursor: pointer; - } - .banner .menu ul li:last-child { - border-bottom: none; - } - .banner .menu ul li:hover { - background: #333; - } - .video-list { - padding: 80px 20px 20px; - } - .video-carousel { - position: relative; - } - .slick-slide { - display: flex; - justify-content: center; - } - .video-item { - width: 150px; - margin: 10px; - background: #2c2c2c; - border: 1px solid #444; - border-radius: 5px; - overflow: hidden; - box-shadow: 0 2px 5px rgba(0,0,0,0.5); - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - text-align: center; - } - .video-item img { - width: 100%; - height: auto; - } - .video-item .info { - padding: 10px; - background: #1f1f1f; - } - .player { - display: flex; - justify-content: center; - margin-top: 20px; - } - .player iframe, - .player video { - width: 80%; - max-width: 800px; - border: 2px solid #444; - border-radius: 5px; - } - .slick-prev, - .slick-next { - width: 40px; - height: 40px; - background: #333; - color: #e0e0e0; - border: none; - border-radius: 50%; - line-height: 40px; - text-align: center; - font-size: 20px; - cursor: pointer; - z-index: 1000; - } - .slick-prev { - left: 10px; - } - .slick-next { - right: 10px; - } - @media (max-width: 768px) { - .video-item { - width: 200px; - } - } - @media (max-width: 480px) { - .video-item { - width: 150px; - } - } \ No newline at end of file + font-family: Arial, sans-serif; + margin: 0; + padding: 0; + background-color: #121212; + color: #e0e0e0; +} + +.banner { + display: flex; + align-items: center; + justify-content: space-between; + background-color: #1f1f1f; + color: #e0e0e0; + padding: 10px 20px; + position: fixed; + width: 96%; + top: 0; + z-index: 1000; +} + +.banner .logo { + font-size: 24px; + font-weight: bold; +} + +.banner .logo img { + height: 40px; +} + +.banner .search-bar { + flex-grow: 1; + display: flex; + align-items: center; + margin: 0 20px; +} + +.banner input[type="text"] { + width: 100%; + padding: 5px; + border: none; + border-radius: 3px; + margin-right: 10px; + background-color: #333; + color: #e0e0e0; +} + +.banner .search-bar button { + background: url('https://cdn.jsdelivr.net/npm/uix@1.1.0/dist/icons/search.svg') no-repeat center; + background-size: 20px; + border: none; + width: 30px; + height: 30px; + cursor: pointer; +} + +.banner .menu { + position: relative; +} + +.banner .menu button { + background: url('https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcR5nhCKmVjqZVfc19KXRTIXpeT6mweVBNeAmw&s') no-repeat center; + background-size: 30px; + border: none; + width: 40px; + height: 40px; + cursor: pointer; + color: #e0e0e0; +} + +.banner .menu ul { + display: none; + position: absolute; + top: 35px; + right: 0; + background: #1f1f1f; + border: 1px solid #333; + border-radius: 5px; + list-style: none; + padding: 0; + margin: 0; + z-index: 1000; +} + +.banner .menu ul li { + padding: 10px; + border-bottom: 1px solid #333; + color: #e0e0e0; + cursor: pointer; +} + +.banner .menu ul li:last-child { + border-bottom: none; +} + +.banner .menu ul li:hover { + background: #333; +} + +.video-list { + padding: 80px 20px 20px; +} + +.video-carousel { + position: relative; +} + +.slick-slide { + display: flex; + justify-content: center; +} + +.video-item { + width: 150px; + margin: 10px; + background: #2c2c2c; + border: 1px solid #444; + border-radius: 5px; + overflow: hidden; + box-shadow: 0 2px 5px rgba(0, 0, 0, 0.5); + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; +} + +.video-item img { + width: 100%; + height: auto; +} + +.video-item .info { + padding: 10px; + background: #1f1f1f; +} + +.player { + display: flex; + justify-content: center; + margin-top: 20px; +} + +.player iframe, +.player video { + width: 80%; + max-width: 800px; + border: 2px solid #444; + border-radius: 5px; +} + +.slick-prev, +.slick-next { + width: 40px; + height: 40px; + background: #333; + color: #e0e0e0; + border: none; + border-radius: 50%; + line-height: 40px; + text-align: center; + font-size: 20px; + cursor: pointer; + z-index: 1000; +} + +.slick-prev { + left: 10px; +} + +.slick-next { + right: 10px; +} + +@media (max-width: 768px) { + .video-item { + width: 200px; + } +} + +@media (max-width: 480px) { + .video-item { + width: 150px; + } +} \ No newline at end of file diff --git a/src/public/js/app_videos_upload.js b/src/public/js/app_videos_upload.js index 49347ea..3f632cc 100644 --- a/src/public/js/app_videos_upload.js +++ b/src/public/js/app_videos_upload.js @@ -6,6 +6,7 @@ document.getElementById('origen').addEventListener('change', function () { const fileInput = document.getElementById('videoUpload'); const previewImg = document.getElementById('previewImg'); + if (origen === 'Local') { fileGroup.style.display = 'block'; urlGroup.style.display = 'none'; @@ -101,10 +102,11 @@ document.getElementById('uploadForm').addEventListener('submit', function (event url: urlOrFile, miniatura: origen === 'Local' ? document.getElementById('previewImg').src : document.getElementById('previewUrl').src, tipo: document.getElementById('tipo').value, - tamano: document.getElementById('tamano').value, + //tamano: document.getElementById('tamano').value, origen: origen, }; console.log('Video subido:', videoData); // Aquí puedes agregar código para procesar la subida y guardado de los datos. -}); \ No newline at end of file +}); + diff --git a/src/public/videos/98b17158-0fe4-4833-b801-e2e42e33823a.mp4 b/src/public/videos/98b17158-0fe4-4833-b801-e2e42e33823a.mp4 new file mode 100644 index 0000000..f2842a3 Binary files /dev/null and b/src/public/videos/98b17158-0fe4-4833-b801-e2e42e33823a.mp4 differ diff --git a/src/public/videos/fef1bbca-8802-4bcd-bcc7-070fc4a2e9e3.mp4 b/src/public/videos/fef1bbca-8802-4bcd-bcc7-070fc4a2e9e3.mp4 new file mode 100644 index 0000000..7945fc6 Binary files /dev/null and b/src/public/videos/fef1bbca-8802-4bcd-bcc7-070fc4a2e9e3.mp4 differ diff --git a/src/rutas/rt_apps.js b/src/rutas/rt_apps.js index 27fa645..f707c60 100644 --- a/src/rutas/rt_apps.js +++ b/src/rutas/rt_apps.js @@ -2,15 +2,26 @@ const express = require('express'); const rutas = express.Router(); const controlador_init = require('../controladores/controlador_Apps'); +const controlador_videos = require('../controladores/controlador_videos'); // Controlador para videos + rutas.get('/app_restaurant', controlador_init.app_restaurant);//login testing css / dev //rutas.get('/usuarios', controlador_init.user);// rutas.get('/dash_board', controlador_init.dashboard);// rutas.get('/users', controlador_init.user);//devuelve usuaios con el el ROL meseros rutas.get('/speedtest', controlador_init.speedtest);//testing velocimetro server -rutas.get('/videos', controlador_init.videos);//videos sigma server -rutas.get('/video_upload', controlador_init.upload);//videos sigma server + /*** CONFIGURACION DE UN PAGINA QUE CONFIGURE EL ARCHIVO config.js ***/ rutas.get('/configuracion', controlador_init.config);//llama a un view de configuracion del archivo config.js + + +rutas.get('/video', controlador_videos.video_v1);//videos sigma server +rutas.get('/video_upload', controlador_videos.upload_v1);//(GET) Muestra el formulario de subida V1 (antiguo) +rutas.post('/video_upload', controlador_videos.uploadVideoV1); //(POST) Procesa la subida del formulario V1 (antiguo) + +rutas.get('/videos', controlador_videos.videos_v2);//videos sigma server +rutas.get('/videos_upload', controlador_videos.upload_v2);//videos sigma server (version nueva) +rutas.post('/videos_upload', controlador_videos.uploadVideo); // Nueva ruta para manejar la subida + module.exports = rutas; \ No newline at end of file diff --git a/src/views/video_upload.ejs b/src/views/video_upload_v1.ejs similarity index 100% rename from src/views/video_upload.ejs rename to src/views/video_upload_v1.ejs diff --git a/src/views/video_v1.ejs b/src/views/video_v1.ejs new file mode 100644 index 0000000..ad2d636 --- /dev/null +++ b/src/views/video_v1.ejs @@ -0,0 +1,720 @@ + + + + + + + SIGMA - Reproductor de Videos + + + + + + + + + + + + +
+
+
+
+ + + + +
+

Cargando video...

+
+
+ +
+

Video Principal SIGMA

+

Selecciona un video de la lista para reproducir

+
+
+ +
+

🎬 Lista de Videos

+ +
+
+
+ + + + + + + \ No newline at end of file diff --git a/src/views/videos.ejs b/src/views/videos.ejs deleted file mode 100644 index e7cfe3c..0000000 --- a/src/views/videos.ejs +++ /dev/null @@ -1,152 +0,0 @@ - - - - - - - Lista de Videos - - - - - - - - - - - -
- -
- -
- - - -
- - - - - - - - \ No newline at end of file diff --git a/src/views/videos_upload.ejs b/src/views/videos_upload.ejs new file mode 100644 index 0000000..141b984 --- /dev/null +++ b/src/views/videos_upload.ejs @@ -0,0 +1,349 @@ + + + + + + + SIGMA - Subir Video + + + + + + + +
+
+

+ + Subir Contenido Multimedia +

+
+
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+ +
+ +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/src/views/videos_upload_v2.ejs b/src/views/videos_upload_v2.ejs new file mode 100644 index 0000000..280ca00 --- /dev/null +++ b/src/views/videos_upload_v2.ejs @@ -0,0 +1,349 @@ + + + + + + + SIGMA - Subir Video + + + + + + + +
+
+

+ + Subir Contenido Multimedia +

+
+
+ + +
+
+ + +
+
+ + +
+ +
+ + +
+ +
+ +
+
+
+
+
+ + + + + \ No newline at end of file diff --git a/src/views/videos_v2.ejs b/src/views/videos_v2.ejs new file mode 100644 index 0000000..95f707f --- /dev/null +++ b/src/views/videos_v2.ejs @@ -0,0 +1,253 @@ + + + + + + + SIGMA - Galería de Videos (V2) + + + + + + + +
+

Galería de Videos (V2 - Base de Datos)

+ <% if (error) { %> +

<%= error %>

+ <% } else if (!videos || videos.length === 0) { %> +

No hay videos disponibles en la base de datos. ¡Sube uno ahora!

+ <% } else { %> + + <% } %> +
+ + + + + + + \ No newline at end of file