diff --git a/api/index.go b/api/index.go index a16dd2f..a23a4bd 100644 --- a/api/index.go +++ b/api/index.go @@ -1,160 +1,158 @@ package handler import ( - "log" - "net/http" - "sync" + "log" + "net/http" + "sync" - "github.com/gorilla/handlers" - "github.com/gorilla/mux" - "github.com/joho/godotenv" - "go.mongodb.org/mongo-driver/mongo" + "github.com/gorilla/handlers" + "github.com/gorilla/mux" + "github.com/joho/godotenv" + "go.mongodb.org/mongo-driver/mongo" - "neomovies-api/pkg/config" - "neomovies-api/pkg/database" - handlersPkg "neomovies-api/pkg/handlers" - "neomovies-api/pkg/middleware" - "neomovies-api/pkg/services" + "neomovies-api/pkg/config" + "neomovies-api/pkg/database" + handlersPkg "neomovies-api/pkg/handlers" + "neomovies-api/pkg/middleware" + "neomovies-api/pkg/services" ) var ( - globalDB *mongo.Database - globalCfg *config.Config - initOnce sync.Once - initError error + globalDB *mongo.Database + globalCfg *config.Config + initOnce sync.Once + initError error ) func initializeApp() { - if err := godotenv.Load(); err != nil { _ = err } + if err := godotenv.Load(); err != nil { + _ = err + } - globalCfg = config.New() + globalCfg = config.New() - var err error - globalDB, err = database.Connect(globalCfg.MongoURI, globalCfg.MongoDBName) - if err != nil { - log.Printf("Failed to connect to database: %v", err) - initError = err - return - } + var err error + globalDB, err = database.Connect(globalCfg.MongoURI, globalCfg.MongoDBName) + if err != nil { + log.Printf("Failed to connect to database: %v", err) + initError = err + return + } - log.Println("Successfully connected to database") + log.Println("Successfully connected to database") } func Handler(w http.ResponseWriter, r *http.Request) { - initOnce.Do(initializeApp) + initOnce.Do(initializeApp) - if initError != nil { - log.Printf("Initialization error: %v", initError) - http.Error(w, "Application initialization failed: "+initError.Error(), http.StatusInternalServerError) - return - } + if initError != nil { + log.Printf("Initialization error: %v", initError) + http.Error(w, "Application initialization failed: "+initError.Error(), http.StatusInternalServerError) + return + } - tmdbService := services.NewTMDBService(globalCfg.TMDBAccessToken) - emailService := services.NewEmailService(globalCfg) - authService := services.NewAuthService(globalDB, globalCfg.JWTSecret, emailService, globalCfg.BaseURL, globalCfg.GoogleClientID, globalCfg.GoogleClientSecret, globalCfg.GoogleRedirectURL, globalCfg.FrontendURL) + tmdbService := services.NewTMDBService(globalCfg.TMDBAccessToken) + emailService := services.NewEmailService(globalCfg) + authService := services.NewAuthService(globalDB, globalCfg.JWTSecret, emailService, globalCfg.BaseURL, globalCfg.GoogleClientID, globalCfg.GoogleClientSecret, globalCfg.GoogleRedirectURL, globalCfg.FrontendURL) - movieService := services.NewMovieService(globalDB, tmdbService) - tvService := services.NewTVService(globalDB, tmdbService) - favoritesService := services.NewFavoritesService(globalDB, tmdbService) - torrentService := services.NewTorrentServiceWithConfig(globalCfg.RedAPIBaseURL, globalCfg.RedAPIKey) - reactionsService := services.NewReactionsService(globalDB) + movieService := services.NewMovieService(globalDB, tmdbService) + tvService := services.NewTVService(globalDB, tmdbService) + favoritesService := services.NewFavoritesService(globalDB, tmdbService) + torrentService := services.NewTorrentServiceWithConfig(globalCfg.RedAPIBaseURL, globalCfg.RedAPIKey) + reactionsService := services.NewReactionsService(globalDB) - authHandler := handlersPkg.NewAuthHandler(authService) - movieHandler := handlersPkg.NewMovieHandler(movieService) - tvHandler := handlersPkg.NewTVHandler(tvService) - favoritesHandler := handlersPkg.NewFavoritesHandler(favoritesService) - docsHandler := handlersPkg.NewDocsHandler() - searchHandler := handlersPkg.NewSearchHandler(tmdbService) - categoriesHandler := handlersPkg.NewCategoriesHandler(tmdbService) - playersHandler := handlersPkg.NewPlayersHandler(globalCfg) - webtorrentHandler := handlersPkg.NewWebTorrentHandler(tmdbService) - torrentsHandler := handlersPkg.NewTorrentsHandler(torrentService, tmdbService) - reactionsHandler := handlersPkg.NewReactionsHandler(reactionsService) - imagesHandler := handlersPkg.NewImagesHandler() + authHandler := handlersPkg.NewAuthHandler(authService) + movieHandler := handlersPkg.NewMovieHandler(movieService) + tvHandler := handlersPkg.NewTVHandler(tvService) + favoritesHandler := handlersPkg.NewFavoritesHandler(favoritesService, globalCfg) + docsHandler := handlersPkg.NewDocsHandler() + searchHandler := handlersPkg.NewSearchHandler(tmdbService) + categoriesHandler := handlersPkg.NewCategoriesHandler(tmdbService) + playersHandler := handlersPkg.NewPlayersHandler(globalCfg) + torrentsHandler := handlersPkg.NewTorrentsHandler(torrentService, tmdbService) + reactionsHandler := handlersPkg.NewReactionsHandler(reactionsService) + imagesHandler := handlersPkg.NewImagesHandler() - router := mux.NewRouter() + router := mux.NewRouter() - router.HandleFunc("/", docsHandler.ServeDocs).Methods("GET") - router.HandleFunc("/openapi.json", docsHandler.GetOpenAPISpec).Methods("GET") + router.HandleFunc("/", docsHandler.ServeDocs).Methods("GET") + router.HandleFunc("/openapi.json", docsHandler.GetOpenAPISpec).Methods("GET") - api := router.PathPrefix("/api/v1").Subrouter() + api := router.PathPrefix("/api/v1").Subrouter() - api.HandleFunc("/health", handlersPkg.HealthCheck).Methods("GET") - api.HandleFunc("/auth/register", authHandler.Register).Methods("POST") - api.HandleFunc("/auth/login", authHandler.Login).Methods("POST") - api.HandleFunc("/auth/verify", authHandler.VerifyEmail).Methods("POST") - api.HandleFunc("/auth/resend-code", authHandler.ResendVerificationCode).Methods("POST") - api.HandleFunc("/auth/google/login", authHandler.GoogleLogin).Methods("GET") - api.HandleFunc("/auth/google/callback", authHandler.GoogleCallback).Methods("GET") + api.HandleFunc("/health", handlersPkg.HealthCheck).Methods("GET") + api.HandleFunc("/auth/register", authHandler.Register).Methods("POST") + api.HandleFunc("/auth/login", authHandler.Login).Methods("POST") + api.HandleFunc("/auth/verify", authHandler.VerifyEmail).Methods("POST") + api.HandleFunc("/auth/resend-code", authHandler.ResendVerificationCode).Methods("POST") + api.HandleFunc("/auth/google/login", authHandler.GoogleLogin).Methods("GET") + api.HandleFunc("/auth/google/callback", authHandler.GoogleCallback).Methods("GET") - api.HandleFunc("/search/multi", searchHandler.MultiSearch).Methods("GET") + api.HandleFunc("/search/multi", searchHandler.MultiSearch).Methods("GET") - api.HandleFunc("/categories", categoriesHandler.GetCategories).Methods("GET") - api.HandleFunc("/categories/{id}/movies", categoriesHandler.GetMoviesByCategory).Methods("GET") - api.HandleFunc("/categories/{id}/media", categoriesHandler.GetMediaByCategory).Methods("GET") + api.HandleFunc("/categories", categoriesHandler.GetCategories).Methods("GET") + api.HandleFunc("/categories/{id}/movies", categoriesHandler.GetMoviesByCategory).Methods("GET") + api.HandleFunc("/categories/{id}/media", categoriesHandler.GetMediaByCategory).Methods("GET") - api.HandleFunc("/players/alloha/{imdb_id}", playersHandler.GetAllohaPlayer).Methods("GET") - api.HandleFunc("/players/lumex/{imdb_id}", playersHandler.GetLumexPlayer).Methods("GET") - api.HandleFunc("/players/vibix/{imdb_id}", playersHandler.GetVibixPlayer).Methods("GET") + api.HandleFunc("/players/alloha/{imdb_id}", playersHandler.GetAllohaPlayer).Methods("GET") + api.HandleFunc("/players/lumex/{imdb_id}", playersHandler.GetLumexPlayer).Methods("GET") + api.HandleFunc("/players/vibix/{imdb_id}", playersHandler.GetVibixPlayer).Methods("GET") - api.HandleFunc("/webtorrent/player", webtorrentHandler.OpenPlayer).Methods("GET") - api.HandleFunc("/webtorrent/metadata", webtorrentHandler.GetMetadata).Methods("GET") + api.HandleFunc("/torrents/search/{imdbId}", torrentsHandler.SearchTorrents).Methods("GET") + api.HandleFunc("/torrents/movies", torrentsHandler.SearchMovies).Methods("GET") + api.HandleFunc("/torrents/series", torrentsHandler.SearchSeries).Methods("GET") + api.HandleFunc("/torrents/anime", torrentsHandler.SearchAnime).Methods("GET") + api.HandleFunc("/torrents/seasons", torrentsHandler.GetAvailableSeasons).Methods("GET") + api.HandleFunc("/torrents/search", torrentsHandler.SearchByQuery).Methods("GET") - api.HandleFunc("/torrents/search/{imdbId}", torrentsHandler.SearchTorrents).Methods("GET") - api.HandleFunc("/torrents/movies", torrentsHandler.SearchMovies).Methods("GET") - api.HandleFunc("/torrents/series", torrentsHandler.SearchSeries).Methods("GET") - api.HandleFunc("/torrents/anime", torrentsHandler.SearchAnime).Methods("GET") - api.HandleFunc("/torrents/seasons", torrentsHandler.GetAvailableSeasons).Methods("GET") - api.HandleFunc("/torrents/search", torrentsHandler.SearchByQuery).Methods("GET") - - api.HandleFunc("/reactions/{mediaType}/{mediaId}/counts", reactionsHandler.GetReactionCounts).Methods("GET") + api.HandleFunc("/reactions/{mediaType}/{mediaId}/counts", reactionsHandler.GetReactionCounts).Methods("GET") - api.HandleFunc("/images/{size}/{path:.*}", imagesHandler.GetImage).Methods("GET") + api.HandleFunc("/images/{size}/{path:.*}", imagesHandler.GetImage).Methods("GET") - api.HandleFunc("/movies/search", movieHandler.Search).Methods("GET") - api.HandleFunc("/movies/popular", movieHandler.Popular).Methods("GET") - api.HandleFunc("/movies/top-rated", movieHandler.TopRated).Methods("GET") - api.HandleFunc("/movies/upcoming", movieHandler.Upcoming).Methods("GET") - api.HandleFunc("/movies/now-playing", movieHandler.NowPlaying).Methods("GET") - api.HandleFunc("/movies/{id}", movieHandler.GetByID).Methods("GET") - api.HandleFunc("/movies/{id}/recommendations", movieHandler.GetRecommendations).Methods("GET") - api.HandleFunc("/movies/{id}/similar", movieHandler.GetSimilar).Methods("GET") - api.HandleFunc("/movies/{id}/external-ids", movieHandler.GetExternalIDs).Methods("GET") + api.HandleFunc("/movies/search", movieHandler.Search).Methods("GET") + api.HandleFunc("/movies/popular", movieHandler.Popular).Methods("GET") + api.HandleFunc("/movies/top-rated", movieHandler.TopRated).Methods("GET") + api.HandleFunc("/movies/upcoming", movieHandler.Upcoming).Methods("GET") + api.HandleFunc("/movies/now-playing", movieHandler.NowPlaying).Methods("GET") + api.HandleFunc("/movies/{id}", movieHandler.GetByID).Methods("GET") + api.HandleFunc("/movies/{id}/recommendations", movieHandler.GetRecommendations).Methods("GET") + api.HandleFunc("/movies/{id}/similar", movieHandler.GetSimilar).Methods("GET") + api.HandleFunc("/movies/{id}/external-ids", movieHandler.GetExternalIDs).Methods("GET") - api.HandleFunc("/tv/search", tvHandler.Search).Methods("GET") - api.HandleFunc("/tv/popular", tvHandler.Popular).Methods("GET") - api.HandleFunc("/tv/top-rated", tvHandler.TopRated).Methods("GET") - api.HandleFunc("/tv/on-the-air", tvHandler.OnTheAir).Methods("GET") - api.HandleFunc("/tv/airing-today", tvHandler.AiringToday).Methods("GET") - api.HandleFunc("/tv/{id}", tvHandler.GetByID).Methods("GET") - api.HandleFunc("/tv/{id}/recommendations", tvHandler.GetRecommendations).Methods("GET") - api.HandleFunc("/tv/{id}/similar", tvHandler.GetSimilar).Methods("GET") - api.HandleFunc("/tv/{id}/external-ids", tvHandler.GetExternalIDs).Methods("GET") + api.HandleFunc("/tv/search", tvHandler.Search).Methods("GET") + api.HandleFunc("/tv/popular", tvHandler.Popular).Methods("GET") + api.HandleFunc("/tv/top-rated", tvHandler.TopRated).Methods("GET") + api.HandleFunc("/tv/on-the-air", tvHandler.OnTheAir).Methods("GET") + api.HandleFunc("/tv/airing-today", tvHandler.AiringToday).Methods("GET") + api.HandleFunc("/tv/{id}", tvHandler.GetByID).Methods("GET") + api.HandleFunc("/tv/{id}/recommendations", tvHandler.GetRecommendations).Methods("GET") + api.HandleFunc("/tv/{id}/similar", tvHandler.GetSimilar).Methods("GET") + api.HandleFunc("/tv/{id}/external-ids", tvHandler.GetExternalIDs).Methods("GET") - protected := api.PathPrefix("").Subrouter() - protected.Use(middleware.JWTAuth(globalCfg.JWTSecret)) + protected := api.PathPrefix("").Subrouter() + protected.Use(middleware.JWTAuth(globalCfg.JWTSecret)) - protected.HandleFunc("/favorites", favoritesHandler.GetFavorites).Methods("GET") - protected.HandleFunc("/favorites/{id}", favoritesHandler.AddToFavorites).Methods("POST") - protected.HandleFunc("/favorites/{id}", favoritesHandler.RemoveFromFavorites).Methods("DELETE") - protected.HandleFunc("/favorites/{id}/check", favoritesHandler.CheckIsFavorite).Methods("GET") + protected.HandleFunc("/favorites", favoritesHandler.GetFavorites).Methods("GET") + protected.HandleFunc("/favorites/{id}", favoritesHandler.AddToFavorites).Methods("POST") + protected.HandleFunc("/favorites/{id}", favoritesHandler.RemoveFromFavorites).Methods("DELETE") + protected.HandleFunc("/favorites/{id}/check", favoritesHandler.CheckIsFavorite).Methods("GET") - protected.HandleFunc("/auth/profile", authHandler.GetProfile).Methods("GET") - protected.HandleFunc("/auth/profile", authHandler.UpdateProfile).Methods("PUT") - protected.HandleFunc("/auth/profile", authHandler.DeleteAccount).Methods("DELETE") - - protected.HandleFunc("/reactions/{mediaType}/{mediaId}/my-reaction", reactionsHandler.GetMyReaction).Methods("GET") - protected.HandleFunc("/reactions/{mediaType}/{mediaId}", reactionsHandler.SetReaction).Methods("POST") - protected.HandleFunc("/reactions/{mediaType}/{mediaId}", reactionsHandler.RemoveReaction).Methods("DELETE") - protected.HandleFunc("/reactions/my", reactionsHandler.GetMyReactions).Methods("GET") + protected.HandleFunc("/auth/profile", authHandler.GetProfile).Methods("GET") + protected.HandleFunc("/auth/profile", authHandler.UpdateProfile).Methods("PUT") + protected.HandleFunc("/auth/profile", authHandler.DeleteAccount).Methods("DELETE") - corsHandler := handlers.CORS( - handlers.AllowedOrigins([]string{"*"}), - handlers.AllowedMethods([]string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}), - handlers.AllowedHeaders([]string{"Authorization", "Content-Type", "Accept", "Origin", "X-Requested-With", "X-CSRF-Token"}), - handlers.AllowCredentials(), - handlers.ExposedHeaders([]string{"Authorization", "Content-Type"}), - ) + protected.HandleFunc("/reactions/{mediaType}/{mediaId}/my-reaction", reactionsHandler.GetMyReaction).Methods("GET") + protected.HandleFunc("/reactions/{mediaType}/{mediaId}", reactionsHandler.SetReaction).Methods("POST") + protected.HandleFunc("/reactions/{mediaType}/{mediaId}", reactionsHandler.RemoveReaction).Methods("DELETE") + protected.HandleFunc("/reactions/my", reactionsHandler.GetMyReactions).Methods("GET") - corsHandler(router).ServeHTTP(w, r) -} \ No newline at end of file + corsHandler := handlers.CORS( + handlers.AllowedOrigins([]string{"*"}), + handlers.AllowedMethods([]string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}), + handlers.AllowedHeaders([]string{"Authorization", "Content-Type", "Accept", "Origin", "X-Requested-With", "X-CSRF-Token"}), + handlers.AllowCredentials(), + handlers.ExposedHeaders([]string{"Authorization", "Content-Type"}), + ) + + corsHandler(router).ServeHTTP(w, r) +} diff --git a/main.go b/main.go index 9e11250..28208af 100644 --- a/main.go +++ b/main.go @@ -18,7 +18,9 @@ import ( ) func main() { - if err := godotenv.Load(); err != nil { _ = err } + if err := godotenv.Load(); err != nil { + _ = err + } cfg := config.New() @@ -42,12 +44,11 @@ func main() { authHandler := appHandlers.NewAuthHandler(authService) movieHandler := appHandlers.NewMovieHandler(movieService) tvHandler := appHandlers.NewTVHandler(tvService) - favoritesHandler := appHandlers.NewFavoritesHandler(favoritesService) + favoritesHandler := appHandlers.NewFavoritesHandler(favoritesService, cfg) docsHandler := appHandlers.NewDocsHandler() searchHandler := appHandlers.NewSearchHandler(tmdbService) categoriesHandler := appHandlers.NewCategoriesHandler(tmdbService) playersHandler := appHandlers.NewPlayersHandler(cfg) - webtorrentHandler := appHandlers.NewWebTorrentHandler(tmdbService) torrentsHandler := appHandlers.NewTorrentsHandler(torrentService, tmdbService) reactionsHandler := appHandlers.NewReactionsHandler(reactionsService) imagesHandler := appHandlers.NewImagesHandler() @@ -75,10 +76,7 @@ func main() { api.HandleFunc("/players/alloha/{imdb_id}", playersHandler.GetAllohaPlayer).Methods("GET") api.HandleFunc("/players/lumex/{imdb_id}", playersHandler.GetLumexPlayer).Methods("GET") - api.HandleFunc("/players/vibix/{imdb_id}", playersHandler.GetVibixPlayer).Methods("GET") - - api.HandleFunc("/webtorrent/player", webtorrentHandler.OpenPlayer).Methods("GET") - api.HandleFunc("/webtorrent/metadata", webtorrentHandler.GetMetadata).Methods("GET") + api.HandleFunc("/players/vibix/{imdb_id}", playersHandler.GetVibixPlayer).Methods("GET") api.HandleFunc("/torrents/search/{imdbId}", torrentsHandler.SearchTorrents).Methods("GET") api.HandleFunc("/torrents/movies", torrentsHandler.SearchMovies).Methods("GET") @@ -154,10 +152,12 @@ func main() { } port := cfg.Port - if port == "" { port = "3000" } + if port == "" { + port = "3000" + } if err := http.ListenAndServe(":"+port, finalHandler); err != nil { fmt.Printf("❌ Server failed to start: %v\n", err) os.Exit(1) } -} \ No newline at end of file +} diff --git a/pkg/config/config.go b/pkg/config/config.go index eda0414..b05d585 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -6,46 +6,50 @@ import ( ) type Config struct { - MongoURI string - MongoDBName string - TMDBAccessToken string - JWTSecret string - Port string - BaseURL string - NodeEnv string - GmailUser string - GmailPassword string - LumexURL string - AllohaToken string - RedAPIBaseURL string - RedAPIKey string - GoogleClientID string + MongoURI string + MongoDBName string + TMDBAccessToken string + JWTSecret string + Port string + BaseURL string + NodeEnv string + GmailUser string + GmailPassword string + LumexURL string + AllohaToken string + RedAPIBaseURL string + RedAPIKey string + GoogleClientID string GoogleClientSecret string GoogleRedirectURL string FrontendURL string + VibixHost string + VibixToken string } func New() *Config { mongoURI := getMongoURI() return &Config{ - MongoURI: mongoURI, - MongoDBName: getEnv(EnvMongoDBName, DefaultMongoDBName), - TMDBAccessToken: getEnv(EnvTMDBAccessToken, ""), - JWTSecret: getEnv(EnvJWTSecret, DefaultJWTSecret), - Port: getEnv(EnvPort, DefaultPort), - BaseURL: getEnv(EnvBaseURL, DefaultBaseURL), - NodeEnv: getEnv(EnvNodeEnv, DefaultNodeEnv), - GmailUser: getEnv(EnvGmailUser, ""), - GmailPassword: getEnv(EnvGmailPassword, ""), - LumexURL: getEnv(EnvLumexURL, ""), - AllohaToken: getEnv(EnvAllohaToken, ""), - RedAPIBaseURL: getEnv(EnvRedAPIBaseURL, DefaultRedAPIBase), - RedAPIKey: getEnv(EnvRedAPIKey, ""), - GoogleClientID: getEnv(EnvGoogleClientID, ""), + MongoURI: mongoURI, + MongoDBName: getEnv(EnvMongoDBName, DefaultMongoDBName), + TMDBAccessToken: getEnv(EnvTMDBAccessToken, ""), + JWTSecret: getEnv(EnvJWTSecret, DefaultJWTSecret), + Port: getEnv(EnvPort, DefaultPort), + BaseURL: getEnv(EnvBaseURL, DefaultBaseURL), + NodeEnv: getEnv(EnvNodeEnv, DefaultNodeEnv), + GmailUser: getEnv(EnvGmailUser, ""), + GmailPassword: getEnv(EnvGmailPassword, ""), + LumexURL: getEnv(EnvLumexURL, ""), + AllohaToken: getEnv(EnvAllohaToken, ""), + RedAPIBaseURL: getEnv(EnvRedAPIBaseURL, DefaultRedAPIBase), + RedAPIKey: getEnv(EnvRedAPIKey, ""), + GoogleClientID: getEnv(EnvGoogleClientID, ""), GoogleClientSecret: getEnv(EnvGoogleClientSecret, ""), GoogleRedirectURL: getEnv(EnvGoogleRedirectURL, ""), FrontendURL: getEnv(EnvFrontendURL, ""), + VibixHost: getEnv(EnvVibixHost, DefaultVibixHost), + VibixToken: getEnv(EnvVibixToken, ""), } } @@ -65,4 +69,4 @@ func getEnv(key, defaultValue string) string { return value } return defaultValue -} \ No newline at end of file +} diff --git a/pkg/handlers/favorites.go b/pkg/handlers/favorites.go index 858dd62..7fc42f7 100644 --- a/pkg/handlers/favorites.go +++ b/pkg/handlers/favorites.go @@ -8,10 +8,10 @@ import ( "github.com/gorilla/mux" + "neomovies-api/pkg/config" "neomovies-api/pkg/middleware" "neomovies-api/pkg/models" "neomovies-api/pkg/services" - "neomovies-api/pkg/config" ) type FavoritesHandler struct { @@ -22,26 +22,10 @@ type FavoritesHandler struct { func NewFavoritesHandler(favoritesService *services.FavoritesService, cfg *config.Config) *FavoritesHandler { return &FavoritesHandler{ favoritesService: favoritesService, - config: cfg, + config: cfg, } } -type MediaInfo struct { - ID string `json:"id"` - Title string `json:"title"` - OriginalTitle string `json:"original_title,omitempty"` - Overview string `json:"overview"` - PosterPath string `json:"poster_path"` - BackdropPath string `json:"backdrop_path"` - ReleaseDate string `json:"release_date,omitempty"` - FirstAirDate string `json:"first_air_date,omitempty"` - VoteAverage float64 `json:"vote_average"` - VoteCount int `json:"vote_count"` - MediaType string `json:"media_type"` - Popularity float64 `json:"popularity"` - GenreIDs []int `json:"genre_ids"` -} - func (h *FavoritesHandler) GetFavorites(w http.ResponseWriter, r *http.Request) { userID, ok := middleware.GetUserIDFromContext(r.Context()) if !ok { @@ -73,16 +57,16 @@ func (h *FavoritesHandler) AddToFavorites(w http.ResponseWriter, r *http.Request vars := mux.Vars(r) mediaID := vars["id"] mediaType := r.URL.Query().Get("type") - + if mediaID == "" { http.Error(w, "Media ID is required", http.StatusBadRequest) return } - + if mediaType == "" { mediaType = "movie" // По умолчанию фильм для обратной совместимости } - + if mediaType != "movie" && mediaType != "tv" { http.Error(w, "Media type must be 'movie' or 'tv'", http.StatusBadRequest) return @@ -118,16 +102,16 @@ func (h *FavoritesHandler) RemoveFromFavorites(w http.ResponseWriter, r *http.Re vars := mux.Vars(r) mediaID := vars["id"] mediaType := r.URL.Query().Get("type") - + if mediaID == "" { http.Error(w, "Media ID is required", http.StatusBadRequest) return } - + if mediaType == "" { mediaType = "movie" // По умолчанию фильм для обратной совместимости } - + if mediaType != "movie" && mediaType != "tv" { http.Error(w, "Media type must be 'movie' or 'tv'", http.StatusBadRequest) return @@ -156,16 +140,16 @@ func (h *FavoritesHandler) CheckIsFavorite(w http.ResponseWriter, r *http.Reques vars := mux.Vars(r) mediaID := vars["id"] mediaType := r.URL.Query().Get("type") - + if mediaID == "" { http.Error(w, "Media ID is required", http.StatusBadRequest) return } - + if mediaType == "" { mediaType = "movie" // По умолчанию фильм для обратной совместимости } - + if mediaType != "movie" && mediaType != "tv" { http.Error(w, "Media type must be 'movie' or 'tv'", http.StatusBadRequest) return @@ -185,12 +169,12 @@ func (h *FavoritesHandler) CheckIsFavorite(w http.ResponseWriter, r *http.Reques } // fetchMediaInfoRussian получает информацию о медиа на русском языке из TMDB -func (h *FavoritesHandler) fetchMediaInfoRussian(mediaID, mediaType string) (*MediaInfo, error) { +func (h *FavoritesHandler) fetchMediaInfoRussian(mediaID, mediaType string) (*models.MediaInfo, error) { var url string if mediaType == "movie" { - url = fmt.Sprintf("https://api.themoviedb.org/3/movie/%s?api_key=%s&language=ru-RU", mediaID, h.config.TMDBAPIKey) + url = fmt.Sprintf("https://api.themoviedb.org/3/movie/%s?api_key=%s&language=ru-RU", mediaID, h.config.TMDBAccessToken) } else { - url = fmt.Sprintf("https://api.themoviedb.org/3/tv/%s?api_key=%s&language=ru-RU", mediaID, h.config.TMDBAPIKey) + url = fmt.Sprintf("https://api.themoviedb.org/3/tv/%s?api_key=%s&language=ru-RU", mediaID, h.config.TMDBAccessToken) } resp, err := http.Get(url) @@ -213,7 +197,7 @@ func (h *FavoritesHandler) fetchMediaInfoRussian(mediaID, mediaType string) (*Me return nil, fmt.Errorf("failed to parse TMDB response: %w", err) } - mediaInfo := &MediaInfo{ + mediaInfo := &models.MediaInfo{ ID: mediaID, MediaType: mediaType, } @@ -273,4 +257,4 @@ func (h *FavoritesHandler) fetchMediaInfoRussian(mediaID, mediaType string) (*Me } return mediaInfo, nil -} \ No newline at end of file +} diff --git a/pkg/handlers/webtorrent.go b/pkg/handlers/webtorrent.go deleted file mode 100644 index 117e28f..0000000 --- a/pkg/handlers/webtorrent.go +++ /dev/null @@ -1,578 +0,0 @@ -package handlers - -import ( - "encoding/json" - "html/template" - "net/http" - "net/url" - "strconv" - - "neomovies-api/pkg/models" - "neomovies-api/pkg/services" -) - -type WebTorrentHandler struct { - tmdbService *services.TMDBService -} - -func NewWebTorrentHandler(tmdbService *services.TMDBService) *WebTorrentHandler { - return &WebTorrentHandler{ - tmdbService: tmdbService, - } -} - -// Структура для ответа с метаданными -type MediaMetadata struct { - ID int `json:"id"` - Title string `json:"title"` - Type string `json:"type"` // "movie" or "tv" - Year int `json:"year,omitempty"` - PosterPath string `json:"posterPath,omitempty"` - BackdropPath string `json:"backdropPath,omitempty"` - Overview string `json:"overview,omitempty"` - Seasons []SeasonMetadata `json:"seasons,omitempty"` - Episodes []EpisodeMetadata `json:"episodes,omitempty"` - Runtime int `json:"runtime,omitempty"` - Genres []models.Genre `json:"genres,omitempty"` -} - -type SeasonMetadata struct { - SeasonNumber int `json:"seasonNumber"` - Name string `json:"name"` - Episodes []EpisodeMetadata `json:"episodes"` -} - -type EpisodeMetadata struct { - EpisodeNumber int `json:"episodeNumber"` - SeasonNumber int `json:"seasonNumber"` - Name string `json:"name"` - Overview string `json:"overview,omitempty"` - Runtime int `json:"runtime,omitempty"` - StillPath string `json:"stillPath,omitempty"` -} - -// Открытие плеера с магнет ссылкой -func (h *WebTorrentHandler) OpenPlayer(w http.ResponseWriter, r *http.Request) { - magnetLink := r.Header.Get("X-Magnet-Link") - if magnetLink == "" { - magnetLink = r.URL.Query().Get("magnet") - } - - if magnetLink == "" { - http.Error(w, "Magnet link is required", http.StatusBadRequest) - return - } - - // Декодируем magnet ссылку если она закодирована - decodedMagnet, err := url.QueryUnescape(magnetLink) - if err != nil { - decodedMagnet = magnetLink - } - - // Отдаем HTML страницу с плеером - tmpl := ` - -
- - -