IMPLEMENTACION DE LOS VIDEOS EN EL CATALOGO PUBLICO

This commit is contained in:
2026-06-13 08:52:18 -05:00
parent e4588b75db
commit 33331f9016
17 changed files with 441 additions and 298 deletions
+165
View File
@@ -23,6 +23,7 @@ const DATA_DIR = path.join(__dirname, 'data');
const FRONTEND_DIR = path.join(__dirname, 'frontend');
const IMG_DIR = path.join(__dirname, 'Imagenes');
const PEDIDOS_DIR = path.join(__dirname, 'pedidos');
const VIDEOS_DIR = path.join(__dirname, 'videos');
// ════════════════════════════════
// MIDDLEWARES
@@ -32,6 +33,7 @@ app.use(cookieParser(SECRET));
app.use(express.static(FRONTEND_DIR));
app.use('/Imagenes', express.static(IMG_DIR, { maxAge: '7d' }));
app.use('/pedidos', express.static(PEDIDOS_DIR));
app.use('/videos', express.static(VIDEOS_DIR));
// Evita el 404 de favicon.ico
app.get('/favicon.ico', (req, res) => res.status(204).end());
@@ -2162,6 +2164,169 @@ app.post('/api/pedidos/generar-pdf', async (req, res) => {
}
});
// ════════════════════════════════
// REDES SOCIALES — gestión de publicaciones embebidas
// ════════════════════════════════
const REDES_FILE = 'redes.json';
async function getRedes() {
try { return await readJson(REDES_FILE); }
catch { return []; }
}
function extraerPlataforma(url) {
if (/instagram\.com/i.test(url)) return 'instagram';
if (/facebook\.com/i.test(url)) return 'facebook';
return null;
}
// Público: solo activas
app.get('/api/redes', async (req, res) => {
const todas = await getRedes();
res.json(todas.filter(r => r.activo).sort((a, b) => a.orden - b.orden));
});
// Admin: todas
app.get('/api/redes/admin', requireAdmin, async (req, res) => {
const todas = await getRedes();
res.json(todas.sort((a, b) => a.orden - b.orden));
});
app.post('/api/redes', requireAdmin, async (req, res) => {
const { url } = req.body || {};
if (!url || !url.trim()) {
return res.status(400).json({ error: 'La URL es obligatoria' });
}
const plataforma = extraerPlataforma(url);
if (!plataforma) {
return res.status(400).json({ error: 'La URL debe ser de Instagram o Facebook' });
}
const todas = await getRedes();
const nueva = {
id: String(Date.now()),
url: url.trim(),
plataforma,
activo: true,
orden: todas.length
};
todas.push(nueva);
await writeJson(REDES_FILE, todas);
res.json(todas);
});
app.delete('/api/redes/:id', requireAdmin, async (req, res) => {
let todas = await getRedes();
todas = todas.filter(r => r.id !== req.params.id);
await writeJson(REDES_FILE, todas);
res.json(todas);
});
app.put('/api/redes/:id', requireAdmin, async (req, res) => {
const todas = await getRedes();
const idx = todas.findIndex(r => r.id === req.params.id);
if (idx === -1) return res.status(404).json({ error: 'No encontrada' });
const { activo } = req.body || {};
if (typeof activo === 'boolean') todas[idx].activo = activo;
await writeJson(REDES_FILE, todas);
res.json(todas);
});
// ════════════════════════════════
// VIDEOS — gestión de videos subidos
// ════════════════════════════════
const MAX_VIDEOS = 10;
const videoUpload = multer({
storage: multer.diskStorage({
destination: VIDEOS_DIR,
filename: (req, file, cb) => {
const ext = path.extname(file.originalname) || '.mp4';
cb(null, `video-${Date.now()}${ext}`);
}
}),
limits: { fileSize: 200 * 1024 * 1024 } // 200MB
});
app.get('/api/videos', async (req, res) => {
try {
await fs.mkdir(VIDEOS_DIR, { recursive: true });
const files = await fs.readdir(VIDEOS_DIR);
const videos = files
.filter(f => f.startsWith('video-'))
.sort()
.reverse()
.map(f => ({ filename: f, url: `/videos/${f}` }));
res.json(videos);
} catch (err) {
console.error('Error listing videos:', err);
res.status(500).json({ error: 'Error al listar videos' });
}
});
app.post('/api/videos', requireAdmin, videoUpload.single('video'), async (req, res) => {
try {
await fs.mkdir(VIDEOS_DIR, { recursive: true });
const files = await fs.readdir(VIDEOS_DIR);
const videoFiles = files.filter(f => f.startsWith('video-'));
if (videoFiles.length > MAX_VIDEOS) {
// Eliminar el que se subió justo ahora si excede
if (req.file) await fs.unlink(req.file.path).catch(() => {});
return res.status(400).json({ error: `Máximo ${MAX_VIDEOS} videos. Elimina uno antes de subir otro.` });
}
const videos = videoFiles.sort().reverse().map(f => ({ filename: f, url: `/videos/${f}` }));
res.json(videos);
} catch (err) {
console.error('Error uploading video:', err);
if (req.file) await fs.unlink(req.file.path).catch(() => {});
res.status(500).json({ error: 'Error al subir video' });
}
});
app.delete('/api/videos/:filename', requireAdmin, async (req, res) => {
const { filename } = req.params;
if (!filename.startsWith('video-')) {
return res.status(400).json({ error: 'Nombre de archivo inválido' });
}
try {
await fs.unlink(path.join(VIDEOS_DIR, filename));
res.json({ ok: true });
} catch (err) {
if (err.code === 'ENOENT') return res.status(404).json({ error: 'Video no encontrado' });
console.error('Error deleting video:', err);
res.status(500).json({ error: 'Error al eliminar video' });
}
});
// Proxy para embeds de redes sociales (evita bloqueo de terceros en móviles)
app.get('/api/redes/proxy', async (req, res) => {
const { url } = req.query;
if (!url) return res.status(400).json({ error: 'Falta url' });
let embedUrl;
if (url.includes('instagram.com/p/')) {
const match = url.match(/instagram\.com\/p\/([^/?]+)/);
if (!match) return res.status(400).json({ error: 'URL de Instagram inválida' });
embedUrl = `https://www.instagram.com/p/${match[1]}/embed`;
} else if (url.includes('facebook.com')) {
embedUrl = `https://www.facebook.com/plugins/post.php?href=${encodeURIComponent(url)}&show_text=true`;
} else {
return res.status(400).json({ error: 'Solo se admiten URLs de Instagram y Facebook' });
}
try {
const response = await fetch(embedUrl, {
headers: { 'User-Agent': 'Mozilla/5.0 (compatible; InfinityBot)' }
});
const html = await response.text();
res.set('Content-Type', 'text/html; charset=utf-8');
res.set('X-Frame-Options', '');
res.send(html);
} catch (err) {
console.error('Redes proxy error:', err);
res.status(502).send('Error al cargar el contenido');
}
});
// ════════════════════════════════
// START
// ════════════════════════════════