const axios = require('axios'); const Media = require('../models/Media'); // 1. GET TRENDING (Lazy Sync: Fetch TMDB -> Save DB -> Return) exports.getTrending = async (req, res) => { try { // Fetch from TMDB const response = await axios.get(`https://api.themoviedb.org/3/trending/all/day`, { params: { api_key: process.env.TMDB_KEY, region: 'IN' } }); const trendingItems = []; // Process results for (const item of response.data.results) { // Skip incomplete data or people if (item.media_type === 'person') continue; const releaseDate = item.release_date || item.first_air_date; const tmdbId = item.id.toString(); // Prepare object for DB const mediaData = { tmdbId: tmdbId, title: item.title || item.name, type: item.media_type, posterPath: item.poster_path, backdropPath: item.backdrop_path, releaseDate: releaseDate ? new Date(releaseDate) : null, overview: item.overview, brutaleStats: {popularity : item.popularity, avgRating: item.vote_average, voteCount: item.vote_count}, }; // Upsert into DB (Update if exists, Insert if new) const updatedMedia = await Media.findOneAndUpdate( { tmdbId: tmdbId }, mediaData, { upsert: true, new: true, setDefaultsOnInsert: true } ); trendingItems.push(updatedMedia); } res.json(trendingItems); } catch (error) { console.error("Trending Error:", error.message); res.status(500).json({ error: 'Failed to fetch trending content' }); } }; exports.getPopular = async (req, res) => { try { const page = req.query.page || 1; // Fetch from TMDB const response = await axios.get(`https://api.themoviedb.org/3/movie/popular`, { params: { api_key: process.env.TMDB_KEY, page, region: "IN" } }); const popularItems = []; for (const item of response.data.results) { const tmdbId = item.id.toString(); const mediaData = { tmdbId: tmdbId, title: item.title, type: 'movie', posterPath: item.poster_path, backdropPath: item.backdrop_path, releaseDate: item.release_date ? new Date(item.release_date) : null, overview: item.overview, brutaleStats: { popularity: item.popularity, avgRating: item.vote_average?.toFixed(1) || "0.0", voteCount: item.vote_count } }; // Upsert into DB (Insert if new, update if existing) const updatedMedia = await Media.findOneAndUpdate( { tmdbId: tmdbId }, mediaData, { upsert: true, new: true, setDefaultsOnInsert: true } ); popularItems.push(updatedMedia); } res.json(popularItems); } catch (error) { console.error("Popular Error:", error.message); res.status(500).json({ error: "Failed to fetch popular movies" }); } }; // 2. GET DETAILS exports.getMediaDetails = async (req, res) => { try { const { id } = req.params; // This is the TMDB ID passed from URL // Try finding in DB first let media = await Media.findOne({ tmdbId: id }); // If not in DB, fetch from TMDB and save if (!media) { // We need to know if it's a movie or tv show. // For this simplified version, we might need to try both or rely on the query param. // BUT, usually the user clicks from the homepage where we already saved it. // Let's try fetching as movie first, then TV as fallback. try { const tmdbRes = await axios.get(`https://api.themoviedb.org/3/movie/${id}`, { params: { api_key: process.env.TMDB_KEY } }); const item = tmdbRes.data; media = await Media.create({ tmdbId: item.id.toString(), title: item.title, type: 'movie', posterPath: item.poster_path, backdropPath: item.backdrop_path, releaseDate: item.release_date, overview: item.overview }); } catch (err) { // Try TV const tmdbResTv = await axios.get(`https://api.themoviedb.org/3/tv/${id}`, { params: { api_key: process.env.TMDB_KEY } }); const item = tmdbResTv.data; media = await Media.create({ tmdbId: item.id.toString(), title: item.name, type: 'tv', posterPath: item.poster_path, backdropPath: item.backdrop_path, releaseDate: item.first_air_date, overview: item.overview }); } } if (!media) return res.status(404).json({ error: 'Media not found' }); res.json(media); } catch (error) { console.error("Details Error:", error.message); res.status(404).json({ error: 'Media not found on TMDB or DB' }); } }; // 3. SEARCH (Hybrid) exports.searchMedia = async (req, res) => { const query = req.query.q; if (!query) return res.json([]); try { // Search DB (using text index created in Schema) // Note: Ensure you created the index in MongoDB Atlas or via Schema: MediaSchema.index({ title: 'text' }); let results = await Media.find( { $text: { $search: query } }, { score: { $meta: "textScore" } } ).sort({ score: { $meta: "textScore" } }).limit(10); // If few results, fetch TMDB if (results.length < 5) { const tmdbRes = await axios.get(`https://api.themoviedb.org/3/search/multi`, { params: { api_key: process.env.TMDB_KEY, query: query } }); const tmdbItems = tmdbRes.data.results .filter(item => (item.media_type === 'movie' || item.media_type === 'tv') && item.poster_path) .map(item => ({ tmdbId: item.id.toString(), title: item.title || item.name, posterPath: item.poster_path, type: item.media_type, releaseDate: item.release_date || item.first_air_date, // Temporary object structure for frontend brutaleStats: { avgRating: 0 } })); // Merge results (prevent duplicates) const existingIds = new Set(results.map(r => r.tmdbId)); const newItems = tmdbItems.filter(i => !existingIds.has(i.tmdbId)); results = [...results, ...newItems]; } res.json(results); } catch (error) { res.status(500).json({ error: 'Search failed' }); } };