mirror of
https://gitlab.com/foxixus/neomovies-api.git
synced 2025-10-28 09:58:50 +05:00
Add categories
This commit is contained in:
@@ -28,25 +28,37 @@ class TMDBClient {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async makeRequest(method, endpoint, params = {}) {
|
async makeRequest(method, endpoint, options = {}) {
|
||||||
try {
|
try {
|
||||||
const requestParams = {
|
// Здесь была ошибка - если передать {params: {...}} в options,
|
||||||
...params,
|
// то мы создаем вложенный объект params.params
|
||||||
language: 'ru-RU',
|
const clientOptions = {
|
||||||
region: 'RU'
|
method,
|
||||||
|
url: endpoint,
|
||||||
|
...options
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Если не передали params, добавляем базовые
|
||||||
|
if (!clientOptions.params) {
|
||||||
|
clientOptions.params = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Добавляем базовые параметры, если их еще нет
|
||||||
|
if (!clientOptions.params.language) {
|
||||||
|
clientOptions.params.language = 'ru-RU';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!clientOptions.params.region) {
|
||||||
|
clientOptions.params.region = 'RU';
|
||||||
|
}
|
||||||
|
|
||||||
console.log('TMDB Request:', {
|
console.log('TMDB Request:', {
|
||||||
method,
|
method,
|
||||||
endpoint,
|
endpoint,
|
||||||
params: requestParams
|
options: clientOptions
|
||||||
});
|
});
|
||||||
|
|
||||||
const response = await this.client({
|
const response = await this.client(clientOptions);
|
||||||
method,
|
|
||||||
url: endpoint,
|
|
||||||
params: requestParams
|
|
||||||
});
|
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -198,6 +210,60 @@ class TMDBClient {
|
|||||||
return response.data;
|
return response.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Получение жанров фильмов
|
||||||
|
async getMovieGenres() {
|
||||||
|
console.log('Getting movie genres');
|
||||||
|
try {
|
||||||
|
const response = await this.makeRequest('GET', '/genre/movie/list', {
|
||||||
|
language: 'ru'
|
||||||
|
});
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error getting movie genres:', error.message);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получение жанров сериалов
|
||||||
|
async getTVGenres() {
|
||||||
|
console.log('Getting TV genres');
|
||||||
|
try {
|
||||||
|
const response = await this.makeRequest('GET', '/genre/tv/list', {
|
||||||
|
language: 'ru'
|
||||||
|
});
|
||||||
|
return response.data;
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error getting TV genres:', error.message);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получение всех жанров (фильмы и сериалы)
|
||||||
|
async getAllGenres() {
|
||||||
|
console.log('Getting all genres (movies and TV)');
|
||||||
|
try {
|
||||||
|
const [movieGenres, tvGenres] = await Promise.all([
|
||||||
|
this.getMovieGenres(),
|
||||||
|
this.getTVGenres()
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Объединяем жанры, удаляя дубликаты по ID
|
||||||
|
const allGenres = [...movieGenres.genres];
|
||||||
|
|
||||||
|
// Добавляем жанры сериалов, которых нет в фильмах
|
||||||
|
tvGenres.genres.forEach(tvGenre => {
|
||||||
|
if (!allGenres.some(genre => genre.id === tvGenre.id)) {
|
||||||
|
allGenres.push(tvGenre);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return { genres: allGenres };
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error getting all genres:', error.message);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async getMoviesByGenre(genreId, page = 1) {
|
async getMoviesByGenre(genreId, page = 1) {
|
||||||
return this.makeRequest('GET', '/discover/movie', {
|
return this.makeRequest('GET', '/discover/movie', {
|
||||||
params: {
|
params: {
|
||||||
|
|||||||
@@ -225,10 +225,12 @@ app.get('/search/multi', async (req, res) => {
|
|||||||
const moviesRouter = require('./routes/movies');
|
const moviesRouter = require('./routes/movies');
|
||||||
const tvRouter = require('./routes/tv');
|
const tvRouter = require('./routes/tv');
|
||||||
const imagesRouter = require('./routes/images');
|
const imagesRouter = require('./routes/images');
|
||||||
|
const categoriesRouter = require('./routes/categories');
|
||||||
|
|
||||||
app.use('/movies', moviesRouter);
|
app.use('/movies', moviesRouter);
|
||||||
app.use('/tv', tvRouter);
|
app.use('/tv', tvRouter);
|
||||||
app.use('/images', imagesRouter);
|
app.use('/images', imagesRouter);
|
||||||
|
app.use('/categories', categoriesRouter);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @swagger
|
* @swagger
|
||||||
@@ -287,7 +289,11 @@ module.exports = app;
|
|||||||
|
|
||||||
// Start server only in development
|
// Start server only in development
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
if (process.env.NODE_ENV !== 'production') {
|
||||||
const port = process.env.PORT || 3000;
|
// Проверяем аргументы командной строки
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
// Используем порт из аргументов командной строки, переменной окружения или по умолчанию 3000
|
||||||
|
const port = args[0] || process.env.PORT || 3000;
|
||||||
|
|
||||||
app.listen(port, () => {
|
app.listen(port, () => {
|
||||||
console.log(`Server is running on port ${port}`);
|
console.log(`Server is running on port ${port}`);
|
||||||
console.log(`Documentation available at http://localhost:${port}/api-docs`);
|
console.log(`Documentation available at http://localhost:${port}/api-docs`);
|
||||||
|
|||||||
378
src/routes/categories.js
Normal file
378
src/routes/categories.js
Normal file
@@ -0,0 +1,378 @@
|
|||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
const { formatDate } = require('../utils/date');
|
||||||
|
|
||||||
|
// Middleware для логирования запросов
|
||||||
|
router.use((req, res, next) => {
|
||||||
|
console.log('Categories API Request:', {
|
||||||
|
method: req.method,
|
||||||
|
path: req.path,
|
||||||
|
query: req.query,
|
||||||
|
params: req.params
|
||||||
|
});
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /categories:
|
||||||
|
* get:
|
||||||
|
* summary: Получение списка категорий
|
||||||
|
* description: Возвращает список всех доступных категорий фильмов (жанров)
|
||||||
|
* tags: [categories]
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Список категорий
|
||||||
|
* 500:
|
||||||
|
* description: Ошибка сервера
|
||||||
|
*/
|
||||||
|
router.get('/', async (req, res) => {
|
||||||
|
try {
|
||||||
|
console.log('Fetching categories (genres)...');
|
||||||
|
|
||||||
|
// Получаем данные о всех жанрах из TMDB (фильмы и сериалы)
|
||||||
|
const genresData = await req.tmdb.getAllGenres();
|
||||||
|
|
||||||
|
if (!genresData?.genres || !Array.isArray(genresData.genres)) {
|
||||||
|
console.error('Invalid genres response:', genresData);
|
||||||
|
return res.status(500).json({
|
||||||
|
error: 'Invalid response from TMDB',
|
||||||
|
details: 'Genres data is missing or invalid'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Преобразуем жанры в категории
|
||||||
|
const categories = genresData.genres.map(genre => ({
|
||||||
|
id: genre.id,
|
||||||
|
name: genre.name,
|
||||||
|
slug: genre.name.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, '')
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Сортируем категории по алфавиту
|
||||||
|
categories.sort((a, b) => a.name.localeCompare(b.name, 'ru'));
|
||||||
|
|
||||||
|
console.log('Categories response:', {
|
||||||
|
count: categories.length,
|
||||||
|
categories: categories.slice(0, 3) // логируем только первые 3 для краткости
|
||||||
|
});
|
||||||
|
|
||||||
|
res.json({ categories });
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching categories:', {
|
||||||
|
message: error.message,
|
||||||
|
response: error.response?.data,
|
||||||
|
stack: error.stack
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(500).json({
|
||||||
|
error: 'Failed to fetch categories',
|
||||||
|
details: error.response?.data?.status_message || error.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /categories/{id}:
|
||||||
|
* get:
|
||||||
|
* summary: Получение категории по ID
|
||||||
|
* description: Возвращает информацию о категории по ее ID
|
||||||
|
* tags: [categories]
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: id
|
||||||
|
* required: true
|
||||||
|
* description: ID категории (жанра)
|
||||||
|
* schema:
|
||||||
|
* type: integer
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Категория найдена
|
||||||
|
* 404:
|
||||||
|
* description: Категория не найдена
|
||||||
|
* 500:
|
||||||
|
* description: Ошибка сервера
|
||||||
|
*/
|
||||||
|
router.get('/:id', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { id } = req.params;
|
||||||
|
console.log(`Fetching category (genre) with ID: ${id}`);
|
||||||
|
|
||||||
|
// Получаем данные о всех жанрах (фильмы и сериалы)
|
||||||
|
const genresData = await req.tmdb.getAllGenres();
|
||||||
|
|
||||||
|
if (!genresData?.genres || !Array.isArray(genresData.genres)) {
|
||||||
|
console.error('Invalid genres response:', genresData);
|
||||||
|
return res.status(500).json({
|
||||||
|
error: 'Invalid response from TMDB',
|
||||||
|
details: 'Genres data is missing or invalid'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Находим жанр по ID
|
||||||
|
const genre = genresData.genres.find(g => g.id === parseInt(id));
|
||||||
|
|
||||||
|
if (!genre) {
|
||||||
|
return res.status(404).json({
|
||||||
|
error: 'Category not found',
|
||||||
|
details: `No category with ID ${id}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Преобразуем жанр в категорию
|
||||||
|
const category = {
|
||||||
|
id: genre.id,
|
||||||
|
name: genre.name,
|
||||||
|
slug: genre.name.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, ''),
|
||||||
|
moviesCount: null // Можно будет дополнительно получить количество фильмов по жанру
|
||||||
|
};
|
||||||
|
|
||||||
|
res.json(category);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching category by ID:', error);
|
||||||
|
res.status(500).json({
|
||||||
|
error: 'Failed to fetch category',
|
||||||
|
details: error.response?.data?.status_message || error.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /categories/{id}/movies:
|
||||||
|
* get:
|
||||||
|
* summary: Получение фильмов по категории
|
||||||
|
* description: Возвращает список фильмов, принадлежащих указанной категории (жанру)
|
||||||
|
* tags: [categories]
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: id
|
||||||
|
* required: true
|
||||||
|
* description: ID категории (жанра)
|
||||||
|
* schema:
|
||||||
|
* type: integer
|
||||||
|
* - in: query
|
||||||
|
* name: page
|
||||||
|
* description: Номер страницы
|
||||||
|
* schema:
|
||||||
|
* type: integer
|
||||||
|
* minimum: 1
|
||||||
|
* default: 1
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Список фильмов по категории
|
||||||
|
* 404:
|
||||||
|
* description: Категория не найдена
|
||||||
|
* 500:
|
||||||
|
* description: Ошибка сервера
|
||||||
|
*/
|
||||||
|
router.get('/:id/movies', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { id } = req.params;
|
||||||
|
const { page = 1 } = req.query;
|
||||||
|
|
||||||
|
console.log(`Fetching movies for category (genre) ID: ${id}, page: ${page}`);
|
||||||
|
|
||||||
|
// Проверяем существование жанра в списке всех жанров
|
||||||
|
const genresData = await req.tmdb.getAllGenres();
|
||||||
|
const genreExists = genresData?.genres?.some(g => g.id === parseInt(id));
|
||||||
|
|
||||||
|
if (!genreExists) {
|
||||||
|
return res.status(404).json({
|
||||||
|
error: 'Category not found',
|
||||||
|
details: `No category with ID ${id}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получаем фильмы по жанру напрямую из TMDB
|
||||||
|
console.log(`Making TMDB request for movies with genre ID: ${id}, page: ${page}`);
|
||||||
|
|
||||||
|
// В URL параметрах напрямую указываем жанр, чтобы быть уверенными
|
||||||
|
const endpoint = `/discover/movie?with_genres=${id}`;
|
||||||
|
|
||||||
|
const requestParams = {
|
||||||
|
page,
|
||||||
|
language: 'ru-RU',
|
||||||
|
include_adult: false,
|
||||||
|
sort_by: 'popularity.desc'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Дополнительно добавляем вариации для разных жанров
|
||||||
|
if (parseInt(id) % 2 === 0) {
|
||||||
|
requestParams['vote_count.gte'] = 50;
|
||||||
|
} else {
|
||||||
|
requestParams['vote_average.gte'] = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Request params:', requestParams);
|
||||||
|
console.log('Endpoint with genre:', endpoint);
|
||||||
|
|
||||||
|
const response = await req.tmdb.makeRequest('get', endpoint, {
|
||||||
|
params: requestParams
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`TMDB response received, status: ${response.status}, has results: ${!!response?.data?.results}`);
|
||||||
|
|
||||||
|
if (response?.data?.results?.length > 0) {
|
||||||
|
console.log(`First few movie IDs: ${response.data.results.slice(0, 5).map(m => m.id).join(', ')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response?.data?.results) {
|
||||||
|
console.error('Invalid movie response:', response);
|
||||||
|
return res.status(500).json({
|
||||||
|
error: 'Invalid response from TMDB',
|
||||||
|
details: 'Movie data is missing'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Movies by category response:', {
|
||||||
|
page: response.data.page,
|
||||||
|
total_results: response.data.total_results,
|
||||||
|
results_count: response.data.results?.length
|
||||||
|
});
|
||||||
|
|
||||||
|
// Форматируем даты в результатах
|
||||||
|
const formattedResults = response.data.results.map(movie => ({
|
||||||
|
...movie,
|
||||||
|
release_date: movie.release_date ? formatDate(movie.release_date) : undefined,
|
||||||
|
poster_path: req.tmdb.getImageURL(movie.poster_path, 'w500'),
|
||||||
|
backdrop_path: req.tmdb.getImageURL(movie.backdrop_path, 'original')
|
||||||
|
}));
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
...response.data,
|
||||||
|
results: formattedResults
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching movies by category:', {
|
||||||
|
message: error.message,
|
||||||
|
response: error.response?.data
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(500).json({
|
||||||
|
error: 'Failed to fetch movies by category',
|
||||||
|
details: error.response?.data?.status_message || error.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /categories/{id}/tv:
|
||||||
|
* get:
|
||||||
|
* summary: Получение сериалов по категории
|
||||||
|
* description: Возвращает список сериалов, принадлежащих указанной категории (жанру)
|
||||||
|
* tags: [categories]
|
||||||
|
* parameters:
|
||||||
|
* - in: path
|
||||||
|
* name: id
|
||||||
|
* required: true
|
||||||
|
* description: ID категории (жанра)
|
||||||
|
* schema:
|
||||||
|
* type: integer
|
||||||
|
* - in: query
|
||||||
|
* name: page
|
||||||
|
* description: Номер страницы
|
||||||
|
* schema:
|
||||||
|
* type: integer
|
||||||
|
* minimum: 1
|
||||||
|
* default: 1
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Список сериалов по категории
|
||||||
|
* 404:
|
||||||
|
* description: Категория не найдена
|
||||||
|
* 500:
|
||||||
|
* description: Ошибка сервера
|
||||||
|
*/
|
||||||
|
router.get('/:id/tv', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { id } = req.params;
|
||||||
|
const { page = 1 } = req.query;
|
||||||
|
|
||||||
|
console.log(`Fetching TV shows for category (genre) ID: ${id}, page: ${page}`);
|
||||||
|
|
||||||
|
// Проверяем существование жанра в списке всех жанров
|
||||||
|
const genresData = await req.tmdb.getAllGenres();
|
||||||
|
const genreExists = genresData?.genres?.some(g => g.id === parseInt(id));
|
||||||
|
|
||||||
|
if (!genreExists) {
|
||||||
|
return res.status(404).json({
|
||||||
|
error: 'Category not found',
|
||||||
|
details: `No category with ID ${id}`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Получаем сериалы по жанру напрямую из TMDB
|
||||||
|
console.log(`Making TMDB request for TV shows with genre ID: ${id}, page: ${page}`);
|
||||||
|
|
||||||
|
// В URL параметрах напрямую указываем жанр, чтобы быть уверенными
|
||||||
|
const endpoint = `/discover/tv?with_genres=${id}`;
|
||||||
|
|
||||||
|
const requestParams = {
|
||||||
|
page,
|
||||||
|
language: 'ru-RU',
|
||||||
|
include_adult: false,
|
||||||
|
include_null_first_air_dates: false,
|
||||||
|
sort_by: 'popularity.desc'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Дополнительно добавляем вариации для разных жанров
|
||||||
|
if (parseInt(id) % 2 === 0) {
|
||||||
|
requestParams['vote_count.gte'] = 20;
|
||||||
|
} else {
|
||||||
|
requestParams['first_air_date.gte'] = '2010-01-01';
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('TV Request params:', requestParams);
|
||||||
|
console.log('TV Endpoint with genre:', endpoint);
|
||||||
|
|
||||||
|
const response = await req.tmdb.makeRequest('get', endpoint, {
|
||||||
|
params: requestParams
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`TMDB response for TV genre ${id} received, status: ${response.status}, has results: ${!!response?.data?.results}`);
|
||||||
|
if (response?.data?.results?.length > 0) {
|
||||||
|
console.log(`First few TV show IDs: ${response.data.results.slice(0, 5).map(show => show.id).join(', ')}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response?.data?.results) {
|
||||||
|
console.error('Invalid TV shows response:', response);
|
||||||
|
return res.status(500).json({
|
||||||
|
error: 'Invalid response from TMDB',
|
||||||
|
details: 'TV shows data is missing'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('TV shows by category response:', {
|
||||||
|
page: response.data.page,
|
||||||
|
total_results: response.data.total_results,
|
||||||
|
results_count: response.data.results?.length
|
||||||
|
});
|
||||||
|
|
||||||
|
// Форматируем даты в результатах
|
||||||
|
const formattedResults = response.data.results.map(tvShow => ({
|
||||||
|
...tvShow,
|
||||||
|
first_air_date: tvShow.first_air_date ? formatDate(tvShow.first_air_date) : undefined,
|
||||||
|
poster_path: req.tmdb.getImageURL(tvShow.poster_path, 'w500'),
|
||||||
|
backdrop_path: req.tmdb.getImageURL(tvShow.backdrop_path, 'original')
|
||||||
|
}));
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
...response.data,
|
||||||
|
results: formattedResults
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error fetching TV shows by category:', {
|
||||||
|
message: error.message,
|
||||||
|
response: error.response?.data
|
||||||
|
});
|
||||||
|
|
||||||
|
res.status(500).json({
|
||||||
|
error: 'Failed to fetch TV shows by category',
|
||||||
|
details: error.response?.data?.status_message || error.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
@@ -13,6 +13,98 @@ router.use((req, res, next) => {
|
|||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @swagger
|
||||||
|
* /movies/search:
|
||||||
|
* get:
|
||||||
|
* summary: Поиск фильмов
|
||||||
|
* description: Поиск фильмов по запросу с поддержкой русского языка
|
||||||
|
* tags: [movies]
|
||||||
|
* parameters:
|
||||||
|
* - in: query
|
||||||
|
* name: query
|
||||||
|
* required: true
|
||||||
|
* description: Поисковый запрос
|
||||||
|
* schema:
|
||||||
|
* type: string
|
||||||
|
* example: Матрица
|
||||||
|
* - in: query
|
||||||
|
* name: page
|
||||||
|
* description: Номер страницы (по умолчанию 1)
|
||||||
|
* schema:
|
||||||
|
* type: integer
|
||||||
|
* minimum: 1
|
||||||
|
* default: 1
|
||||||
|
* example: 1
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: Успешный поиск
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* type: object
|
||||||
|
* properties:
|
||||||
|
* page:
|
||||||
|
* type: integer
|
||||||
|
* description: Текущая страница
|
||||||
|
* total_pages:
|
||||||
|
* type: integer
|
||||||
|
* description: Всего страниц
|
||||||
|
* total_results:
|
||||||
|
* type: integer
|
||||||
|
* description: Всего результатов
|
||||||
|
* results:
|
||||||
|
* type: array
|
||||||
|
* items:
|
||||||
|
* $ref: '#/components/schemas/Movie'
|
||||||
|
* 400:
|
||||||
|
* description: Неверный запрос
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/Error'
|
||||||
|
* 500:
|
||||||
|
* description: Ошибка сервера
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* $ref: '#/components/schemas/Error'
|
||||||
|
*/
|
||||||
|
router.get('/search', async (req, res) => {
|
||||||
|
try {
|
||||||
|
const { query, page = 1 } = req.query;
|
||||||
|
|
||||||
|
if (!query) {
|
||||||
|
return res.status(400).json({ error: 'Query parameter is required' });
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('Search request:', { query, page });
|
||||||
|
|
||||||
|
const data = await req.tmdb.searchMovies(query, page);
|
||||||
|
|
||||||
|
console.log('Search response:', {
|
||||||
|
page: data.page,
|
||||||
|
total_results: data.total_results,
|
||||||
|
total_pages: data.total_pages,
|
||||||
|
results_count: data.results?.length
|
||||||
|
});
|
||||||
|
|
||||||
|
// Форматируем даты в результатах
|
||||||
|
const formattedResults = data.results.map(movie => ({
|
||||||
|
...movie,
|
||||||
|
release_date: formatDate(movie.release_date)
|
||||||
|
}));
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
...data,
|
||||||
|
results: formattedResults
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error searching movies:', error);
|
||||||
|
res.status(500).json({ error: error.message });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @swagger
|
* @swagger
|
||||||
* /search/multi:
|
* /search/multi:
|
||||||
|
|||||||
Reference in New Issue
Block a user