2025-08-07 13:47:42 +00:00
|
|
|
|
package services
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"encoding/json"
|
|
|
|
|
|
"fmt"
|
|
|
|
|
|
"net/http"
|
|
|
|
|
|
"net/url"
|
|
|
|
|
|
"strconv"
|
2025-10-19 08:30:16 +00:00
|
|
|
|
"strings"
|
2025-08-07 13:47:42 +00:00
|
|
|
|
|
|
|
|
|
|
"neomovies-api/pkg/models"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
type TMDBService struct {
|
|
|
|
|
|
accessToken string
|
|
|
|
|
|
baseURL string
|
|
|
|
|
|
client *http.Client
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func NewTMDBService(accessToken string) *TMDBService {
|
|
|
|
|
|
return &TMDBService{
|
|
|
|
|
|
accessToken: accessToken,
|
|
|
|
|
|
baseURL: "https://api.themoviedb.org/3",
|
|
|
|
|
|
client: &http.Client{},
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *TMDBService) makeRequest(endpoint string, target interface{}) error {
|
|
|
|
|
|
req, err := http.NewRequest("GET", endpoint, nil)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Используем Bearer токен вместо API key в query параметрах
|
|
|
|
|
|
req.Header.Set("Authorization", "Bearer "+s.accessToken)
|
|
|
|
|
|
req.Header.Set("Accept", "application/json")
|
|
|
|
|
|
|
|
|
|
|
|
resp, err := s.client.Do(req)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
|
|
if resp.StatusCode != http.StatusOK {
|
|
|
|
|
|
return fmt.Errorf("TMDB API error: %d", resp.StatusCode)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return json.NewDecoder(resp.Body).Decode(target)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *TMDBService) SearchMovies(query string, page int, language, region string, year int) (*models.TMDBResponse, error) {
|
|
|
|
|
|
params := url.Values{}
|
|
|
|
|
|
params.Set("query", query)
|
|
|
|
|
|
params.Set("page", strconv.Itoa(page))
|
|
|
|
|
|
params.Set("include_adult", "false")
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
if language != "" {
|
|
|
|
|
|
params.Set("language", language)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
params.Set("language", "ru-RU")
|
|
|
|
|
|
}
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
if region != "" {
|
|
|
|
|
|
params.Set("region", region)
|
|
|
|
|
|
}
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
if year > 0 {
|
|
|
|
|
|
params.Set("year", strconv.Itoa(year))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
endpoint := fmt.Sprintf("%s/search/movie?%s", s.baseURL, params.Encode())
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
var response models.TMDBResponse
|
|
|
|
|
|
err := s.makeRequest(endpoint, &response)
|
|
|
|
|
|
return &response, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *TMDBService) SearchMulti(query string, page int, language string) (*models.MultiSearchResponse, error) {
|
|
|
|
|
|
params := url.Values{}
|
|
|
|
|
|
params.Set("query", query)
|
|
|
|
|
|
params.Set("page", strconv.Itoa(page))
|
|
|
|
|
|
params.Set("include_adult", "false")
|
|
|
|
|
|
|
|
|
|
|
|
if language != "" {
|
|
|
|
|
|
params.Set("language", language)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
params.Set("language", "ru-RU")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
endpoint := fmt.Sprintf("%s/search/multi?%s", s.baseURL, params.Encode())
|
|
|
|
|
|
|
|
|
|
|
|
var response models.MultiSearchResponse
|
|
|
|
|
|
err := s.makeRequest(endpoint, &response)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Фильтруем результаты: убираем "person", и без названия
|
|
|
|
|
|
filteredResults := make([]models.MultiSearchResult, 0)
|
|
|
|
|
|
for _, result := range response.Results {
|
|
|
|
|
|
if result.MediaType == "person" {
|
|
|
|
|
|
continue
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
hasTitle := false
|
|
|
|
|
|
if result.MediaType == "movie" && result.Title != "" {
|
|
|
|
|
|
hasTitle = true
|
|
|
|
|
|
} else if result.MediaType == "tv" && result.Name != "" {
|
|
|
|
|
|
hasTitle = true
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if hasTitle {
|
|
|
|
|
|
filteredResults = append(filteredResults, result)
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
response.Results = filteredResults
|
|
|
|
|
|
response.TotalResults = len(filteredResults)
|
|
|
|
|
|
|
|
|
|
|
|
return &response, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-14 11:34:31 +00:00
|
|
|
|
// Алиас для совместимости с новым WebTorrent handler
|
|
|
|
|
|
func (s *TMDBService) SearchTV(query string, page int, language string, firstAirDateYear int) (*models.TMDBTVResponse, error) {
|
|
|
|
|
|
return s.SearchTVShows(query, page, language, firstAirDateYear)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
func (s *TMDBService) SearchTVShows(query string, page int, language string, firstAirDateYear int) (*models.TMDBTVResponse, error) {
|
|
|
|
|
|
params := url.Values{}
|
|
|
|
|
|
params.Set("query", query)
|
|
|
|
|
|
params.Set("page", strconv.Itoa(page))
|
|
|
|
|
|
params.Set("include_adult", "false")
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
if language != "" {
|
|
|
|
|
|
params.Set("language", language)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
params.Set("language", "ru-RU")
|
|
|
|
|
|
}
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
if firstAirDateYear > 0 {
|
|
|
|
|
|
params.Set("first_air_date_year", strconv.Itoa(firstAirDateYear))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
endpoint := fmt.Sprintf("%s/search/tv?%s", s.baseURL, params.Encode())
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
var response models.TMDBTVResponse
|
|
|
|
|
|
err := s.makeRequest(endpoint, &response)
|
|
|
|
|
|
return &response, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *TMDBService) GetMovie(id int, language string) (*models.Movie, error) {
|
|
|
|
|
|
params := url.Values{}
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
if language != "" {
|
|
|
|
|
|
params.Set("language", language)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
params.Set("language", "ru-RU")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
endpoint := fmt.Sprintf("%s/movie/%d?%s", s.baseURL, id, params.Encode())
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
var movie models.Movie
|
|
|
|
|
|
err := s.makeRequest(endpoint, &movie)
|
|
|
|
|
|
return &movie, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *TMDBService) GetTVShow(id int, language string) (*models.TVShow, error) {
|
|
|
|
|
|
params := url.Values{}
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
if language != "" {
|
|
|
|
|
|
params.Set("language", language)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
params.Set("language", "ru-RU")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
endpoint := fmt.Sprintf("%s/tv/%d?%s", s.baseURL, id, params.Encode())
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
var tvShow models.TVShow
|
|
|
|
|
|
err := s.makeRequest(endpoint, &tvShow)
|
|
|
|
|
|
return &tvShow, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-10-19 08:30:16 +00:00
|
|
|
|
// Map TMDB movie to unified content with prefixed IDs. Requires optional external IDs for imdbId.
|
|
|
|
|
|
func MapTMDBToUnifiedMovie(movie *models.Movie, external *models.ExternalIDs) *models.UnifiedContent {
|
|
|
|
|
|
if movie == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
genres := make([]models.UnifiedGenre, 0, len(movie.Genres))
|
|
|
|
|
|
for _, g := range movie.Genres {
|
|
|
|
|
|
name := strings.TrimSpace(g.Name)
|
|
|
|
|
|
id := strings.ToLower(strings.ReplaceAll(name, " ", "-"))
|
|
|
|
|
|
if id == "" {
|
|
|
|
|
|
id = strconv.Itoa(g.ID)
|
|
|
|
|
|
}
|
|
|
|
|
|
genres = append(genres, models.UnifiedGenre{ID: id, Name: name})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var imdb string
|
|
|
|
|
|
if external != nil {
|
|
|
|
|
|
imdb = external.IMDbID
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var budgetPtr *int64
|
|
|
|
|
|
if movie.Budget > 0 {
|
|
|
|
|
|
v := movie.Budget
|
|
|
|
|
|
budgetPtr = &v
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var revenuePtr *int64
|
|
|
|
|
|
if movie.Revenue > 0 {
|
|
|
|
|
|
v := movie.Revenue
|
|
|
|
|
|
revenuePtr = &v
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ext := models.UnifiedExternalIDs{
|
|
|
|
|
|
KP: nil,
|
|
|
|
|
|
TMDB: &movie.ID,
|
|
|
|
|
|
IMDb: imdb,
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return &models.UnifiedContent{
|
|
|
|
|
|
ID: strconv.Itoa(movie.ID),
|
|
|
|
|
|
SourceID: "tmdb_" + strconv.Itoa(movie.ID),
|
|
|
|
|
|
Title: movie.Title,
|
|
|
|
|
|
OriginalTitle: movie.OriginalTitle,
|
|
|
|
|
|
Description: movie.Overview,
|
|
|
|
|
|
ReleaseDate: movie.ReleaseDate,
|
|
|
|
|
|
EndDate: nil,
|
|
|
|
|
|
Type: "movie",
|
|
|
|
|
|
Genres: genres,
|
|
|
|
|
|
Rating: movie.VoteAverage,
|
|
|
|
|
|
PosterURL: movie.PosterPath,
|
|
|
|
|
|
BackdropURL: movie.BackdropPath,
|
|
|
|
|
|
Director: "",
|
|
|
|
|
|
Cast: []models.UnifiedCastMember{},
|
|
|
|
|
|
Duration: movie.Runtime,
|
|
|
|
|
|
Country: firstCountry(movie.ProductionCountries),
|
|
|
|
|
|
Language: movie.OriginalLanguage,
|
|
|
|
|
|
Budget: budgetPtr,
|
|
|
|
|
|
Revenue: revenuePtr,
|
|
|
|
|
|
IMDbID: imdb,
|
|
|
|
|
|
ExternalIDs: ext,
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func firstCountry(countries []models.ProductionCountry) string {
|
|
|
|
|
|
if len(countries) == 0 {
|
|
|
|
|
|
return ""
|
|
|
|
|
|
}
|
|
|
|
|
|
if strings.TrimSpace(countries[0].Name) != "" {
|
|
|
|
|
|
return countries[0].Name
|
|
|
|
|
|
}
|
|
|
|
|
|
return countries[0].ISO31661
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
func (s *TMDBService) GetGenres(mediaType string, language string) (*models.GenresResponse, error) {
|
|
|
|
|
|
params := url.Values{}
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
if language != "" {
|
|
|
|
|
|
params.Set("language", language)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
params.Set("language", "ru-RU")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
endpoint := fmt.Sprintf("%s/genre/%s/list?%s", s.baseURL, mediaType, params.Encode())
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
var response models.GenresResponse
|
|
|
|
|
|
err := s.makeRequest(endpoint, &response)
|
|
|
|
|
|
return &response, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *TMDBService) GetAllGenres() (*models.GenresResponse, error) {
|
|
|
|
|
|
// Получаем жанры фильмов
|
|
|
|
|
|
movieGenres, err := s.GetGenres("movie", "ru-RU")
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Получаем жанры сериалов
|
|
|
|
|
|
tvGenres, err := s.GetGenres("tv", "ru-RU")
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Объединяем жанры, убирая дубликаты
|
|
|
|
|
|
allGenres := make(map[int]models.Genre)
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
for _, genre := range movieGenres.Genres {
|
|
|
|
|
|
allGenres[genre.ID] = genre
|
|
|
|
|
|
}
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
for _, genre := range tvGenres.Genres {
|
|
|
|
|
|
allGenres[genre.ID] = genre
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Преобразуем обратно в слайс
|
|
|
|
|
|
var genres []models.Genre
|
|
|
|
|
|
for _, genre := range allGenres {
|
|
|
|
|
|
genres = append(genres, genre)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return &models.GenresResponse{Genres: genres}, nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *TMDBService) GetPopularMovies(page int, language, region string) (*models.TMDBResponse, error) {
|
|
|
|
|
|
params := url.Values{}
|
|
|
|
|
|
params.Set("page", strconv.Itoa(page))
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
if language != "" {
|
|
|
|
|
|
params.Set("language", language)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
params.Set("language", "ru-RU")
|
|
|
|
|
|
}
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
if region != "" {
|
|
|
|
|
|
params.Set("region", region)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
endpoint := fmt.Sprintf("%s/movie/popular?%s", s.baseURL, params.Encode())
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
var response models.TMDBResponse
|
|
|
|
|
|
err := s.makeRequest(endpoint, &response)
|
|
|
|
|
|
return &response, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *TMDBService) GetTopRatedMovies(page int, language, region string) (*models.TMDBResponse, error) {
|
|
|
|
|
|
params := url.Values{}
|
|
|
|
|
|
params.Set("page", strconv.Itoa(page))
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
if language != "" {
|
|
|
|
|
|
params.Set("language", language)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
params.Set("language", "ru-RU")
|
|
|
|
|
|
}
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
if region != "" {
|
|
|
|
|
|
params.Set("region", region)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
endpoint := fmt.Sprintf("%s/movie/top_rated?%s", s.baseURL, params.Encode())
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
var response models.TMDBResponse
|
|
|
|
|
|
err := s.makeRequest(endpoint, &response)
|
|
|
|
|
|
return &response, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *TMDBService) GetUpcomingMovies(page int, language, region string) (*models.TMDBResponse, error) {
|
|
|
|
|
|
params := url.Values{}
|
|
|
|
|
|
params.Set("page", strconv.Itoa(page))
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
if language != "" {
|
|
|
|
|
|
params.Set("language", language)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
params.Set("language", "ru-RU")
|
|
|
|
|
|
}
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
if region != "" {
|
|
|
|
|
|
params.Set("region", region)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
endpoint := fmt.Sprintf("%s/movie/upcoming?%s", s.baseURL, params.Encode())
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
var response models.TMDBResponse
|
|
|
|
|
|
err := s.makeRequest(endpoint, &response)
|
|
|
|
|
|
return &response, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *TMDBService) GetNowPlayingMovies(page int, language, region string) (*models.TMDBResponse, error) {
|
|
|
|
|
|
params := url.Values{}
|
|
|
|
|
|
params.Set("page", strconv.Itoa(page))
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
if language != "" {
|
|
|
|
|
|
params.Set("language", language)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
params.Set("language", "ru-RU")
|
|
|
|
|
|
}
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
if region != "" {
|
|
|
|
|
|
params.Set("region", region)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
endpoint := fmt.Sprintf("%s/movie/now_playing?%s", s.baseURL, params.Encode())
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
var response models.TMDBResponse
|
|
|
|
|
|
err := s.makeRequest(endpoint, &response)
|
|
|
|
|
|
return &response, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *TMDBService) GetMovieRecommendations(id, page int, language string) (*models.TMDBResponse, error) {
|
|
|
|
|
|
params := url.Values{}
|
|
|
|
|
|
params.Set("page", strconv.Itoa(page))
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
if language != "" {
|
|
|
|
|
|
params.Set("language", language)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
params.Set("language", "ru-RU")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
endpoint := fmt.Sprintf("%s/movie/%d/recommendations?%s", s.baseURL, id, params.Encode())
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
var response models.TMDBResponse
|
|
|
|
|
|
err := s.makeRequest(endpoint, &response)
|
|
|
|
|
|
return &response, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *TMDBService) GetSimilarMovies(id, page int, language string) (*models.TMDBResponse, error) {
|
|
|
|
|
|
params := url.Values{}
|
|
|
|
|
|
params.Set("page", strconv.Itoa(page))
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
if language != "" {
|
|
|
|
|
|
params.Set("language", language)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
params.Set("language", "ru-RU")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
endpoint := fmt.Sprintf("%s/movie/%d/similar?%s", s.baseURL, id, params.Encode())
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
var response models.TMDBResponse
|
|
|
|
|
|
err := s.makeRequest(endpoint, &response)
|
|
|
|
|
|
return &response, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *TMDBService) GetPopularTVShows(page int, language string) (*models.TMDBTVResponse, error) {
|
|
|
|
|
|
params := url.Values{}
|
|
|
|
|
|
params.Set("page", strconv.Itoa(page))
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
if language != "" {
|
|
|
|
|
|
params.Set("language", language)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
params.Set("language", "ru-RU")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
endpoint := fmt.Sprintf("%s/tv/popular?%s", s.baseURL, params.Encode())
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
var response models.TMDBTVResponse
|
|
|
|
|
|
err := s.makeRequest(endpoint, &response)
|
|
|
|
|
|
return &response, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *TMDBService) GetTopRatedTVShows(page int, language string) (*models.TMDBTVResponse, error) {
|
|
|
|
|
|
params := url.Values{}
|
|
|
|
|
|
params.Set("page", strconv.Itoa(page))
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
if language != "" {
|
|
|
|
|
|
params.Set("language", language)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
params.Set("language", "ru-RU")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
endpoint := fmt.Sprintf("%s/tv/top_rated?%s", s.baseURL, params.Encode())
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
var response models.TMDBTVResponse
|
|
|
|
|
|
err := s.makeRequest(endpoint, &response)
|
|
|
|
|
|
return &response, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *TMDBService) GetOnTheAirTVShows(page int, language string) (*models.TMDBTVResponse, error) {
|
|
|
|
|
|
params := url.Values{}
|
|
|
|
|
|
params.Set("page", strconv.Itoa(page))
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
if language != "" {
|
|
|
|
|
|
params.Set("language", language)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
params.Set("language", "ru-RU")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
endpoint := fmt.Sprintf("%s/tv/on_the_air?%s", s.baseURL, params.Encode())
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
var response models.TMDBTVResponse
|
|
|
|
|
|
err := s.makeRequest(endpoint, &response)
|
|
|
|
|
|
return &response, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *TMDBService) GetAiringTodayTVShows(page int, language string) (*models.TMDBTVResponse, error) {
|
|
|
|
|
|
params := url.Values{}
|
|
|
|
|
|
params.Set("page", strconv.Itoa(page))
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
if language != "" {
|
|
|
|
|
|
params.Set("language", language)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
params.Set("language", "ru-RU")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
endpoint := fmt.Sprintf("%s/tv/airing_today?%s", s.baseURL, params.Encode())
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
var response models.TMDBTVResponse
|
|
|
|
|
|
err := s.makeRequest(endpoint, &response)
|
|
|
|
|
|
return &response, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *TMDBService) GetTVRecommendations(id, page int, language string) (*models.TMDBTVResponse, error) {
|
|
|
|
|
|
params := url.Values{}
|
|
|
|
|
|
params.Set("page", strconv.Itoa(page))
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
if language != "" {
|
|
|
|
|
|
params.Set("language", language)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
params.Set("language", "ru-RU")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
endpoint := fmt.Sprintf("%s/tv/%d/recommendations?%s", s.baseURL, id, params.Encode())
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
var response models.TMDBTVResponse
|
|
|
|
|
|
err := s.makeRequest(endpoint, &response)
|
|
|
|
|
|
return &response, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *TMDBService) GetSimilarTVShows(id, page int, language string) (*models.TMDBTVResponse, error) {
|
|
|
|
|
|
params := url.Values{}
|
|
|
|
|
|
params.Set("page", strconv.Itoa(page))
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
if language != "" {
|
|
|
|
|
|
params.Set("language", language)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
params.Set("language", "ru-RU")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
endpoint := fmt.Sprintf("%s/tv/%d/similar?%s", s.baseURL, id, params.Encode())
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
var response models.TMDBTVResponse
|
|
|
|
|
|
err := s.makeRequest(endpoint, &response)
|
|
|
|
|
|
return &response, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *TMDBService) GetMovieExternalIDs(id int) (*models.ExternalIDs, error) {
|
|
|
|
|
|
endpoint := fmt.Sprintf("%s/movie/%d/external_ids", s.baseURL, id)
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
var ids models.ExternalIDs
|
|
|
|
|
|
err := s.makeRequest(endpoint, &ids)
|
|
|
|
|
|
return &ids, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *TMDBService) GetTVExternalIDs(id int) (*models.ExternalIDs, error) {
|
|
|
|
|
|
endpoint := fmt.Sprintf("%s/tv/%d/external_ids", s.baseURL, id)
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
var ids models.ExternalIDs
|
|
|
|
|
|
err := s.makeRequest(endpoint, &ids)
|
|
|
|
|
|
return &ids, err
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *TMDBService) DiscoverMoviesByGenre(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")
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
if language != "" {
|
|
|
|
|
|
params.Set("language", language)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
params.Set("language", "ru-RU")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
endpoint := fmt.Sprintf("%s/discover/movie?%s", s.baseURL, params.Encode())
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-07 13:47:42 +00:00
|
|
|
|
var response models.TMDBResponse
|
|
|
|
|
|
err := s.makeRequest(endpoint, &response)
|
|
|
|
|
|
return &response, err
|
2025-08-14 11:34:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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")
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-14 11:34:31 +00:00
|
|
|
|
if language != "" {
|
|
|
|
|
|
params.Set("language", language)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
params.Set("language", "ru-RU")
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
endpoint := fmt.Sprintf("%s/discover/tv?%s", s.baseURL, params.Encode())
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-14 11:34:31 +00:00
|
|
|
|
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)
|
2025-09-28 11:46:20 +00:00
|
|
|
|
|
2025-08-14 11:34:31 +00:00
|
|
|
|
var season models.SeasonDetails
|
|
|
|
|
|
err := s.makeRequest(endpoint, &season)
|
|
|
|
|
|
return &season, err
|
2025-09-28 11:46:20 +00:00
|
|
|
|
}
|