diff --git a/ErsatzTV.Application/Channels/Commands/RefreshChannelDataHandler.cs b/ErsatzTV.Application/Channels/Commands/RefreshChannelDataHandler.cs index 97dfd84c3..622c2dff6 100644 --- a/ErsatzTV.Application/Channels/Commands/RefreshChannelDataHandler.cs +++ b/ErsatzTV.Application/Channels/Commands/RefreshChannelDataHandler.cs @@ -1194,12 +1194,17 @@ public class RefreshChannelDataHandler : IRequestHandler // must deserialize channel from json foreach (ExternalJsonChannel channel in maybeChannel) { - // TODO: null start time should log and throw + if (!DateTimeOffset.TryParse( + channel.StartTime, + CultureInfo.InvariantCulture, + DateTimeStyles.AssumeUniversal, + out DateTimeOffset parsed)) + { + throw new InvalidOperationException( + $"External json channel in file {path} has an invalid start time '{channel.StartTime}'"); + } - DateTimeOffset startTime = DateTimeOffset.Parse( - channel.StartTime ?? string.Empty, - CultureInfo.InvariantCulture, - DateTimeStyles.AssumeUniversal).ToLocalTime(); + DateTimeOffset startTime = parsed.ToLocalTime(); for (var i = 0; i < channel.Programs.Length; i++) { diff --git a/ErsatzTV.Application/Playouts/Commands/ReplacePlayoutAlternateScheduleItemsHandler.cs b/ErsatzTV.Application/Playouts/Commands/ReplacePlayoutAlternateScheduleItemsHandler.cs index 0cf6490a6..580558159 100644 --- a/ErsatzTV.Application/Playouts/Commands/ReplacePlayoutAlternateScheduleItemsHandler.cs +++ b/ErsatzTV.Application/Playouts/Commands/ReplacePlayoutAlternateScheduleItemsHandler.cs @@ -20,7 +20,10 @@ public class ReplacePlayoutAlternateScheduleItemsHandler( ReplacePlayoutAlternateScheduleItems request, CancellationToken cancellationToken) { - // TODO: validate that items is not empty + if (request.Items.Count == 0) + { + return BaseError.New("Playout alternate schedule items must not be empty"); + } try { diff --git a/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs b/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs index 48e0b1202..a7ed7ef40 100644 --- a/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs +++ b/ErsatzTV.Core/Scheduling/PlayoutBuilder.cs @@ -1448,10 +1448,10 @@ public class PlayoutBuilder : IPlayoutBuilder } // fall through to default case if we can't make the proper enumerator + _logger.LogWarning("Unable to build marathon enumerator; falling back to random"); goto default; default: - // TODO: handle this error case differently? return new RandomizedMediaCollectionEnumerator(mediaItems, state); } } diff --git a/ErsatzTV.Infrastructure/Streaming/ExternalJsonPlayoutItemProvider.cs b/ErsatzTV.Infrastructure/Streaming/ExternalJsonPlayoutItemProvider.cs index 5e904d1cf..9ec345306 100644 --- a/ErsatzTV.Infrastructure/Streaming/ExternalJsonPlayoutItemProvider.cs +++ b/ErsatzTV.Infrastructure/Streaming/ExternalJsonPlayoutItemProvider.cs @@ -93,12 +93,21 @@ public class ExternalJsonPlayoutItemProvider : IExternalJsonPlayoutItemProvider // must deserialize channel from json foreach (ExternalJsonChannel channel in maybeChannel) { - // TODO: null start time should log and throw + if (!DateTimeOffset.TryParse( + channel.StartTime, + CultureInfo.InvariantCulture, + DateTimeStyles.AssumeUniversal, + out DateTimeOffset parsed)) + { + _logger.LogError( + "External json channel in file {ScheduleFile} has an invalid start time {StartTime}", + playout.ScheduleFile, + channel.StartTime); + + return new UnableToLocatePlayoutItem(); + } - DateTimeOffset startTime = DateTimeOffset.Parse( - channel.StartTime ?? string.Empty, - CultureInfo.InvariantCulture, - DateTimeStyles.AssumeUniversal).ToLocalTime(); + DateTimeOffset startTime = parsed.ToLocalTime(); //_logger.LogDebug("external json start time: {StartTime}", startTime); @@ -208,14 +217,35 @@ public class ExternalJsonPlayoutItemProvider : IExternalJsonPlayoutItemProvider .Include(pms => pms.Connections) .SelectOneAsync(pms => pms.ServerName, pms => pms.ServerName == program.ServerKey, cancellationToken); + if (maybeServer.IsNone) + { + _logger.LogWarning( + "Unable to stream remotely; no Plex server found with server name {ServerName}", + program.ServerKey); + } + foreach (PlexMediaSource server in maybeServer) { Option maybeConnection = server.Connections.SingleOrDefault(c => c.IsActive); + if (maybeConnection.IsNone) + { + _logger.LogWarning( + "Unable to stream remotely; Plex server {ServerName} has no active connection", + server.ServerName); + } + foreach (PlexConnection connection in maybeConnection) { Option maybeToken = await _plexSecretStore.GetServerAuthToken(server.ClientIdentifier); + if (maybeToken.IsNone) + { + _logger.LogWarning( + "Unable to stream remotely; Plex server {ServerName} has no auth token", + server.ServerName); + } + foreach (PlexServerAuthToken token in maybeToken) { MediaItem mediaItem = program.Type switch @@ -241,7 +271,6 @@ public class ExternalJsonPlayoutItemProvider : IExternalJsonPlayoutItemProvider } } - // TODO: log errors? return new UnableToLocatePlayoutItem(); }