Update package-lock.json and package.json to reflect openai version change from 4.80.1 to 4.82.0

This commit is contained in:
2025-11-11 03:24:23 -05:00
parent 25e2baef86
commit 01491626ee
4 changed files with 153 additions and 32 deletions

112
README.md
View File

@@ -0,0 +1,112 @@
# Audio Control - Backend
Este es el proyecto de backend para la aplicación **SoundWave**. Es una API RESTful construida con Node.js y Express, diseñada para gestionar la autenticación de usuarios, controlar un reproductor de audio y administrar una lista de reproducción de videos de YouTube.
## Tabla de Contenidos
- [Acerca del Proyecto](#acerca-del-proyecto)
- [Estructura de la API](#estructura-de-la-api)
- [Tecnologías](#tecnologías)
- [Instalación y Uso](#instalación-y-uso)
- [Variables de Entorno](#variables-de-entorno)
- [Estructura de la Base de Datos](#estructura-de-la-base-de-datos)
## Acerca del Proyecto
Este backend proporciona los servicios necesarios para que el frontend `audio-player` funcione correctamente.
- **API RESTful**: Endpoints claros y definidos para la gestión de recursos.
- **Autenticación Segura**: Maneja la autenticación de usuarios a través de Google OAuth 2.0 y genera tokens JWT para sesiones seguras.
- **Gestión de Base de Datos**: Se conecta a una base de datos MySQL para persistir datos de usuarios y listas de reproducción.
- **Panel de Control Integrado**: Sirve una interfaz web simple con EJS y Materialize CSS para el control directo del reproductor.
- **Manejo de Errores Centralizado**: Utiliza un middleware de Express para gestionar todos los errores de forma consistente.
## Estructura de la API
A continuación se describen los endpoints principales:
### Autenticación
- `POST /api/auth/google`: Autentica a un usuario con un token de Google. Crea el usuario si no existe y devuelve un token JWT de la aplicación.
### Playlist de YouTube
- `GET /api/youtube-playlist`: Devuelve la lista de reproducción de videos de YouTube.
- `POST /api/youtube-video`: Añade un nuevo video a la lista de reproducción.
### Control Remoto
- `GET /cmd?consulta=<comando>`: Endpoint para enviar comandos a un reproductor (ej. `play_video`, `pausa_video`).
## Tecnologías
- **Node.js**: Entorno de ejecución de JavaScript.
- **Express.js**: Framework web para Node.js.
- **MySQL**: Sistema de gestión de bases de datos.
- **jsonwebtoken**: Para la creación y verificación de tokens JWT.
- **google-auth-library**: Para verificar los tokens de ID de Google.
- **dotenv**: Para la gestión de variables de entorno.
- **EJS**: Motor de plantillas para servir el panel de control.
## Instalación y Uso
1. **Clona el repositorio:**
```bash
git clone <URL_DEL_REPOSITORIO>
cd audio_control
```
2. **Instala las dependencias:**
```bash
npm install
```
3. **Configura las variables de entorno:**
Crea un archivo `.env` en la raíz del proyecto (`src/.env`). Consulta la sección Variables de Entorno.
4. **Inicia el servidor:**
```bash
npm start
```
El servidor se iniciará en el puerto 2000 (o el que se especifique).
## Variables de Entorno
Crea un archivo `.env` en el directorio `src/` con las siguientes variables. **Es crucial para la seguridad y el funcionamiento de la aplicación.**
```
# Secret para firmar los tokens JWT (usa un valor largo y aleatorio)
JWT_SECRET=tu_super_secreto_para_jwt
# Credenciales de Google Cloud para OAuth 2.0
GOOGLE_CLIENT_ID=tu_client_id_de_google.apps.googleusercontent.com
```
## Estructura de la Base de Datos
El proyecto requiere una base de datos MySQL con al menos las siguientes tablas:
**Tabla `users`**:
```sql
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
google_id VARCHAR(255) UNIQUE,
email VARCHAR(255) NOT NULL UNIQUE,
name VARCHAR(255),
picture_url VARCHAR(255),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```
**Tabla `rep_youtube`**:
```sql
CREATE TABLE rep_youtube (
id INT AUTO_INCREMENT PRIMARY KEY,
video_id VARCHAR(50) NOT NULL,
title VARCHAR(255) NOT NULL,
channel VARCHAR(255),
thumbnail VARCHAR(255),
duration VARCHAR(20),
added_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```

View File

@@ -66,6 +66,22 @@ app.get('/cmd', (req, res) => {
//archivos staticos //archivos staticos
app.use(express.static(path.join(__dirname, 'public'))); app.use(express.static(path.join(__dirname, 'public')));
// --- MANEJO DE ERRORES ---
// Middleware para capturar rutas no encontradas (404)
app.use((req, res, next) => {
res.status(404).json({ message: 'Recurso no encontrado.' });
});
// Middleware de manejo de errores centralizado
// Se activa cuando se llama a next(error) en cualquier parte de la aplicación.
app.use((err, req, res, next) => {
console.error('[ERROR STACK]:', err.stack); // Loguear el error completo para depuración
const status = err.status || 500;
const message = err.message || 'Error interno del servidor.';
res.status(status).json({ message });
});
//inicia servidor //inicia servidor
app.listen(app.get('port'),() =>{ app.listen(app.get('port'),() =>{
console.log('Servidor activo App SIGMA Puerto: '+puertoApp); console.log('Servidor activo App SIGMA Puerto: '+puertoApp);

View File

@@ -1,17 +1,14 @@
const controlador = {}; const controlador = {};
controlador.panel = (req, res) => {
controlador.panel = (req, res, next) => {
res.render('panel'); res.render('panel');
}; };
controlador.clientes = (req, res, next) => {
controlador.clientes = (req, res) => {
req.getConnection((err, conn) => { req.getConnection((err, conn) => {
if (err) return next(err);
conn.query('SELECT * FROM rep_youtube order by id DESC LIMIT 50', (err, rows) => {//se obtiene error o consulta filas(rows) conn.query('SELECT * FROM rep_youtube order by id DESC LIMIT 50', (err, rows) => {//se obtiene error o consulta filas(rows)
if(err){ if (err) return next(err);
res.json(err);
//next(err);
}
//console.log(rows);
res.render('panel',{ res.render('panel',{
data:rows data:rows
}); });
@@ -19,37 +16,35 @@ controlador.clientes = (req, res) => {
}); });
}; };
controlador.getYouTubePlaylist = (req, res) => { controlador.getYouTubePlaylist = (req, res, next) => {
req.getConnection((err, conn) => { req.getConnection((err, conn) => {
if (err) { if (err) return next(err);
console.error("Error de conexión a la BD:", err);
return res.status(500).json({ message: "Error de conexión a la base de datos" });
}
// Asumiendo que la tabla rep_youtube tiene al menos 'video_id' y 'title' // Asumiendo que la tabla rep_youtube tiene al menos 'video_id' y 'title'
conn.query('SELECT id, video_id, title FROM rep_youtube ORDER BY id DESC LIMIT 50', (err, rows) => { conn.query('SELECT id, video_id, title FROM rep_youtube ORDER BY id DESC LIMIT 50', (err, rows) => {
if (err) { if (err) return next(err);
return res.status(500).json({ error: "Error al obtener la playlist de YouTube" });
}
res.json({ playlist: rows }); res.json({ playlist: rows });
}); });
}); });
}; };
controlador.addYouTubeVideo = (req, res) => { controlador.addYouTubeVideo = (req, res, next) => {
// Extraemos los datos del cuerpo de la petición // Extraemos los datos del cuerpo de la petición
const { video_id, title, channel, thumbnail, duration } = req.body; const { video_id, title, channel, thumbnail, duration } = req.body;
if (!video_id || !title) { if (!video_id || !title) {
return res.status(400).json({ message: "Los campos 'video_id' y 'title' son obligatorios." }); const error = new Error("Los campos 'video_id' y 'title' son obligatorios.");
error.status = 400;
return next(error);
} }
const newVideo = { video_id, title, channel, thumbnail, duration }; const newVideo = { video_id, title, channel, thumbnail, duration };
req.getConnection((err, conn) => { req.getConnection((err, conn) => {
if (err) return res.status(500).json({ message: "Error de conexión a la base de datos" }); if (err) return next(err);
conn.query('INSERT INTO rep_youtube SET ?', [newVideo], (err, result) => { conn.query('INSERT INTO rep_youtube SET ?', [newVideo], (err, result) => {
if (err) return res.status(500).json({ message: "Error al guardar el video", error: err }); if (err) return next(err);
res.status(201).json({ message: "Video añadido con éxito", id: result.insertId }); res.status(201).json({ message: "Video añadido con éxito", id: result.insertId });
}); });
}); });

View File

@@ -11,17 +11,18 @@ function generateTokenAndRespond(user, res) {
} }
// --- NUEVA RUTA DE AUTENTICACIÓN CON GOOGLE --- // --- NUEVA RUTA DE AUTENTICACIÓN CON GOOGLE ---
controlador_auth.authenticateWithGoogle = (req, res) => { controlador_auth.authenticateWithGoogle = (req, res, next) => { // Añadido 'next'
const { token } = req.body; const { token } = req.body;
if (!token) { if (!token) {
return res.status(400).json({ message: 'No se proporcionó el token de Google.' }); const error = new Error('No se proporcionó el token de Google.');
error.status = 400;
return next(error);
} }
req.getConnection(async (err, conn) => { req.getConnection(async (err, conn) => {
if (err) { if (err) {
console.error("Error de conexión a la BD:", err); return next(err); // Pasa el error al middleware central
return res.status(500).json({ message: "Error de conexión a la base de datos" });
} }
try { try {
@@ -35,8 +36,7 @@ controlador_auth.authenticateWithGoogle = (req, res) => {
// 2. Buscar usuario por email // 2. Buscar usuario por email
conn.query('SELECT * FROM users WHERE email = ?', [email], (err, rows) => { conn.query('SELECT * FROM users WHERE email = ?', [email], (err, rows) => {
if (err) { if (err) {
console.error("Error en consulta SQL:", err); return next(err); // Pasa el error al middleware central
return res.status(500).json({ message: "Error en la base de datos" });
} }
const user = rows[0]; const user = rows[0];
@@ -45,10 +45,7 @@ controlador_auth.authenticateWithGoogle = (req, res) => {
// Crear nuevo usuario // Crear nuevo usuario
const newUser = { google_id: googleId, email, name, picture_url: picture }; const newUser = { google_id: googleId, email, name, picture_url: picture };
conn.query('INSERT INTO users SET ?', newUser, (err, result) => { conn.query('INSERT INTO users SET ?', newUser, (err, result) => {
if (err) { if (err) return next(err); // Pasa el error al middleware central
console.error("Error al crear usuario:", err);
return res.status(500).json({ message: "Error al registrar usuario" });
}
const createdUser = { id: result.insertId, ...newUser }; const createdUser = { id: result.insertId, ...newUser };
generateTokenAndRespond(createdUser, res); generateTokenAndRespond(createdUser, res);
}); });
@@ -58,8 +55,9 @@ controlador_auth.authenticateWithGoogle = (req, res) => {
} }
}); });
} catch (error) { } catch (error) {
console.error('Error en autenticación con Google:', error.message); const authError = new Error('Token de Google inválido o expirado.');
return res.status(401).json({ message: 'Token de Google inválido o expirado.' }); authError.status = 401;
return next(authError); // Pasa el error al middleware central
} }
}); });
}; };