Files
silo-server/internal/api/handlers/user_state.go
T

152 lines
4.0 KiB
Go

package handlers
import (
"context"
"github.com/Silo-Server/silo-server/internal/catalog"
"github.com/Silo-Server/silo-server/internal/models"
"github.com/Silo-Server/silo-server/internal/userstore"
)
type itemUserStateResponse struct {
Played bool `json:"played"`
IsFavorite bool `json:"is_favorite"`
InWatchlist bool `json:"in_watchlist"`
}
func resolveItemUserStates(
ctx context.Context,
store userstore.UserStore,
profileID string,
episodeRepo *catalog.EpisodeRepository,
items []*models.MediaItem,
) (map[string]*itemUserStateResponse, error) {
result := make(map[string]*itemUserStateResponse, len(items))
if store == nil || profileID == "" || len(items) == 0 {
return result, nil
}
contentIDs := make([]string, 0, len(items))
seriesIDs := make([]string, 0)
seasonIDs := make([]string, 0)
seenContent := make(map[string]struct{}, len(items))
seenSeries := make(map[string]struct{})
seenSeason := make(map[string]struct{})
for _, item := range items {
if item == nil || item.ContentID == "" {
continue
}
if _, ok := seenContent[item.ContentID]; ok {
continue
}
seenContent[item.ContentID] = struct{}{}
contentIDs = append(contentIDs, item.ContentID)
switch item.Type {
case "series":
if _, ok := seenSeries[item.ContentID]; !ok {
seenSeries[item.ContentID] = struct{}{}
seriesIDs = append(seriesIDs, item.ContentID)
}
case "season":
if _, ok := seenSeason[item.ContentID]; !ok {
seenSeason[item.ContentID] = struct{}{}
seasonIDs = append(seasonIDs, item.ContentID)
}
}
}
favoriteMap, err := store.ListFavoritesByMediaItems(ctx, profileID, contentIDs)
if err != nil {
return nil, err
}
watchlistMap, err := store.ListWatchlistByMediaItems(ctx, profileID, contentIDs)
if err != nil {
return nil, err
}
progressIDs := append([]string{}, contentIDs...)
seriesEpisodes := map[string][]*models.Episode{}
seasonEpisodes := map[string][]*models.Episode{}
if episodeRepo != nil {
if len(seriesIDs) > 0 {
seriesEpisodes, err = episodeRepo.ListBySeriesIDs(ctx, seriesIDs)
if err != nil {
return nil, err
}
for _, episodes := range seriesEpisodes {
for _, episode := range episodes {
if episode == nil || episode.ContentID == "" {
continue
}
if _, ok := seenContent[episode.ContentID]; ok {
continue
}
seenContent[episode.ContentID] = struct{}{}
progressIDs = append(progressIDs, episode.ContentID)
}
}
}
if len(seasonIDs) > 0 {
seasonEpisodes, err = episodeRepo.ListBySeasonIDs(ctx, seasonIDs)
if err != nil {
return nil, err
}
for _, episodes := range seasonEpisodes {
for _, episode := range episodes {
if episode == nil || episode.ContentID == "" {
continue
}
if _, ok := seenContent[episode.ContentID]; ok {
continue
}
seenContent[episode.ContentID] = struct{}{}
progressIDs = append(progressIDs, episode.ContentID)
}
}
}
}
progressMap, err := store.ListProgressByMediaItems(ctx, profileID, progressIDs)
if err != nil {
return nil, err
}
for _, item := range items {
if item == nil || item.ContentID == "" {
continue
}
state := &itemUserStateResponse{
IsFavorite: favoriteMap[item.ContentID],
InWatchlist: watchlistMap[item.ContentID],
}
switch item.Type {
case "series":
state.Played = allEpisodesCompleted(seriesEpisodes[item.ContentID], progressMap)
case "season":
state.Played = allEpisodesCompleted(seasonEpisodes[item.ContentID], progressMap)
default:
state.Played = progressMap[item.ContentID].Completed
}
result[item.ContentID] = state
}
return result, nil
}
func allEpisodesCompleted(episodes []*models.Episode, progressMap map[string]userstore.WatchProgress) bool {
if len(episodes) == 0 {
return false
}
for _, episode := range episodes {
if episode == nil || episode.ContentID == "" {
return false
}
progress, ok := progressMap[episode.ContentID]
if !ok || !progress.Completed {
return false
}
}
return true
}