Add WebTorrent Player(Experimental)

This commit is contained in:
2025-08-14 11:34:31 +00:00
parent 3d81ae0331
commit 7796e741d6
14 changed files with 1556 additions and 148 deletions

147
pkg/services/favorites.go Normal file
View File

@@ -0,0 +1,147 @@
package services
import (
"context"
"fmt"
"strconv"
"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
}
func NewFavoritesService(db *mongo.Database, tmdb *TMDBService) *FavoritesService {
return &FavoritesService{
db: db,
tmdb: tmdb,
}
}
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
}
var title, posterPath string
// Получаем информацию из TMDB в зависимости от типа медиа
mediaIDInt, err := strconv.Atoi(mediaID)
if err != nil {
return fmt.Errorf("invalid media ID: %s", mediaID)
}
if mediaType == "movie" {
movie, err := s.tmdb.GetMovie(mediaIDInt, "en-US")
if err != nil {
return err
}
title = movie.Title
posterPath = movie.PosterPath
} else if mediaType == "tv" {
tv, err := s.tmdb.GetTVShow(mediaIDInt, "en-US")
if err != nil {
return err
}
title = tv.Name
posterPath = tv.PosterPath
} else {
return fmt.Errorf("invalid media type: %s", mediaType)
}
// Формируем полный URL для постера
if posterPath != "" {
posterPath = fmt.Sprintf("https://image.tmdb.org/t/p/w500%s", posterPath)
}
favorite := models.Favorite{
UserID: userID,
MediaID: mediaID,
MediaType: mediaType,
Title: title,
PosterPath: posterPath,
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
}

View File

@@ -1,23 +1,17 @@
package services
import (
"context"
"strconv"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"neomovies-api/pkg/models"
)
type MovieService struct {
db *mongo.Database
tmdb *TMDBService
}
func NewMovieService(db *mongo.Database, tmdb *TMDBService) *MovieService {
return &MovieService{
db: db,
tmdb: tmdb,
}
}
@@ -54,56 +48,7 @@ func (s *MovieService) GetSimilar(id, page int, language string) (*models.TMDBRe
return s.tmdb.GetSimilarMovies(id, page, language)
}
func (s *MovieService) AddToFavorites(userID string, movieID string) error {
collection := s.db.Collection("users")
filter := bson.M{"_id": userID}
update := bson.M{
"$addToSet": bson.M{"favorites": movieID},
}
_, err := collection.UpdateOne(context.Background(), filter, update)
return err
}
func (s *MovieService) RemoveFromFavorites(userID string, movieID string) error {
collection := s.db.Collection("users")
filter := bson.M{"_id": userID}
update := bson.M{
"$pull": bson.M{"favorites": movieID},
}
_, err := collection.UpdateOne(context.Background(), filter, update)
return err
}
func (s *MovieService) GetFavorites(userID string, language string) ([]models.Movie, error) {
collection := s.db.Collection("users")
var user models.User
err := collection.FindOne(context.Background(), bson.M{"_id": userID}).Decode(&user)
if err != nil {
return nil, err
}
var movies []models.Movie
for _, movieIDStr := range user.Favorites {
movieID, err := strconv.Atoi(movieIDStr)
if err != nil {
continue
}
movie, err := s.tmdb.GetMovie(movieID, language)
if err != nil {
continue
}
movies = append(movies, *movie)
}
return movies, nil
}
func (s *MovieService) GetExternalIDs(id int) (*models.ExternalIDs, error) {
return s.tmdb.GetMovieExternalIDs(id)

View File

@@ -119,6 +119,11 @@ func (s *TMDBService) SearchMulti(query string, page int, language string) (*mod
return &response, nil
}
// Алиас для совместимости с новым WebTorrent handler
func (s *TMDBService) SearchTV(query string, page int, language string, firstAirDateYear int) (*models.TMDBTVResponse, error) {
return s.SearchTVShows(query, page, language, firstAirDateYear)
}
func (s *TMDBService) SearchTVShows(query string, page int, language string, firstAirDateYear int) (*models.TMDBTVResponse, error) {
params := url.Values{}
params.Set("query", query)
@@ -476,4 +481,35 @@ func (s *TMDBService) DiscoverMoviesByGenre(genreID, page int, language string)
var response models.TMDBResponse
err := s.makeRequest(endpoint, &response)
return &response, err
}
func (s *TMDBService) DiscoverTVByGenre(genreID, page int, language string) (*models.TMDBResponse, error) {
params := url.Values{}
params.Set("page", strconv.Itoa(page))
params.Set("with_genres", strconv.Itoa(genreID))
params.Set("sort_by", "popularity.desc")
if language != "" {
params.Set("language", language)
} else {
params.Set("language", "ru-RU")
}
endpoint := fmt.Sprintf("%s/discover/tv?%s", s.baseURL, params.Encode())
var response models.TMDBResponse
err := s.makeRequest(endpoint, &response)
return &response, err
}
func (s *TMDBService) GetTVSeason(tvID, seasonNumber int, language string) (*models.SeasonDetails, error) {
if language == "" {
language = "ru-RU"
}
endpoint := fmt.Sprintf("%s/tv/%d/season/%d?language=%s", s.baseURL, tvID, seasonNumber, language)
var season models.SeasonDetails
err := s.makeRequest(endpoint, &season)
return &season, err
}