Brutale-api / src /controllers /media.controller.js
rohanshaw's picture
Upload 16 files
e557560 verified
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' });
}
};