diff --git a/src/Jellyfin.LiveTv/Listings/SchedulesDirect.cs b/src/Jellyfin.LiveTv/Listings/SchedulesDirect.cs index 3aa0f0408b..c1ccb24bf4 100644 --- a/src/Jellyfin.LiveTv/Listings/SchedulesDirect.cs +++ b/src/Jellyfin.LiveTv/Listings/SchedulesDirect.cs @@ -684,27 +684,37 @@ namespace Jellyfin.LiveTv.Listings sdCode?.ToString() ?? "N/A", responseBody); - if (sdCode is SdErrorCode.InvalidUser or SdErrorCode.InvalidHash or SdErrorCode.AccountLocked or SdErrorCode.AccountExpired or SdErrorCode.PasswordRequired) + if (sdCode is SdErrorCode.AccountExpired or SdErrorCode.InvalidHash or SdErrorCode.InvalidUser or SdErrorCode.AccountLocked or SdErrorCode.AppLocked or SdErrorCode.AccountInactive) { // Permanent account errors — disable SD for this server lifetime. - _logger.LogError("Schedules Direct account error (code {SdCode}). Disabling SD until server restart", sdCode); + _logger.LogError("Schedules Direct account error (code {SdCode}). Disabling SD until server restart.", sdCode); _tokens.Clear(); _accountError = true; } - else if (sdCode is SdErrorCode.MaxLoginAttempts or SdErrorCode.TemporaryLockout) + else if (sdCode is SdErrorCode.ServiceOffline or SdErrorCode.ServiceBusy or SdErrorCode.AccountTempLock) { // Transient login errors — back off for 30 minutes, then allow retry. + _logger.LogError("Schedules Direct transient error (code {SdCode}). Backing off for 30 minutes.", sdCode); _tokens.Clear(); Interlocked.Exchange(ref _lastErrorResponseTicks, DateTime.UtcNow.Ticks); } - else if (sdCode is SdErrorCode.MaxImageDownloads) + else if (sdCode is SdErrorCode.MaxLoginAttempts or SdErrorCode.MaxIPAttempts) + { + // 24 hour bans - stop image and metadata requests until SD reset at 00:00 UTC. + _logger.LogError("Schedules Direct service limit error (code {SdCode}). Disabling until SD reset.", sdCode); + SetImageLimitHit(); + SetMetadataLimitHit(); + } + else if (sdCode is SdErrorCode.MaxImageDownloads or SdErrorCode.MaxImageDownloadsTrial) { // Max image downloads — stop image requests until SD resets at 00:00 UTC. + _logger.LogError("Schedules Direct image download limit hit (code {SdCode}). Disabling image acquisition until SD reset.", sdCode); SetImageLimitHit(); } else if (sdCode is SdErrorCode.MaxScheduleRequests) { // Max schedule/metadata requests — stop metadata requests until SD resets at 00:00 UTC. + _logger.LogError("Schedules Direct metadata download limit hit (code {SdCode}). Disabling metadata acquisition until SD reset.", sdCode); SetMetadataLimitHit(); } else if (enableRetry diff --git a/src/Jellyfin.LiveTv/Listings/SchedulesDirectDtos/SdErrorCode.cs b/src/Jellyfin.LiveTv/Listings/SchedulesDirectDtos/SdErrorCode.cs index ec6c6c475b..fffbfb9a58 100644 --- a/src/Jellyfin.LiveTv/Listings/SchedulesDirectDtos/SdErrorCode.cs +++ b/src/Jellyfin.LiveTv/Listings/SchedulesDirectDtos/SdErrorCode.cs @@ -3,39 +3,59 @@ namespace Jellyfin.LiveTv.Listings.SchedulesDirectDtos; /// -/// Schedules Direct API error codes. +/// Schedules Direct API error codes. See https://github.com/SchedulesDirect/JSON-Service/wiki/API-20141201#error-response for details. /// public enum SdErrorCode { /// - /// Invalid user. + /// Schedules Direct unavailable/out of service. /// - InvalidUser = 4001, + ServiceOffline = 3000, /// - /// Invalid password hash. + /// Schedules Direct busy. /// - InvalidHash = 4003, - - /// - /// Account locked or disabled. - /// - AccountLocked = 4004, + ServiceBusy = 3001, /// /// Account expired. /// - AccountExpired = 4005, + AccountExpired = 4001, /// - /// Token has expired. + /// Invalid password hash. + /// + InvalidHash = 4002, + + /// + /// Invalid user or password. + /// + InvalidUser = 4003, + + /// + /// Account temporarily locked due to login failures. + /// + AccountTempLock = 4004, + + /// + /// Account permanently locked due to abuse. + /// + AccountLocked = 4005, + + /// + /// Token has expired. Request a new one. /// TokenExpired = 4006, /// - /// Password is required. + /// Application locked out. /// - PasswordRequired = 4008, + AppLocked = 4007, + + /// + /// Account not active. + /// + AccountInactive = 4008, /// /// Maximum login attempts exceeded. @@ -43,17 +63,32 @@ public enum SdErrorCode MaxLoginAttempts = 4009, /// - /// Temporary lockout. + /// Maximum unique IP attempts reached. /// - TemporaryLockout = 4010, + MaxIPAttempts = 4010, + + /// + /// Lineup change maximum reached. + /// + MaxScheduleRequests = 4100, + + /// + /// Requested image not found. + /// + ImageNotFound = 5000, /// /// Maximum image downloads reached for the day. /// MaxImageDownloads = 5002, + /// + /// Trial specific maximum image downloads reached for the day. + /// + MaxImageDownloadsTrial = 5003, + /// /// Maximum schedule/metadata requests reached for the day. /// - MaxScheduleRequests = 5003 + MaxInvalidImages = 5004 }