Files
AnimeAnnouncer/AnimeAnnouncer.Web/Pages/Index.cshtml.cs
T

151 lines
5.1 KiB
C#

using AnimeAnnouncer.Cache;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace AnimeAnnouncer.Web.Pages;
public class IndexModel : PageModel
{
private readonly ILogger<IndexModel> _logger;
private readonly TMDBCache? _tmdbCache;
public List<AiringShowViewModel> AiringShows { get; set; } = new();
public string? ErrorMessage { get; set; }
public IndexModel(ILogger<IndexModel> logger, IServiceProvider serviceProvider)
{
_logger = logger;
_tmdbCache = serviceProvider.GetService<TMDBCache>();
}
public async Task OnGetAsync()
{
if (_tmdbCache == null)
{
ErrorMessage = "Redis cache connection is not configured or unavailable.";
return;
}
try
{
List<AiringSoonItem>? airingList = await _tmdbCache.GetAiringList();
if (airingList == null || airingList.Count == 0)
{
AiringShows = new List<AiringShowViewModel>();
return;
}
var viewModels = new List<AiringShowViewModel>();
foreach (var airingItem in airingList)
{
TMDBCacheItem? cacheItem = null;
try
{
cacheItem = await _tmdbCache.GetCacheItem($"ShowCache-{airingItem.Title}");
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to retrieve cache item for title: {Title}", airingItem.Title);
}
viewModels.Add(new AiringShowViewModel
{
AiringSoon = airingItem,
CachedDetails = cacheItem
});
}
// Exclude placeholder/sentinel last-air-dates (e.g. DateTime.MaxValue == 12/31/9999,
// used by the announcer when an exact air date is unknown), then sort descending
// by LastAirDate (nulls last).
var displayable = viewModels.Where(x =>
{
var date = x.EffectiveLastAirDate;
// Keep items with a real, displayable date; drop the MaxValue sentinel.
return !date.HasValue || date.Value < DateTime.MaxValue.AddMonths(-1);
}).ToList();
AiringShows = displayable
.Where(x => x.EffectiveLastAirDate.HasValue && x.EffectiveLastAirDate.Value > DateTime.Now)
.OrderBy(x => x.EffectiveLastAirDate)
.ThenBy(x => x.Title)
.ToList();
}
catch (Exception ex)
{
_logger.LogError(ex, "Error loading airing soon list");
ErrorMessage = $"Unable to load airing soon list: {ex.Message}";
}
}
public class AiringShowViewModel
{
public required AiringSoonItem AiringSoon { get; set; }
public TMDBCacheItem? CachedDetails { get; set; }
public string Title => AiringSoon.Title;
public int ShowID => AiringSoon.ShowID;
public DateTime? EffectiveLastAirDate => AiringSoon.LastAirDate ?? CachedDetails?.LastAirDate;
public int LatestEpisodeNumber => AiringSoon.LatestEpisodeNumber > 0
? AiringSoon.LatestEpisodeNumber
: (CachedDetails?.LatestEpisodeNumber ?? 0);
public int? LastEpisodeNumber => CachedDetails?.LastEpisodeNumber;
public int? LatestSeasonNumber => CachedDetails?.LatestSeasonNumber;
public int? LatestOrdinalEpisodeNumber => CachedDetails?.LatestOrdinalEpisodeNumber;
public double? VoteAverage => CachedDetails?.VoteAverage;
public string? Overview => !string.IsNullOrWhiteSpace(CachedDetails?.LatestSeasonOverview)
? CachedDetails.LatestSeasonOverview
: CachedDetails?.Overview;
public string? PosterUrl
{
get
{
if (!string.IsNullOrWhiteSpace(CachedDetails?.LatestSeasonPosterPath))
return CachedDetails.LatestSeasonPosterPath;
if (!string.IsNullOrWhiteSpace(CachedDetails?.PosterPath))
return CachedDetails.PosterPath;
if (!string.IsNullOrWhiteSpace(CachedDetails?.AnilistPosterPath))
return CachedDetails.AnilistPosterPath;
return null;
}
}
public string? BackdropUrl => CachedDetails?.BackdropPath;
public DateTime AirReferenceNow => DateTime.Now;
public bool IsFuture
{
get
{
var date = EffectiveLastAirDate;
return date.HasValue && date.Value > AirReferenceNow;
}
}
public int DaysUntil
{
get
{
var date = EffectiveLastAirDate;
if (!date.HasValue)
return 0;
return (int)((date.Value - AirReferenceNow).Ticks / TimeSpan.FromDays(1).Ticks);
}
}
public string AirDateFormatted
{
get
{
var date = EffectiveLastAirDate;
return date.HasValue ? date.Value.ToString("MM/dd/yyyy") : "Unknown";
}
}
}
}