diff --git a/LICENSE b/LICENSE index 4040e3b..a0a0753 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2025 Foxix + Copyright 2025 NeoMovies Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/package.json b/package.json index d8b4b09..b317f96 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,8 @@ "cors": "^2.8.5", "dotenv": "^16.3.1", "express": "^4.18.2", - "swagger-jsdoc": "^6.2.8" + "swagger-jsdoc": "^6.2.8", + "vercel": "^39.3.0" }, "devDependencies": { "nodemon": "^3.0.2" diff --git a/src/config/tmdb.js b/src/config/tmdb.js index 489e873..2ab3a12 100644 --- a/src/config/tmdb.js +++ b/src/config/tmdb.js @@ -171,6 +171,70 @@ class TMDBClient { const response = await this.makeRequest('GET', `/movie/${id}/external_ids`); return response.data; } + + async searchTVShows(query, page = 1) { + const pageNum = parseInt(page, 10) || 1; + console.log('Searching TV shows:', { query, page: pageNum }); + + const response = await this.makeRequest('GET', '/search/tv', { + query, + page: pageNum, + include_adult: false + }); + + const data = response.data; + data.results = data.results + .filter(show => show.poster_path && show.overview && show.vote_average > 0) + .map(show => ({ + ...show, + poster_path: this.getImageURL(show.poster_path, 'w500'), + backdrop_path: this.getImageURL(show.backdrop_path, 'original') + })); + + return data; + } + + async getTVShow(id) { + const response = await this.makeRequest('GET', `/tv/${id}`); + const show = response.data; + return { + ...show, + poster_path: this.getImageURL(show.poster_path, 'w500'), + backdrop_path: this.getImageURL(show.backdrop_path, 'original') + }; + } + + async getPopularTVShows(page = 1) { + const pageNum = parseInt(page, 10) || 1; + const response = await this.makeRequest('GET', '/tv/popular', { + page: pageNum + }); + + const data = response.data; + data.results = data.results.map(show => ({ + ...show, + poster_path: this.getImageURL(show.poster_path, 'w500'), + backdrop_path: this.getImageURL(show.backdrop_path, 'original') + })); + + return data; + } + + async getTopRatedTVShows(page = 1) { + const pageNum = parseInt(page, 10) || 1; + const response = await this.makeRequest('GET', '/tv/top_rated', { + page: pageNum + }); + + const data = response.data; + data.results = data.results.map(show => ({ + ...show, + poster_path: this.getImageURL(show.poster_path, 'w500'), + backdrop_path: this.getImageURL(show.backdrop_path, 'original') + })); + + return data; + } } module.exports = TMDBClient; diff --git a/src/routes/movies.js b/src/routes/movies.js index bdf8de1..e79aed1 100644 --- a/src/routes/movies.js +++ b/src/routes/movies.js @@ -452,4 +452,117 @@ router.get('/upcoming', async (req, res) => { } }); +// TV Shows Routes +router.get('/tv/search', async (req, res) => { + try { + const { query, page } = req.query; + const pageNum = parseInt(page, 10) || 1; + + if (!query) { + return res.status(400).json({ error: 'Query parameter is required' }); + } + + if (pageNum < 1) { + return res.status(400).json({ error: 'Page must be greater than 0' }); + } + + const response = await req.tmdb.searchTVShows(query, pageNum); + + if (!response || !response.data) { + throw new Error('Failed to fetch data from TMDB'); + } + + const { results, ...rest } = response.data; + + const formattedResults = results.map(show => ({ + ...show, + first_air_date: formatDate(show.first_air_date) + })); + + res.json({ + ...rest, + results: formattedResults + }); + } catch (error) { + console.error('Error searching TV shows:', error); + res.status(500).json({ error: error.message }); + } +}); + +router.get('/tv/:id', async (req, res) => { + try { + const { id } = req.params; + const show = await req.tmdb.getTVShow(id); + show.first_air_date = formatDate(show.first_air_date); + res.json(show); + } catch (error) { + console.error('Error fetching TV show:', error); + res.status(500).json({ error: error.message }); + } +}); + +router.get('/tv/popular', async (req, res) => { + try { + const { page } = req.query; + const pageNum = parseInt(page, 10) || 1; + + if (pageNum < 1) { + return res.status(400).json({ error: 'Page must be greater than 0' }); + } + + const response = await req.tmdb.getPopularTVShows(pageNum); + + if (!response || !response.data) { + throw new Error('Failed to fetch data from TMDB'); + } + + const { results, ...rest } = response.data; + + const formattedResults = results.map(show => ({ + ...show, + first_air_date: formatDate(show.first_air_date) + })); + + res.json({ + ...rest, + results: formattedResults + }); + } catch (error) { + console.error('Error fetching popular TV shows:', error); + res.status(500).json({ error: error.message }); + } +}); + +router.get('/tv/top-rated', async (req, res) => { + try { + const { page } = req.query; + const pageNum = parseInt(page, 10) || 1; + + if (pageNum < 1) { + return res.status(400).json({ error: 'Page must be greater than 0' }); + } + + const response = await req.tmdb.getTopRatedTVShows(pageNum); + + if (!response || !response.data) { + throw new Error('Failed to fetch data from TMDB'); + } + + const { results, ...rest } = response.data; + + const formattedResults = results.map(show => ({ + ...show, + first_air_date: formatDate(show.first_air_date) + })); + + res.json({ + ...rest, + results: formattedResults + }); + } catch (error) { + console.error('Error fetching top rated TV shows:', error); + res.status(500).json({ error: error.message }); + } +}); + module.exports = router;