mirror of
https://gitlab.com/foxixus/neomovies-api.git
synced 2025-10-27 17:38:51 +05:00
- Add TMDBID field to ExternalIDs model - Enhance GetExternalIDs in MovieService and TVService to fetch TMDB ID via FindTMDBIdByIMDB - Add EnrichKPWithTMDBID function to enrich unified content with TMDB IDs - Update unified handlers to automatically enrich KP content with TMDB IDs - Enrich search results with TMDB IDs by fetching full film data for each result This ensures that when using source=kp, the response includes TMDB IDs in externalIds when available through IMDB ID mapping, while preserving all original KP data.
425 lines
9.5 KiB
Go
425 lines
9.5 KiB
Go
package services
|
|
|
|
import (
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"neomovies-api/pkg/models"
|
|
)
|
|
|
|
func MapKPFilmToTMDBMovie(kpFilm *KPFilm) *models.Movie {
|
|
if kpFilm == nil {
|
|
return nil
|
|
}
|
|
|
|
releaseDate := ""
|
|
if kpFilm.Year > 0 {
|
|
releaseDate = fmt.Sprintf("%d-01-01", kpFilm.Year)
|
|
}
|
|
|
|
genres := make([]models.Genre, 0)
|
|
for _, g := range kpFilm.Genres {
|
|
genres = append(genres, models.Genre{
|
|
ID: 0,
|
|
Name: g.Genre,
|
|
})
|
|
}
|
|
|
|
countries := make([]models.ProductionCountry, 0)
|
|
for _, c := range kpFilm.Countries {
|
|
countries = append(countries, models.ProductionCountry{
|
|
ISO31661: "",
|
|
Name: c.Country,
|
|
})
|
|
}
|
|
|
|
posterPath := ""
|
|
if kpFilm.PosterUrlPreview != "" {
|
|
posterPath = kpFilm.PosterUrlPreview
|
|
} else if kpFilm.PosterUrl != "" {
|
|
posterPath = kpFilm.PosterUrl
|
|
}
|
|
|
|
backdropPath := ""
|
|
if kpFilm.CoverUrl != "" {
|
|
backdropPath = kpFilm.CoverUrl
|
|
}
|
|
|
|
overview := kpFilm.Description
|
|
if overview == "" {
|
|
overview = kpFilm.ShortDescription
|
|
}
|
|
|
|
title := kpFilm.NameRu
|
|
if title == "" {
|
|
title = kpFilm.NameEn
|
|
}
|
|
if title == "" {
|
|
title = kpFilm.NameOriginal
|
|
}
|
|
|
|
originalTitle := kpFilm.NameOriginal
|
|
if originalTitle == "" {
|
|
originalTitle = kpFilm.NameEn
|
|
}
|
|
|
|
return &models.Movie{
|
|
ID: kpFilm.KinopoiskId,
|
|
Title: title,
|
|
OriginalTitle: originalTitle,
|
|
Overview: overview,
|
|
PosterPath: posterPath,
|
|
BackdropPath: backdropPath,
|
|
ReleaseDate: releaseDate,
|
|
VoteAverage: kpFilm.RatingKinopoisk,
|
|
VoteCount: kpFilm.RatingKinopoiskVoteCount,
|
|
Popularity: float64(kpFilm.RatingKinopoisk * 100),
|
|
Adult: false,
|
|
OriginalLanguage: detectLanguage(kpFilm),
|
|
Runtime: kpFilm.FilmLength,
|
|
Genres: genres,
|
|
Tagline: kpFilm.Slogan,
|
|
ProductionCountries: countries,
|
|
IMDbID: kpFilm.ImdbId,
|
|
KinopoiskID: kpFilm.KinopoiskId,
|
|
}
|
|
}
|
|
|
|
func MapKPFilmToTVShow(kpFilm *KPFilm) *models.TVShow {
|
|
if kpFilm == nil {
|
|
return nil
|
|
}
|
|
|
|
firstAirDate := ""
|
|
if kpFilm.StartYear > 0 {
|
|
firstAirDate = fmt.Sprintf("%d-01-01", kpFilm.StartYear)
|
|
}
|
|
|
|
lastAirDate := ""
|
|
if kpFilm.EndYear > 0 {
|
|
lastAirDate = fmt.Sprintf("%d-01-01", kpFilm.EndYear)
|
|
}
|
|
|
|
genres := make([]models.Genre, 0)
|
|
for _, g := range kpFilm.Genres {
|
|
genres = append(genres, models.Genre{
|
|
ID: 0,
|
|
Name: g.Genre,
|
|
})
|
|
}
|
|
|
|
posterPath := ""
|
|
if kpFilm.PosterUrlPreview != "" {
|
|
posterPath = kpFilm.PosterUrlPreview
|
|
} else if kpFilm.PosterUrl != "" {
|
|
posterPath = kpFilm.PosterUrl
|
|
}
|
|
|
|
backdropPath := ""
|
|
if kpFilm.CoverUrl != "" {
|
|
backdropPath = kpFilm.CoverUrl
|
|
}
|
|
|
|
overview := kpFilm.Description
|
|
if overview == "" {
|
|
overview = kpFilm.ShortDescription
|
|
}
|
|
|
|
name := kpFilm.NameRu
|
|
if name == "" {
|
|
name = kpFilm.NameEn
|
|
}
|
|
if name == "" {
|
|
name = kpFilm.NameOriginal
|
|
}
|
|
|
|
originalName := kpFilm.NameOriginal
|
|
if originalName == "" {
|
|
originalName = kpFilm.NameEn
|
|
}
|
|
|
|
status := "Ended"
|
|
if kpFilm.Completed {
|
|
status = "Ended"
|
|
} else {
|
|
status = "Returning Series"
|
|
}
|
|
|
|
return &models.TVShow{
|
|
ID: kpFilm.KinopoiskId,
|
|
Name: name,
|
|
OriginalName: originalName,
|
|
Overview: overview,
|
|
PosterPath: posterPath,
|
|
BackdropPath: backdropPath,
|
|
FirstAirDate: firstAirDate,
|
|
LastAirDate: lastAirDate,
|
|
VoteAverage: kpFilm.RatingKinopoisk,
|
|
VoteCount: kpFilm.RatingKinopoiskVoteCount,
|
|
Popularity: float64(kpFilm.RatingKinopoisk * 100),
|
|
OriginalLanguage: detectLanguage(kpFilm),
|
|
Genres: genres,
|
|
Status: status,
|
|
InProduction: !kpFilm.Completed,
|
|
KinopoiskID: kpFilm.KinopoiskId,
|
|
}
|
|
}
|
|
|
|
// Unified mappers with prefixed IDs
|
|
func MapKPToUnified(kpFilm *KPFilm) *models.UnifiedContent {
|
|
if kpFilm == nil {
|
|
return nil
|
|
}
|
|
|
|
releaseDate := FormatKPDate(kpFilm.Year)
|
|
endDate := (*string)(nil)
|
|
if kpFilm.EndYear > 0 {
|
|
v := FormatKPDate(kpFilm.EndYear)
|
|
endDate = &v
|
|
}
|
|
|
|
genres := make([]models.UnifiedGenre, 0)
|
|
for _, g := range kpFilm.Genres {
|
|
genres = append(genres, models.UnifiedGenre{ID: strings.ToLower(g.Genre), Name: g.Genre})
|
|
}
|
|
|
|
poster := kpFilm.PosterUrlPreview
|
|
if poster == "" {
|
|
poster = kpFilm.PosterUrl
|
|
}
|
|
|
|
country := ""
|
|
if len(kpFilm.Countries) > 0 {
|
|
country = kpFilm.Countries[0].Country
|
|
}
|
|
|
|
title := kpFilm.NameRu
|
|
if title == "" {
|
|
title = kpFilm.NameEn
|
|
}
|
|
originalTitle := kpFilm.NameOriginal
|
|
if originalTitle == "" {
|
|
originalTitle = kpFilm.NameEn
|
|
}
|
|
|
|
var budgetPtr *int64
|
|
var revenuePtr *int64
|
|
|
|
external := models.UnifiedExternalIDs{KP: &kpFilm.KinopoiskId, TMDB: nil, IMDb: kpFilm.ImdbId}
|
|
|
|
return &models.UnifiedContent{
|
|
ID: strconv.Itoa(kpFilm.KinopoiskId),
|
|
SourceID: "kp_" + strconv.Itoa(kpFilm.KinopoiskId),
|
|
Title: title,
|
|
OriginalTitle: originalTitle,
|
|
Description: firstNonEmpty(kpFilm.Description, kpFilm.ShortDescription),
|
|
ReleaseDate: releaseDate,
|
|
EndDate: endDate,
|
|
Type: mapKPTypeToUnified(kpFilm),
|
|
Genres: genres,
|
|
Rating: kpFilm.RatingKinopoisk,
|
|
PosterURL: poster,
|
|
BackdropURL: kpFilm.CoverUrl,
|
|
Director: "",
|
|
Cast: []models.UnifiedCastMember{},
|
|
Duration: kpFilm.FilmLength,
|
|
Country: country,
|
|
Language: detectLanguage(kpFilm),
|
|
Budget: budgetPtr,
|
|
Revenue: revenuePtr,
|
|
IMDbID: kpFilm.ImdbId,
|
|
ExternalIDs: external,
|
|
}
|
|
}
|
|
|
|
func mapKPTypeToUnified(kp *KPFilm) string {
|
|
if kp.Serial || kp.Type == "TV_SERIES" || kp.Type == "MINI_SERIES" {
|
|
return "tv"
|
|
}
|
|
return "movie"
|
|
}
|
|
|
|
func firstNonEmpty(values ...string) string {
|
|
for _, v := range values {
|
|
if strings.TrimSpace(v) != "" {
|
|
return v
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func MapKPSearchToTMDBResponse(kpSearch *KPSearchResponse) *models.TMDBResponse {
|
|
if kpSearch == nil {
|
|
return &models.TMDBResponse{
|
|
Page: 1,
|
|
Results: []models.Movie{},
|
|
TotalPages: 0,
|
|
TotalResults: 0,
|
|
}
|
|
}
|
|
|
|
results := make([]models.Movie, 0)
|
|
for _, film := range kpSearch.Films {
|
|
movie := mapKPFilmShortToMovie(film)
|
|
if movie != nil {
|
|
results = append(results, *movie)
|
|
}
|
|
}
|
|
|
|
totalPages := kpSearch.PagesCount
|
|
if totalPages == 0 && len(results) > 0 {
|
|
totalPages = 1
|
|
}
|
|
|
|
return &models.TMDBResponse{
|
|
Page: 1,
|
|
Results: results,
|
|
TotalPages: totalPages,
|
|
TotalResults: kpSearch.SearchFilmsCountResult,
|
|
}
|
|
}
|
|
|
|
func mapKPFilmShortToMovie(film KPFilmShort) *models.Movie {
|
|
genres := make([]models.Genre, 0)
|
|
for _, g := range film.Genres {
|
|
genres = append(genres, models.Genre{
|
|
ID: 0,
|
|
Name: g.Genre,
|
|
})
|
|
}
|
|
|
|
year := 0
|
|
if film.Year != "" {
|
|
year, _ = strconv.Atoi(film.Year)
|
|
}
|
|
|
|
releaseDate := ""
|
|
if year > 0 {
|
|
releaseDate = fmt.Sprintf("%d-01-01", year)
|
|
}
|
|
|
|
posterPath := film.PosterUrlPreview
|
|
if posterPath == "" {
|
|
posterPath = film.PosterUrl
|
|
}
|
|
|
|
title := film.NameRu
|
|
if title == "" {
|
|
title = film.NameEn
|
|
}
|
|
|
|
originalTitle := film.NameEn
|
|
if originalTitle == "" {
|
|
originalTitle = film.NameRu
|
|
}
|
|
|
|
rating := 0.0
|
|
if film.Rating != "" {
|
|
rating, _ = strconv.ParseFloat(film.Rating, 64)
|
|
}
|
|
|
|
return &models.Movie{
|
|
ID: film.FilmId,
|
|
Title: title,
|
|
OriginalTitle: originalTitle,
|
|
Overview: film.Description,
|
|
PosterPath: posterPath,
|
|
ReleaseDate: releaseDate,
|
|
VoteAverage: rating,
|
|
VoteCount: film.RatingVoteCount,
|
|
Popularity: rating * 100,
|
|
Genres: genres,
|
|
KinopoiskID: film.FilmId,
|
|
}
|
|
}
|
|
|
|
func detectLanguage(film *KPFilm) string {
|
|
if film.NameRu != "" {
|
|
return "ru"
|
|
}
|
|
if film.NameEn != "" {
|
|
return "en"
|
|
}
|
|
return "ru"
|
|
}
|
|
|
|
func MapKPExternalIDsToTMDB(kpFilm *KPFilm) *models.ExternalIDs {
|
|
if kpFilm == nil {
|
|
return &models.ExternalIDs{}
|
|
}
|
|
|
|
return &models.ExternalIDs{
|
|
ID: kpFilm.KinopoiskId,
|
|
IMDbID: kpFilm.ImdbId,
|
|
KinopoiskID: kpFilm.KinopoiskId,
|
|
}
|
|
}
|
|
|
|
func ShouldUseKinopoisk(language string) bool {
|
|
if language == "" {
|
|
return false
|
|
}
|
|
lang := strings.ToLower(language)
|
|
return strings.HasPrefix(lang, "ru")
|
|
}
|
|
|
|
func NormalizeLanguage(language string) string {
|
|
if language == "" {
|
|
return "en-US"
|
|
}
|
|
|
|
lang := strings.ToLower(language)
|
|
if strings.HasPrefix(lang, "ru") {
|
|
return "ru-RU"
|
|
}
|
|
|
|
return "en-US"
|
|
}
|
|
|
|
func ConvertKPRatingToTMDB(kpRating float64) float64 {
|
|
return kpRating
|
|
}
|
|
|
|
func FormatKPDate(year int) string {
|
|
if year <= 0 {
|
|
return time.Now().Format("2006-01-02")
|
|
}
|
|
return fmt.Sprintf("%d-01-01", year)
|
|
}
|
|
|
|
// EnrichKPWithTMDBID обогащает KP контент TMDB ID через IMDB ID
|
|
func EnrichKPWithTMDBID(content *models.UnifiedContent, tmdbService *TMDBService) {
|
|
if content == nil || content.IMDbID == "" || content.ExternalIDs.TMDB != nil {
|
|
return
|
|
}
|
|
|
|
mediaType := "movie"
|
|
if content.Type == "tv" {
|
|
mediaType = "tv"
|
|
}
|
|
|
|
if tmdbID, err := tmdbService.FindTMDBIdByIMDB(content.IMDbID, mediaType, "ru-RU"); err == nil {
|
|
content.ExternalIDs.TMDB = &tmdbID
|
|
}
|
|
}
|
|
|
|
// EnrichKPSearchItemsWithTMDBID обогащает массив поисковых элементов TMDB ID
|
|
func EnrichKPSearchItemsWithTMDBID(items []models.UnifiedSearchItem, tmdbService *TMDBService) {
|
|
for i := range items {
|
|
if items[i].ExternalIDs.IMDb == "" || items[i].ExternalIDs.TMDB != nil {
|
|
continue
|
|
}
|
|
|
|
mediaType := "movie"
|
|
if items[i].Type == "tv" {
|
|
mediaType = "tv"
|
|
}
|
|
|
|
if tmdbID, err := tmdbService.FindTMDBIdByIMDB(items[i].ExternalIDs.IMDb, mediaType, "ru-RU"); err == nil {
|
|
items[i].ExternalIDs.TMDB = &tmdbID
|
|
}
|
|
}
|
|
}
|