const express = require('express'); const router = express.Router(); const { authenticate } = require('../middleware/auth'); const { readLimiter, modifyLimiter } = require('../middleware/rateLimiter'); const { db } = require('../database/db'); const logger = require('../utils/logger'); /** * Record watch history */ router.post('/', modifyLimiter, authenticate, (req, res) => { const { channel_id, duration, profile_id } = req.body; const user_id = req.user.userId; if (!channel_id) { return res.status(400).json({ error: 'channel_id is required' }); } db.run( `INSERT INTO watch_history (user_id, profile_id, channel_id, duration) VALUES (?, ?, ?, ?)`, [user_id, profile_id || null, channel_id, duration || 0], function(err) { if (err) { logger.error('Error recording watch history:', err); return res.status(500).json({ error: 'Failed to record watch history' }); } res.json({ message: 'Watch history recorded', id: this.lastID }); } ); }); /** * Get user watch history */ router.get('/', readLimiter, authenticate, (req, res) => { const user_id = req.user.userId; const { limit = 50, offset = 0, profile_id } = req.query; let query = ` SELECT wh.id, wh.watched_at, wh.duration, c.id as channel_id, c.name as channel_name, c.logo, c.custom_logo, c.group_name, c.is_radio FROM watch_history wh INNER JOIN channels c ON wh.channel_id = c.id WHERE wh.user_id = ? `; const params = [user_id]; if (profile_id) { query += ' AND wh.profile_id = ?'; params.push(profile_id); } query += ' ORDER BY wh.watched_at DESC LIMIT ? OFFSET ?'; params.push(parseInt(limit), parseInt(offset)); db.all(query, params, (err, rows) => { if (err) { logger.error('Error fetching watch history:', err); return res.status(500).json({ error: 'Failed to fetch watch history' }); } res.json(rows); }); }); /** * Get most watched channels (recommendations) */ router.get('/top-channels', readLimiter, authenticate, (req, res) => { const user_id = req.user.userId; const { limit = 10, profile_id, days = 30 } = req.query; let query = ` SELECT c.id, c.name, c.logo, c.custom_logo, c.group_name, c.is_radio, c.url, COUNT(wh.id) as watch_count, SUM(wh.duration) as total_duration, MAX(wh.watched_at) as last_watched FROM watch_history wh INNER JOIN channels c ON wh.channel_id = c.id WHERE wh.user_id = ? AND wh.watched_at >= datetime('now', '-' || ? || ' days') `; const params = [user_id, days]; if (profile_id) { query += ' AND wh.profile_id = ?'; params.push(profile_id); } query += ` GROUP BY c.id ORDER BY watch_count DESC, total_duration DESC LIMIT ? `; params.push(parseInt(limit)); db.all(query, params, (err, rows) => { if (err) { logger.error('Error fetching top channels:', err); return res.status(500).json({ error: 'Failed to fetch top channels' }); } res.json(rows); }); }); /** * Get recommended channels based on viewing patterns */ router.get('/recommendations', readLimiter, authenticate, (req, res) => { const user_id = req.user.userId; const { limit = 10, profile_id } = req.query; // Get channels from same groups as user's most watched channels let query = ` WITH user_favorite_groups AS ( SELECT DISTINCT c.group_name, COUNT(wh.id) as watch_count FROM watch_history wh INNER JOIN channels c ON wh.channel_id = c.id WHERE wh.user_id = ? AND wh.watched_at >= datetime('now', '-30 days') AND c.group_name IS NOT NULL `; const params = [user_id]; if (profile_id) { query += ' AND wh.profile_id = ?'; params.push(profile_id); } query += ` GROUP BY c.group_name ORDER BY watch_count DESC LIMIT 5 ) SELECT DISTINCT c.id, c.name, c.logo, c.custom_logo, c.group_name, c.is_radio, c.url, c.health_status FROM channels c INNER JOIN user_favorite_groups ufg ON c.group_name = ufg.group_name WHERE c.id NOT IN ( SELECT channel_id FROM watch_history WHERE user_id = ? AND watched_at >= datetime('now', '-7 days') ) AND c.is_active = 1 AND c.health_status != 'dead' ORDER BY RANDOM() LIMIT ? `; params.push(user_id, parseInt(limit)); db.all(query, params, (err, rows) => { if (err) { logger.error('Error fetching recommendations:', err); return res.status(500).json({ error: 'Failed to fetch recommendations' }); } res.json(rows); }); }); /** * Clear watch history */ router.delete('/', modifyLimiter, authenticate, (req, res) => { const user_id = req.user.userId; const { profile_id, days } = req.query; let query = 'DELETE FROM watch_history WHERE user_id = ?'; const params = [user_id]; if (profile_id) { query += ' AND profile_id = ?'; params.push(profile_id); } if (days) { query += ' AND watched_at < datetime("now", "-" || ? || " days")'; params.push(days); } db.run(query, params, function(err) { if (err) { logger.error('Error clearing watch history:', err); return res.status(500).json({ error: 'Failed to clear watch history' }); } res.json({ message: 'Watch history cleared', deleted: this.changes }); }); }); module.exports = router;