Initial commit of AnimeAnnouncer.Web
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
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";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user