mirror of
https://gitlab.com/foxixus/neomovies.git
synced 2025-10-29 02:18:49 +05:00
Измения в АПИ
This commit is contained in:
262
src/lib/api.ts
262
src/lib/api.ts
@@ -1,262 +0,0 @@
|
||||
import axios from 'axios';
|
||||
|
||||
const API_URL = process.env.NEXT_PUBLIC_API_URL;
|
||||
|
||||
if (!API_URL) {
|
||||
throw new Error('NEXT_PUBLIC_API_URL is not defined in environment variables');
|
||||
}
|
||||
|
||||
export const api = axios.create({
|
||||
baseURL: API_URL,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
// Attach JWT token if present in localStorage
|
||||
if (typeof window !== 'undefined') {
|
||||
const token = localStorage.getItem('token');
|
||||
if (token) {
|
||||
api.defaults.headers.common['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Update stored token on login response with { token }
|
||||
api.interceptors.response.use((response) => {
|
||||
if (response.config.url?.includes('/auth/login') && response.data?.token) {
|
||||
if (typeof window !== 'undefined') {
|
||||
localStorage.setItem('token', response.data.token);
|
||||
api.defaults.headers.common['Authorization'] = `Bearer ${response.data.token}`;
|
||||
}
|
||||
}
|
||||
return response;
|
||||
});
|
||||
|
||||
export interface Category {
|
||||
id: number;
|
||||
name: string;
|
||||
slug: string;
|
||||
}
|
||||
|
||||
export interface Genre {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface Movie {
|
||||
id: number;
|
||||
title: string;
|
||||
overview: string;
|
||||
poster_path: string | null;
|
||||
backdrop_path: string | null;
|
||||
release_date: string;
|
||||
vote_average: number;
|
||||
vote_count: number;
|
||||
genre_ids: number[];
|
||||
runtime?: number;
|
||||
genres?: Array<{ id: number; name: string }>;
|
||||
}
|
||||
|
||||
export interface MovieDetails extends Movie {
|
||||
genres: Genre[];
|
||||
runtime: number;
|
||||
imdb_id?: string | null;
|
||||
tagline: string;
|
||||
budget: number;
|
||||
revenue: number;
|
||||
videos: {
|
||||
results: Video[];
|
||||
};
|
||||
credits: {
|
||||
cast: Cast[];
|
||||
crew: Crew[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface TVShow {
|
||||
id: number;
|
||||
name: string;
|
||||
overview: string;
|
||||
poster_path: string | null;
|
||||
backdrop_path: string | null;
|
||||
first_air_date: string;
|
||||
vote_average: number;
|
||||
vote_count: number;
|
||||
genre_ids: number[];
|
||||
}
|
||||
|
||||
export interface TVShowDetails extends TVShow {
|
||||
genres: Genre[];
|
||||
number_of_episodes: number;
|
||||
number_of_seasons: number;
|
||||
tagline: string;
|
||||
credits: {
|
||||
cast: Cast[];
|
||||
crew: Crew[];
|
||||
};
|
||||
seasons: Array<{
|
||||
id: number;
|
||||
name: string;
|
||||
episode_count: number;
|
||||
poster_path: string | null;
|
||||
}>;
|
||||
external_ids?: {
|
||||
imdb_id: string | null;
|
||||
tvdb_id: number | null;
|
||||
tvrage_id: number | null;
|
||||
};
|
||||
}
|
||||
|
||||
export interface Video {
|
||||
id: string;
|
||||
key: string;
|
||||
name: string;
|
||||
site: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface Cast {
|
||||
id: number;
|
||||
name: string;
|
||||
character: string;
|
||||
profile_path: string | null;
|
||||
}
|
||||
|
||||
export interface Crew {
|
||||
id: number;
|
||||
name: string;
|
||||
job: string;
|
||||
profile_path: string | null;
|
||||
}
|
||||
|
||||
export interface MovieResponse {
|
||||
page: number;
|
||||
results: Movie[];
|
||||
total_pages: number;
|
||||
total_results: number;
|
||||
}
|
||||
|
||||
export interface TVShowResponse {
|
||||
page: number;
|
||||
results: TVShow[];
|
||||
total_pages: number;
|
||||
total_results: number;
|
||||
}
|
||||
|
||||
export const categoriesAPI = {
|
||||
// Получение всех категорий
|
||||
getCategories() {
|
||||
return api.get<{ categories: Category[] }>('/categories');
|
||||
},
|
||||
|
||||
// Получение категории по ID
|
||||
getCategory(id: number) {
|
||||
return api.get<Category>(`/categories/${id}`);
|
||||
},
|
||||
|
||||
// Получение фильмов по категории
|
||||
getMoviesByCategory(categoryId: number, page = 1) {
|
||||
return api.get<MovieResponse>(`/categories/${categoryId}/movies`, {
|
||||
params: { page }
|
||||
});
|
||||
},
|
||||
|
||||
// Получение сериалов по категории
|
||||
getTVShowsByCategory(categoryId: number, page = 1) {
|
||||
return api.get<TVShowResponse>(`/categories/${categoryId}/tv`, {
|
||||
params: { page }
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const moviesAPI = {
|
||||
// Получение популярных фильмов
|
||||
getPopular(page = 1) {
|
||||
return api.get<MovieResponse>('/movies/popular', {
|
||||
params: { page }
|
||||
});
|
||||
},
|
||||
|
||||
// Получение данных о фильме по его TMDB ID
|
||||
getMovie(id: string | number) {
|
||||
return api.get<MovieDetails>(`/movies/${id}`);
|
||||
},
|
||||
|
||||
// Получение IMDb ID по TMDB ID для плеера
|
||||
getImdbId(tmdbId: string | number) {
|
||||
return api.get<{ imdb_id: string }>(`/movies/${tmdbId}/external-ids`);
|
||||
},
|
||||
|
||||
// Получение видео по TMDB ID для плеера
|
||||
getVideo(tmdbId: string | number) {
|
||||
return api.get<{ results: Video[] }>(`/movies/${tmdbId}/videos`);
|
||||
},
|
||||
|
||||
// Поиск фильмов
|
||||
searchMovies(query: string, page = 1) {
|
||||
return api.get<MovieResponse>('/movies/search', {
|
||||
params: { query, page }
|
||||
});
|
||||
},
|
||||
|
||||
// Получение предстоящих фильмов
|
||||
getUpcoming(page = 1) {
|
||||
return api.get<MovieResponse>('/movies/upcoming', {
|
||||
params: { page }
|
||||
});
|
||||
},
|
||||
|
||||
// Получение лучших фильмов
|
||||
getTopRated(page = 1) {
|
||||
return api.get<MovieResponse>('/movies/top-rated', {
|
||||
params: { page }
|
||||
});
|
||||
},
|
||||
|
||||
// Получение фильмов по жанру
|
||||
getMoviesByGenre(genreId: number, page = 1) {
|
||||
return api.get<MovieResponse>('/movies/discover', {
|
||||
params: { with_genres: genreId, page }
|
||||
});
|
||||
},
|
||||
|
||||
// Получение жанров
|
||||
getGenres() {
|
||||
return api.get<{ genres: Genre[] }>('/movies/genres');
|
||||
}
|
||||
};
|
||||
|
||||
export const tvAPI = {
|
||||
// Получение популярных сериалов
|
||||
getPopular(page = 1) {
|
||||
return api.get<TVShowResponse>('/tv/popular', {
|
||||
params: { page }
|
||||
});
|
||||
},
|
||||
|
||||
// Получение данных о сериале по его TMDB ID
|
||||
getShow(id: string | number) {
|
||||
return api.get<TVShowDetails>(`/tv/${id}`);
|
||||
},
|
||||
|
||||
// Получение IMDb ID по TMDB ID для плеера
|
||||
getImdbId(tmdbId: string | number) {
|
||||
return api.get<{ imdb_id: string }>(`/tv/${tmdbId}/external-ids`);
|
||||
},
|
||||
|
||||
// Поиск сериалов
|
||||
searchShows(query: string, page = 1) {
|
||||
return api.get<TVShowResponse>('/tv/search', {
|
||||
params: { query, page }
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Мультипоиск (фильмы и сериалы)
|
||||
export const searchAPI = {
|
||||
multiSearch(query: string, page = 1) {
|
||||
return api.get('/search/multi', {
|
||||
params: { query, page }
|
||||
});
|
||||
}
|
||||
};
|
||||
@@ -1,19 +1,10 @@
|
||||
import { api } from './api';
|
||||
import { neoApi } from './neoApi';
|
||||
|
||||
export const authAPI = {
|
||||
register(data: { email: string; password: string; name?: string }) {
|
||||
return api.post('/auth/register', data);
|
||||
},
|
||||
resendCode(email: string) {
|
||||
return api.post('/auth/resend-code', { email });
|
||||
},
|
||||
verify(email: string, code: string) {
|
||||
return api.post('/auth/verify', { email, code });
|
||||
},
|
||||
login(email: string, password: string) {
|
||||
return api.post('/auth/login', { email, password });
|
||||
},
|
||||
deleteAccount() {
|
||||
return api.delete('/auth/profile');
|
||||
}
|
||||
register: (data: any) => neoApi.post('/api/v1/auth/register', data),
|
||||
resendCode: (email: string) => neoApi.post('/api/v1/auth/resend-code', { email }),
|
||||
verify: (email: string, code: string) => neoApi.post('/api/v1/auth/verify', { email, code }),
|
||||
checkVerification: (email: string) => neoApi.post('/api/v1/auth/check-verification', { email }),
|
||||
login: (email: string, password: string) => neoApi.post('/api/v1/auth/login', { email, password }),
|
||||
deleteAccount: () => neoApi.delete('/api/v1/auth/profile'),
|
||||
};
|
||||
|
||||
@@ -1,25 +1,24 @@
|
||||
import { api } from './api';
|
||||
|
||||
import { neoApi } from './neoApi';
|
||||
|
||||
export const favoritesAPI = {
|
||||
// Получить все избранные
|
||||
// Получение всех избранных
|
||||
getFavorites() {
|
||||
return api.get('/favorites');
|
||||
return neoApi.get('/api/v1/favorites');
|
||||
},
|
||||
|
||||
// Добавить в избранное
|
||||
addFavorite(data: { mediaId: string; mediaType: 'movie' | 'tv', title: string, posterPath: string }) {
|
||||
const { mediaId, mediaType, title, posterPath } = data;
|
||||
return api.post(`/favorites/${mediaId}?mediaType=${mediaType}`, { title, posterPath });
|
||||
// Добавление в избранное
|
||||
addFavorite(data: { mediaId: string; mediaType: string; title: string; posterPath?: string }) {
|
||||
const { mediaId, mediaType, ...rest } = data;
|
||||
return neoApi.post(`/api/v1/favorites/${mediaId}?mediaType=${mediaType}`, rest);
|
||||
},
|
||||
|
||||
// Удалить из избранного
|
||||
// Удаление из избранного
|
||||
removeFavorite(mediaId: string) {
|
||||
return api.delete(`/favorites/${mediaId}`);
|
||||
return neoApi.delete(`/api/v1/favorites/${mediaId}`);
|
||||
},
|
||||
|
||||
// Проверить есть ли в избранном
|
||||
// Проверка, добавлен ли в избранное
|
||||
checkFavorite(mediaId: string) {
|
||||
return api.get(`/favorites/check/${mediaId}`);
|
||||
return neoApi.get(`/api/v1/favorites/check/${mediaId}`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -29,32 +29,26 @@ export async function connectToDatabase() {
|
||||
return { db, client };
|
||||
}
|
||||
|
||||
// Инициализация MongoDB
|
||||
export async function initMongoDB() {
|
||||
try {
|
||||
const { db } = await connectToDatabase();
|
||||
|
||||
// Создаем уникальный индекс для избранного
|
||||
await db.collection('favorites').createIndex(
|
||||
{ userId: 1, mediaId: 1, mediaType: 1 },
|
||||
{ unique: true }
|
||||
);
|
||||
|
||||
console.log('MongoDB initialized successfully');
|
||||
} catch (error) {
|
||||
console.error('Error initializing MongoDB:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Функция для сброса и создания индексов
|
||||
export async function resetIndexes() {
|
||||
const { db } = await connectToDatabase();
|
||||
|
||||
// Удаляем все индексы из коллекции favorites
|
||||
await db.collection('favorites').dropIndexes();
|
||||
|
||||
// Создаем новый правильный индекс
|
||||
await db.collection('favorites').createIndex(
|
||||
{ userId: 1, mediaId: 1, mediaType: 1 },
|
||||
{ unique: true }
|
||||
|
||||
@@ -1,18 +1,25 @@
|
||||
import axios from 'axios';
|
||||
|
||||
const API_URL = process.env.NEXT_PUBLIC_API_URL;
|
||||
const API_URL = process.env.NEXT_PUBLIC_API_URL || 'https://neomovies-test-api.vercel.app';
|
||||
|
||||
// Создание экземпляра Axios с базовыми настройками
|
||||
export const neoApi = axios.create({
|
||||
baseURL: API_URL,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
timeout: 30000 // Увеличиваем таймаут до 30 секунд
|
||||
timeout: 30000
|
||||
});
|
||||
|
||||
// Добавляем перехватчики запросов
|
||||
// Перехватчик запросов
|
||||
neoApi.interceptors.request.use(
|
||||
(config) => {
|
||||
// Получение токена из localStorage или другого хранилища
|
||||
const token = localStorage.getItem('token');
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`;
|
||||
}
|
||||
// Логика для пагинации
|
||||
if (config.params?.page) {
|
||||
const page = parseInt(config.params.page);
|
||||
if (isNaN(page) || page < 1) {
|
||||
@@ -27,29 +34,34 @@ neoApi.interceptors.request.use(
|
||||
}
|
||||
);
|
||||
|
||||
// Добавляем перехватчики ответов
|
||||
// Перехватчик ответов
|
||||
neoApi.interceptors.response.use(
|
||||
(response) => {
|
||||
if (response.data && response.data.success && response.data.data !== undefined) {
|
||||
response.data = response.data.data;
|
||||
}
|
||||
return response;
|
||||
},
|
||||
(error) => {
|
||||
console.error('❌ Response Error:', {
|
||||
status: error.response?.status,
|
||||
statusText: error.response?.statusText,
|
||||
url: error.config?.url,
|
||||
method: error.config?.method,
|
||||
message: error.message
|
||||
message: error.message,
|
||||
data: error.response?.data
|
||||
});
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// Функция для получения URL изображения
|
||||
export const getImageUrl = (path: string | null, size: string = 'w500'): string => {
|
||||
if (!path) return '/images/placeholder.jpg';
|
||||
// Извлекаем только ID изображения из полного пути
|
||||
const imageId = path.split('/').pop();
|
||||
if (!imageId) return '/images/placeholder.jpg';
|
||||
return `${API_URL}/images/${size}/${imageId}`;
|
||||
if (path.startsWith('http')) {
|
||||
return path;
|
||||
}
|
||||
const cleanPath = path.startsWith('/') ? path.slice(1) : path;
|
||||
return `${API_URL}/api/v1/images/${size}/${cleanPath}`;
|
||||
};
|
||||
|
||||
export interface Genre {
|
||||
@@ -80,10 +92,44 @@ export interface MovieResponse {
|
||||
total_results: number;
|
||||
}
|
||||
|
||||
export interface TorrentResult {
|
||||
title: string;
|
||||
tracker: string;
|
||||
size: string;
|
||||
seeders: number;
|
||||
peers: number;
|
||||
leechers: number;
|
||||
quality: string;
|
||||
voice?: string[];
|
||||
types?: string[];
|
||||
seasons?: number[];
|
||||
category: string;
|
||||
magnet: string;
|
||||
torrent_link?: string;
|
||||
details?: string;
|
||||
publish_date: string;
|
||||
added_date?: string;
|
||||
source: string;
|
||||
}
|
||||
|
||||
export interface TorrentSearchResponse {
|
||||
query: string;
|
||||
results: TorrentResult[];
|
||||
total: number;
|
||||
}
|
||||
|
||||
export interface AvailableSeasonsResponse {
|
||||
title: string;
|
||||
originalTitle: string;
|
||||
year: string;
|
||||
seasons: number[];
|
||||
total: number;
|
||||
}
|
||||
|
||||
export const searchAPI = {
|
||||
// Поиск фильмов
|
||||
searchMovies(query: string, page = 1) {
|
||||
return neoApi.get<MovieResponse>('/movies/search', {
|
||||
return neoApi.get<MovieResponse>('/api/v1/movies/search', {
|
||||
params: {
|
||||
query,
|
||||
page
|
||||
@@ -94,7 +140,7 @@ export const searchAPI = {
|
||||
|
||||
// Поиск сериалов
|
||||
searchTV(query: string, page = 1) {
|
||||
return neoApi.get<MovieResponse>('/tv/search', {
|
||||
return neoApi.get<MovieResponse>('/api/v1/tv/search', {
|
||||
params: {
|
||||
query,
|
||||
page
|
||||
@@ -103,46 +149,19 @@ export const searchAPI = {
|
||||
});
|
||||
},
|
||||
|
||||
// Мультипоиск (фильмы и сериалы)
|
||||
// Мультипоиск (фильмы и сериалы) - новый эндпоинт
|
||||
async multiSearch(query: string, page = 1) {
|
||||
// Запускаем параллельные запросы к фильмам и сериалам
|
||||
try {
|
||||
const [moviesResponse, tvResponse] = await Promise.all([
|
||||
this.searchMovies(query, page),
|
||||
this.searchTV(query, page)
|
||||
]);
|
||||
// Используем новый эндпоинт Go API
|
||||
const response = await neoApi.get<MovieResponse>('/search/multi', {
|
||||
params: {
|
||||
query,
|
||||
page
|
||||
},
|
||||
timeout: 30000
|
||||
});
|
||||
|
||||
// Объединяем результаты
|
||||
const moviesData = moviesResponse.data;
|
||||
const tvData = tvResponse.data;
|
||||
|
||||
// Метаданные для пагинации
|
||||
const totalResults = (moviesData.total_results || 0) + (tvData.total_results || 0);
|
||||
const totalPages = Math.max(moviesData.total_pages || 0, tvData.total_pages || 0);
|
||||
|
||||
// Добавляем информацию о типе контента
|
||||
const moviesWithType = (moviesData.results || []).map(movie => ({
|
||||
...movie,
|
||||
media_type: 'movie'
|
||||
}));
|
||||
|
||||
const tvWithType = (tvData.results || []).map(show => ({
|
||||
...show,
|
||||
media_type: 'tv'
|
||||
}));
|
||||
|
||||
// Объединяем и сортируем по популярности
|
||||
const combinedResults = [...moviesWithType, ...tvWithType]
|
||||
.sort((a, b) => (b.popularity || 0) - (a.popularity || 0));
|
||||
|
||||
return {
|
||||
data: {
|
||||
page: parseInt(String(page)),
|
||||
results: combinedResults,
|
||||
total_pages: totalPages,
|
||||
total_results: totalResults
|
||||
}
|
||||
};
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error('Error in multiSearch:', error);
|
||||
throw error;
|
||||
@@ -153,7 +172,7 @@ export const searchAPI = {
|
||||
export const moviesAPI = {
|
||||
// Получение популярных фильмов
|
||||
getPopular(page = 1) {
|
||||
return neoApi.get<MovieResponse>('/movies/popular', {
|
||||
return neoApi.get<MovieResponse>('/api/v1/movies/popular', {
|
||||
params: { page },
|
||||
timeout: 30000
|
||||
});
|
||||
@@ -161,7 +180,7 @@ export const moviesAPI = {
|
||||
|
||||
// Получение фильмов с высоким рейтингом
|
||||
getTopRated(page = 1) {
|
||||
return neoApi.get<MovieResponse>('/movies/top_rated', {
|
||||
return neoApi.get<MovieResponse>('/api/v1/movies/top-rated', {
|
||||
params: { page },
|
||||
timeout: 30000
|
||||
});
|
||||
@@ -169,7 +188,15 @@ export const moviesAPI = {
|
||||
|
||||
// Получение новинок
|
||||
getNowPlaying(page = 1) {
|
||||
return neoApi.get<MovieResponse>('/movies/now_playing', {
|
||||
return neoApi.get<MovieResponse>('/api/v1/movies/now-playing', {
|
||||
params: { page },
|
||||
timeout: 30000
|
||||
});
|
||||
},
|
||||
|
||||
// Получение предстоящих фильмов
|
||||
getUpcoming(page = 1) {
|
||||
return neoApi.get<MovieResponse>('/api/v1/movies/upcoming', {
|
||||
params: { page },
|
||||
timeout: 30000
|
||||
});
|
||||
@@ -177,12 +204,12 @@ export const moviesAPI = {
|
||||
|
||||
// Получение данных о фильме по его ID
|
||||
getMovie(id: string | number) {
|
||||
return neoApi.get(`/movies/${id}`, { timeout: 30000 });
|
||||
return neoApi.get(`/api/v1/movies/${id}`, { timeout: 30000 });
|
||||
},
|
||||
|
||||
// Поиск фильмов
|
||||
searchMovies(query: string, page = 1) {
|
||||
return neoApi.get<MovieResponse>('/movies/search', {
|
||||
return neoApi.get<MovieResponse>('/api/v1/movies/search', {
|
||||
params: {
|
||||
query,
|
||||
page
|
||||
@@ -191,16 +218,40 @@ export const moviesAPI = {
|
||||
});
|
||||
},
|
||||
|
||||
// Получение IMDB ID
|
||||
getImdbId(id: string | number) {
|
||||
return neoApi.get(`/movies/${id}/external_ids`, { timeout: 30000 }).then(res => res.data.imdb_id);
|
||||
// Получение IMDB и других external ids
|
||||
getExternalIds(id: string | number) {
|
||||
return neoApi.get(`/api/v1/movies/${id}/external-ids`, { timeout: 30000 }).then(res => res.data);
|
||||
}
|
||||
};
|
||||
|
||||
export const tvShowsAPI = {
|
||||
// Получение популярных сериалов
|
||||
getPopular(page = 1) {
|
||||
return neoApi.get('/tv/popular', {
|
||||
return neoApi.get('/api/v1/tv/popular', {
|
||||
params: { page },
|
||||
timeout: 30000
|
||||
});
|
||||
},
|
||||
|
||||
// Получение сериалов с высоким рейтингом
|
||||
getTopRated(page = 1) {
|
||||
return neoApi.get('/api/v1/tv/top-rated', {
|
||||
params: { page },
|
||||
timeout: 30000
|
||||
});
|
||||
},
|
||||
|
||||
// Получение сериалов в эфире
|
||||
getOnTheAir(page = 1) {
|
||||
return neoApi.get('/api/v1/tv/on-the-air', {
|
||||
params: { page },
|
||||
timeout: 30000
|
||||
});
|
||||
},
|
||||
|
||||
// Получение сериалов, которые выходят сегодня
|
||||
getAiringToday(page = 1) {
|
||||
return neoApi.get('/api/v1/tv/airing-today', {
|
||||
params: { page },
|
||||
timeout: 30000
|
||||
});
|
||||
@@ -208,12 +259,12 @@ export const tvShowsAPI = {
|
||||
|
||||
// Получение данных о сериале по его ID
|
||||
getTVShow(id: string | number) {
|
||||
return neoApi.get(`/tv/${id}`, { timeout: 30000 });
|
||||
return neoApi.get(`/api/v1/tv/${id}`, { timeout: 30000 });
|
||||
},
|
||||
|
||||
// Поиск сериалов
|
||||
searchTVShows(query: string, page = 1) {
|
||||
return neoApi.get('/tv/search', {
|
||||
return neoApi.get('/api/v1/tv/search', {
|
||||
params: {
|
||||
query,
|
||||
page
|
||||
@@ -222,8 +273,101 @@ export const tvShowsAPI = {
|
||||
});
|
||||
},
|
||||
|
||||
// Получение IMDB ID
|
||||
getImdbId(id: string | number) {
|
||||
return neoApi.get(`/tv/${id}/external-ids`, { timeout: 30000 }).then(res => res.data.imdb_id);
|
||||
// Получение IMDB и других external ids
|
||||
getExternalIds(id: string | number) {
|
||||
return neoApi.get(`/api/v1/tv/${id}/external-ids`, { timeout: 30000 }).then(res => res.data);
|
||||
}
|
||||
};
|
||||
|
||||
export const torrentsAPI = {
|
||||
// Поиск торрентов по IMDB ID
|
||||
searchTorrents(imdbId: string, type: 'movie' | 'tv', options?: {
|
||||
season?: number;
|
||||
quality?: string;
|
||||
minQuality?: string;
|
||||
maxQuality?: string;
|
||||
excludeQualities?: string;
|
||||
hdr?: boolean;
|
||||
hevc?: boolean;
|
||||
sortBy?: string;
|
||||
sortOrder?: string;
|
||||
groupByQuality?: boolean;
|
||||
groupBySeason?: boolean;
|
||||
}) {
|
||||
const params: any = { type };
|
||||
|
||||
if (options) {
|
||||
Object.entries(options).forEach(([key, value]) => {
|
||||
if (value !== undefined) {
|
||||
if (key === 'excludeQualities' && Array.isArray(value)) {
|
||||
params[key] = value.join(',');
|
||||
} else {
|
||||
params[key] = value;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return neoApi.get<TorrentSearchResponse>(`/api/v1/torrents/search/${imdbId}`, {
|
||||
params,
|
||||
timeout: 30000
|
||||
});
|
||||
},
|
||||
|
||||
// Получение доступных сезонов для сериала
|
||||
getAvailableSeasons(title: string, originalTitle?: string, year?: string) {
|
||||
const params: any = { title };
|
||||
if (originalTitle) params.originalTitle = originalTitle;
|
||||
if (year) params.year = year;
|
||||
|
||||
return neoApi.get<AvailableSeasonsResponse>('/api/v1/torrents/seasons', {
|
||||
params,
|
||||
timeout: 30000
|
||||
});
|
||||
},
|
||||
|
||||
// Универсальный поиск торрентов по запросу
|
||||
searchByQuery(query: string, type: 'movie' | 'tv' | 'anime' = 'movie', year?: string) {
|
||||
const params: any = { query, type };
|
||||
if (year) params.year = year;
|
||||
|
||||
return neoApi.get<TorrentSearchResponse>('/api/v1/torrents/search', {
|
||||
params,
|
||||
timeout: 30000
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export const categoriesAPI = {
|
||||
// Получение всех категорий
|
||||
getCategories() {
|
||||
return neoApi.get<{ categories: Category[] }>('/api/v1/categories');
|
||||
},
|
||||
|
||||
// Получение категории по ID
|
||||
getCategory(id: number) {
|
||||
return neoApi.get<Category>(`/api/v1/categories/${id}`);
|
||||
},
|
||||
|
||||
// Получение фильмов по категории
|
||||
getMoviesByCategory(categoryId: number, page = 1) {
|
||||
return neoApi.get<MovieResponse>(`/api/v1/categories/${categoryId}/movies`, {
|
||||
params: { page }
|
||||
});
|
||||
},
|
||||
|
||||
// Получение сериалов по категории
|
||||
getTVShowsByCategory(categoryId: number, page = 1) {
|
||||
return neoApi.get<MovieResponse>(`/api/v1/categories/${categoryId}/tv`, {
|
||||
params: { page }
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Новый API-клиент для работы с аутентификацией и профилем
|
||||
export const authAPI = {
|
||||
// Новый метод для удаления аккаунта
|
||||
deleteAccount() {
|
||||
return neoApi.delete('/api/v1/profile');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,28 +1,30 @@
|
||||
import { api } from './api';
|
||||
import { neoApi } from './neoApi';
|
||||
|
||||
export interface Reaction {
|
||||
_id: string;
|
||||
userId: string;
|
||||
type: 'like' | 'dislike';
|
||||
mediaId: string;
|
||||
mediaType: 'movie' | 'tv';
|
||||
type: 'fire' | 'nice' | 'think' | 'bore' | 'shit';
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export const reactionsAPI = {
|
||||
// [PUBLIC] Получить счетчики для всех типов реакций
|
||||
getReactionCounts(mediaType: string, mediaId: string): Promise<{ data: Record<string, number> }> {
|
||||
return api.get(`/reactions/${mediaType}/${mediaId}/counts`);
|
||||
// Получение счетчиков реакций
|
||||
getReactionCounts(mediaType: string, mediaId: string) {
|
||||
return neoApi.get(`/api/v1/reactions/${mediaType}/${mediaId}/counts`);
|
||||
},
|
||||
|
||||
// [AUTH] Получить реакцию пользователя для медиа
|
||||
getMyReaction(mediaType: string, mediaId: string): Promise<{ data: Reaction | null }> {
|
||||
return api.get(`/reactions/${mediaType}/${mediaId}/my-reaction`);
|
||||
// Получение моей реакции
|
||||
getMyReaction(mediaType: string, mediaId: string) {
|
||||
return neoApi.get(`/api/v1/reactions/${mediaType}/${mediaId}/my-reaction`);
|
||||
},
|
||||
|
||||
// [AUTH] Установить/обновить/удалить реакцию
|
||||
setReaction(mediaType: string, mediaId: string, type: Reaction['type']): Promise<{ data: Reaction }> {
|
||||
// Установка реакции
|
||||
setReaction(mediaType: string, mediaId: string, type: 'like' | 'dislike') {
|
||||
const fullMediaId = `${mediaType}_${mediaId}`;
|
||||
return api.post('/reactions', { mediaId: fullMediaId, type });
|
||||
return neoApi.post('/api/v1/reactions', { mediaId: fullMediaId, type });
|
||||
},
|
||||
|
||||
// Удаление реакции
|
||||
removeReaction(mediaType: string, mediaId: string) {
|
||||
return neoApi.delete(`/api/v1/reactions/${mediaType}/${mediaId}`);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user