mirror of
https://gitlab.com/foxixus/neomovies-api.git
synced 2025-12-17 04:56:09 +05:00
258 lines
7.4 KiB
Go
258 lines
7.4 KiB
Go
package services
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"strconv"
|
||
"strings"
|
||
"time"
|
||
|
||
"go.mongodb.org/mongo-driver/bson"
|
||
"go.mongodb.org/mongo-driver/mongo"
|
||
|
||
"neomovies-api/pkg/models"
|
||
)
|
||
|
||
type FavoritesService struct {
|
||
db *mongo.Database
|
||
tmdb *TMDBService
|
||
kinopoisk *KinopoiskService
|
||
}
|
||
|
||
func NewFavoritesService(db *mongo.Database, tmdb *TMDBService) *FavoritesService {
|
||
return &FavoritesService{
|
||
db: db,
|
||
tmdb: tmdb,
|
||
}
|
||
}
|
||
|
||
func NewFavoritesServiceWithKP(db *mongo.Database, tmdb *TMDBService, kp *KinopoiskService) *FavoritesService {
|
||
return &FavoritesService{
|
||
db: db,
|
||
tmdb: tmdb,
|
||
kinopoisk: kp,
|
||
}
|
||
}
|
||
|
||
func (s *FavoritesService) AddToFavorites(userID, mediaID, mediaType string) error {
|
||
collection := s.db.Collection("favorites")
|
||
|
||
// Проверяем, не добавлен ли уже в избранное
|
||
filter := bson.M{
|
||
"userId": userID,
|
||
"mediaId": mediaID,
|
||
"mediaType": mediaType,
|
||
}
|
||
|
||
var existingFavorite models.Favorite
|
||
err := collection.FindOne(context.Background(), filter).Decode(&existingFavorite)
|
||
if err == nil {
|
||
// Уже в избранном
|
||
return nil
|
||
}
|
||
|
||
// Получаем информацию из TMDB
|
||
mediaIDInt, err := strconv.Atoi(mediaID)
|
||
if err != nil {
|
||
return fmt.Errorf("invalid media ID: %s", mediaID)
|
||
}
|
||
|
||
var movie *models.Movie
|
||
var tv *models.TVShow
|
||
|
||
if mediaType == "movie" {
|
||
movie, err = s.tmdb.GetMovie(mediaIDInt, "ru-RU")
|
||
if err != nil {
|
||
return err
|
||
}
|
||
} else if mediaType == "tv" {
|
||
tv, err = s.tmdb.GetTVShow(mediaIDInt, "ru-RU")
|
||
if err != nil {
|
||
return err
|
||
}
|
||
} else {
|
||
return fmt.Errorf("invalid media type: %s", mediaType)
|
||
}
|
||
|
||
favorite := models.Favorite{
|
||
UserID: userID,
|
||
MediaID: mediaID,
|
||
MediaType: mediaType,
|
||
CreatedAt: time.Now(),
|
||
}
|
||
|
||
if movie != nil {
|
||
favorite.Title = movie.Title
|
||
favorite.NameRu = movie.Title
|
||
favorite.NameEn = movie.OriginalTitle
|
||
favorite.PosterPath = movie.PosterPath
|
||
if len(movie.ReleaseDate) >= 4 {
|
||
year, _ := strconv.Atoi(movie.ReleaseDate[:4])
|
||
favorite.Year = year
|
||
}
|
||
favorite.Rating = movie.VoteAverage
|
||
} else if tv != nil {
|
||
favorite.Title = tv.Name
|
||
favorite.NameRu = tv.Name
|
||
favorite.NameEn = tv.OriginalName
|
||
favorite.PosterPath = tv.PosterPath
|
||
if len(tv.FirstAirDate) >= 4 {
|
||
year, _ := strconv.Atoi(tv.FirstAirDate[:4])
|
||
favorite.Year = year
|
||
}
|
||
favorite.Rating = tv.VoteAverage
|
||
}
|
||
|
||
_, err = collection.InsertOne(context.Background(), favorite)
|
||
return err
|
||
}
|
||
|
||
// AddToFavoritesWithInfo adds media to favorites with provided media information
|
||
func (s *FavoritesService) AddToFavoritesWithInfo(userID, mediaID, mediaType string, mediaInfo *models.MediaInfo) error {
|
||
collection := s.db.Collection("favorites")
|
||
|
||
// Проверяем, не добавлен ли уже в избранное
|
||
filter := bson.M{
|
||
"userId": userID,
|
||
"mediaId": mediaID,
|
||
"mediaType": mediaType,
|
||
}
|
||
|
||
var existingFavorite models.Favorite
|
||
err := collection.FindOne(context.Background(), filter).Decode(&existingFavorite)
|
||
if err == nil {
|
||
// Уже в избранном
|
||
return nil
|
||
}
|
||
|
||
// Определяем источник данных и обрабатываем постер соответственно
|
||
var posterPath, posterUrlPreview string
|
||
|
||
if mediaInfo.PosterPath != "" {
|
||
// Проверяем, это TMDB путь (начинается с /) или полный URL от Кинопоиска
|
||
if len(mediaInfo.PosterPath) > 0 && mediaInfo.PosterPath[0] == '/' {
|
||
// TMDB путь - формируем полный URL
|
||
posterPath = fmt.Sprintf("https://image.tmdb.org/t/p/w500%s", mediaInfo.PosterPath)
|
||
} else if len(mediaInfo.PosterPath) > 10 && (mediaInfo.PosterPath[:8] == "https://" || mediaInfo.PosterPath[:7] == "http://") {
|
||
// Полный URL от Кинопоиска - извлекаем ID и формируем через API
|
||
// Пример: https://kinopoiskapiunofficial.tech/images/posters/kp_small/6605654.jpg
|
||
// Нужно получить: /api/v1/images/kp_small/6605654
|
||
posterUrlPreview = extractKinopoiskImagePath(mediaInfo.PosterPath)
|
||
posterPath = posterUrlPreview
|
||
} else {
|
||
// Другой формат - используем как есть
|
||
posterPath = mediaInfo.PosterPath
|
||
}
|
||
}
|
||
|
||
// Извлекаем год из даты
|
||
year := 0
|
||
if mediaType == "movie" && len(mediaInfo.ReleaseDate) >= 4 {
|
||
year, _ = strconv.Atoi(mediaInfo.ReleaseDate[:4])
|
||
} else if mediaType == "tv" && len(mediaInfo.FirstAirDate) >= 4 {
|
||
year, _ = strconv.Atoi(mediaInfo.FirstAirDate[:4])
|
||
}
|
||
|
||
favorite := models.Favorite{
|
||
UserID: userID,
|
||
MediaID: mediaID,
|
||
MediaType: mediaType,
|
||
Title: mediaInfo.Title,
|
||
NameRu: mediaInfo.Title,
|
||
NameEn: mediaInfo.OriginalTitle,
|
||
PosterPath: posterPath,
|
||
PosterUrlPreview: posterUrlPreview,
|
||
Year: year,
|
||
Rating: mediaInfo.VoteAverage,
|
||
CreatedAt: time.Now(),
|
||
}
|
||
|
||
_, err = collection.InsertOne(context.Background(), favorite)
|
||
return err
|
||
}
|
||
|
||
func (s *FavoritesService) RemoveFromFavorites(userID, mediaID, mediaType string) error {
|
||
collection := s.db.Collection("favorites")
|
||
|
||
filter := bson.M{
|
||
"userId": userID,
|
||
"mediaId": mediaID,
|
||
"mediaType": mediaType,
|
||
}
|
||
|
||
_, err := collection.DeleteOne(context.Background(), filter)
|
||
return err
|
||
}
|
||
|
||
func (s *FavoritesService) GetFavorites(userID string) ([]models.Favorite, error) {
|
||
collection := s.db.Collection("favorites")
|
||
|
||
filter := bson.M{
|
||
"userId": userID,
|
||
}
|
||
|
||
cursor, err := collection.Find(context.Background(), filter)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
defer cursor.Close(context.Background())
|
||
|
||
var favorites []models.Favorite
|
||
err = cursor.All(context.Background(), &favorites)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// Возвращаем пустой массив вместо nil если нет избранных
|
||
if favorites == nil {
|
||
favorites = []models.Favorite{}
|
||
}
|
||
|
||
return favorites, nil
|
||
}
|
||
|
||
func (s *FavoritesService) IsFavorite(userID, mediaID, mediaType string) (bool, error) {
|
||
collection := s.db.Collection("favorites")
|
||
|
||
filter := bson.M{
|
||
"userId": userID,
|
||
"mediaId": mediaID,
|
||
"mediaType": mediaType,
|
||
}
|
||
|
||
var favorite models.Favorite
|
||
err := collection.FindOne(context.Background(), filter).Decode(&favorite)
|
||
if err != nil {
|
||
if err == mongo.ErrNoDocuments {
|
||
return false, nil
|
||
}
|
||
return false, err
|
||
}
|
||
|
||
return true, nil
|
||
}
|
||
|
||
// extractKinopoiskImagePath извлекает путь изображения Кинопоиска и преобразует его в API путь
|
||
// Пример входа: https://kinopoiskapiunofficial.tech/images/posters/kp_small/6605654.jpg
|
||
// Пример выхода: /api/v1/images/kp_small/6605654
|
||
func extractKinopoiskImagePath(imageURL string) string {
|
||
// Ищем паттерн /images/posters/
|
||
pattern := "/images/posters/"
|
||
idx := strings.Index(imageURL, pattern)
|
||
if idx == -1 {
|
||
return imageURL
|
||
}
|
||
|
||
// Получаем часть после /images/posters/
|
||
// Например: kp_small/6605654.jpg
|
||
remainder := imageURL[idx+len(pattern):]
|
||
|
||
// Удаляем расширение файла
|
||
if lastDot := strings.LastIndex(remainder, "."); lastDot != -1 {
|
||
remainder = remainder[:lastDot]
|
||
}
|
||
|
||
// Формируем API путь
|
||
return fmt.Sprintf("/api/v1/images/%s", remainder)
|
||
}
|