import { api } from '../api.js'; import { imageCache } from '../services/imageCache.js'; /** * Detect if movie is newly released (within last 30 days or current year) */ function isNewRelease(video) { const currentYear = new Date().getFullYear(); // Check if released this year if (video.year === currentYear) return true; // Check quality badge for "Mới" or "New" indicators const quality = (video.quality || '').toLowerCase(); if (quality.includes('mới') || quality.includes('new')) return true; // Check if movie was recently added (within 7 days) if (video.modified?.time) { const modifiedDate = new Date(video.modified.time); const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000); if (modifiedDate > sevenDaysAgo) return true; } return false; } /** * Detect movie type based on episode count and quality */ function getMovieType(video) { const quality = (video.quality || '').toLowerCase(); const episodeCount = video.episodes?.length || 0; const category = (video.category || video.type || '').toLowerCase(); // Check for trailer if (quality.includes('trailer') || category.includes('trailer')) { return 'trailer'; } // Check for series (has episodes or is marked as series) if (episodeCount > 1 || category.includes('series') || category.includes('phim-bo') || quality.includes('tập') || quality.includes('ep')) { return 'series'; } // Check for animation if (category.includes('hoathinh') || category.includes('animation') || category.includes('anime')) { return 'animation'; } // Default to full movie return 'movie'; } /** * Get episode count text */ function getEpisodeText(video) { const quality = video.quality || ''; // Check if quality contains episode info like "Tập 12" or "12/24" const epMatch = quality.match(/(?:tập\s*)?(\d+)(?:\s*\/\s*(\d+))?/i); if (epMatch) { return quality; // Return as-is, it already contains episode info } const episodeCount = video.episodes?.length || 0; if (episodeCount > 1) { return `${episodeCount} Tập`; } return null; } /** * Create a video card element - PhimMoi Style * @param {Object} video - Video data * @param {function} onPlay - Callback when play is clicked * @param {function} onInfo - Callback when more info is clicked * @returns {HTMLElement} Video card element */ export function createVideoCard(video, onPlay, onInfo) { const card = document.createElement('div'); card.className = 'video-card'; card.dataset.videoId = video.id; // PERFORMANCE: Use backend image proxy for faster loading (WebP + Resized) // Use optimized sizes for mobile/desktop balance (quality vs speed) const isMobile = window.innerWidth < 768; const imageWidth = isMobile ? 180 : 200; const originalThumbnail = video.thumbnail || ''; const thumbnail = api.getProxyUrl(originalThumbnail, imageWidth); const year = video.year || new Date().getFullYear(); // Smart badge detection const isNew = isNewRelease(video); const movieType = getMovieType(video); const episodeText = getEpisodeText(video); // Quality badge (HD, FHD, 4K, CAM, etc.) let qualityBadge = video.quality || 'HD'; // Clean up quality text - remove episode info if it exists qualityBadge = qualityBadge.replace(/(?:tập\s*)?\d+(?:\s*\/\s*\d+)?/gi, '').trim() || 'HD'; if (qualityBadge.length > 6) qualityBadge = 'HD'; // Fallback if too long // Numeric rating badge const rating = parseFloat(video.rating || 0); const isFresh = rating >= 7.0; const ratingPercent = Math.round(rating * 10); let numericRatingHTML = ''; if (rating > 0) { numericRatingHTML = `
`; } // Build rating badge HTML (Rotten Tomatoes style) let tomatoBadgeHTML = ''; if (rating > 0) { const tomatoIcon = isFresh ? '🍅' : '🥀'; tomatoBadgeHTML = `