const express = require('express'); const router = express.Router(); const { db } = require('../database/db'); const { authenticate, requireAdmin } = require('../middleware/auth'); const { readLimiter } = require('../middleware/rateLimiter'); const { sanitizeString } = require('../utils/inputValidator'); const logger = require('../utils/logger'); /** * Global search endpoint * Searches across channels, radio stations, users, settings, etc. */ router.get('/', authenticate, readLimiter, async (req, res) => { try { const { q } = req.query; const isAdmin = req.user.role === 'admin'; if (!q || q.trim().length < 2) { return res.json({ channels: [], radio: [], users: [], settings: [], groups: [] }); } // Validate and sanitize search query const sanitized = sanitizeString(q.trim()); if (sanitized.length > 100) { return res.status(400).json({ error: 'Search query too long' }); } const searchTerm = `%${sanitized}%`; const results = { channels: [], radio: [], users: [], settings: [], groups: [] }; // Search TV channels (only from user's playlists) results.channels = await new Promise((resolve, reject) => { db.all( `SELECT DISTINCT c.id, c.name, c.url, COALESCE(c.custom_logo, c.logo) as logo, c.group_name, c.is_radio FROM channels c JOIN playlists p ON c.playlist_id = p.id WHERE p.user_id = ? AND c.is_radio = 0 AND c.is_active = 1 AND (c.name LIKE ? OR c.group_name LIKE ?) ORDER BY c.name LIMIT 20`, [req.user.userId, searchTerm, searchTerm], (err, rows) => { if (err) reject(err); else resolve(rows || []); } ); }); // Search Radio channels (only from user's playlists) results.radio = await new Promise((resolve, reject) => { db.all( `SELECT DISTINCT c.id, c.name, c.url, COALESCE(c.custom_logo, c.logo) as logo, c.group_name, c.is_radio FROM channels c JOIN playlists p ON c.playlist_id = p.id WHERE p.user_id = ? AND c.is_radio = 1 AND c.is_active = 1 AND (c.name LIKE ? OR c.group_name LIKE ?) ORDER BY c.name LIMIT 20`, [req.user.userId, searchTerm, searchTerm], (err, rows) => { if (err) reject(err); else resolve(rows || []); } ); }); // Search groups (only from user's playlists) results.groups = await new Promise((resolve, reject) => { db.all( `SELECT DISTINCT c.group_name as name, c.is_radio FROM channels c JOIN playlists p ON c.playlist_id = p.id WHERE p.user_id = ? AND c.is_active = 1 AND c.group_name LIKE ? ORDER BY c.group_name LIMIT 10`, [req.user.userId, searchTerm], (err, rows) => { if (err) reject(err); else resolve(rows || []); } ); }); // Search users (admin only) if (isAdmin) { results.users = await new Promise((resolve, reject) => { db.all( `SELECT id, username, email, role, created_at FROM users WHERE username LIKE ? OR email LIKE ? ORDER BY username LIMIT 10`, [searchTerm, searchTerm], (err, rows) => { if (err) reject(err); else resolve(rows || []); } ); }); } // Add settings/pages results (static) const settingsOptions = [ { id: 'settings', name: 'Settings', path: '/settings', icon: 'settings' }, { id: 'user-management', name: 'User Management', path: '/settings?tab=users', icon: 'people' }, { id: 'vpn-settings', name: 'VPN Settings', path: '/settings?tab=vpn', icon: 'vpn_lock' }, { id: '2fa', name: 'Two-Factor Authentication', path: '/settings?tab=2fa', icon: 'security' }, { id: 'live-tv', name: 'Live TV', path: '/live', icon: 'tv' }, { id: 'radio', name: 'Radio', path: '/radio', icon: 'radio' }, { id: 'movies', name: 'Movies', path: '/movies', icon: 'movie' }, { id: 'series', name: 'Series', path: '/series', icon: 'subscriptions' }, { id: 'favorites', name: 'Favorites', path: '/favorites', icon: 'favorite' }, ]; results.settings = settingsOptions.filter(option => option.name.toLowerCase().includes(q.toLowerCase()) ); res.json(results); } catch (error) { console.error('Search error:', error); res.status(500).json({ error: 'Search failed' }); } }); module.exports = router;