Fix Schedules Direct API Error Codes (#16920)

* Clean up Schedules Direct error handling.

* Rename MaxImageDownloads2 to MaxImageDownloadsTrial per suggestion.

* Fix documentation.

* Fix incorrect 3XXX series codes.

* Rename SvcUnavailable to SvcOffline.

* Change 3XXX error code prefix from Svc to Service.
This commit is contained in:
Arazil
2026-05-31 10:22:00 -05:00
committed by GitHub
parent 63d1af5fe7
commit 9397148b20
2 changed files with 66 additions and 21 deletions

View File

@@ -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

View File

@@ -3,39 +3,59 @@
namespace Jellyfin.LiveTv.Listings.SchedulesDirectDtos;
/// <summary>
/// Schedules Direct API error codes.
/// Schedules Direct API error codes. See https://github.com/SchedulesDirect/JSON-Service/wiki/API-20141201#error-response for details.
/// </summary>
public enum SdErrorCode
{
/// <summary>
/// Invalid user.
/// Schedules Direct unavailable/out of service.
/// </summary>
InvalidUser = 4001,
ServiceOffline = 3000,
/// <summary>
/// Invalid password hash.
/// Schedules Direct busy.
/// </summary>
InvalidHash = 4003,
/// <summary>
/// Account locked or disabled.
/// </summary>
AccountLocked = 4004,
ServiceBusy = 3001,
/// <summary>
/// Account expired.
/// </summary>
AccountExpired = 4005,
AccountExpired = 4001,
/// <summary>
/// Token has expired.
/// Invalid password hash.
/// </summary>
InvalidHash = 4002,
/// <summary>
/// Invalid user or password.
/// </summary>
InvalidUser = 4003,
/// <summary>
/// Account temporarily locked due to login failures.
/// </summary>
AccountTempLock = 4004,
/// <summary>
/// Account permanently locked due to abuse.
/// </summary>
AccountLocked = 4005,
/// <summary>
/// Token has expired. Request a new one.
/// </summary>
TokenExpired = 4006,
/// <summary>
/// Password is required.
/// Application locked out.
/// </summary>
PasswordRequired = 4008,
AppLocked = 4007,
/// <summary>
/// Account not active.
/// </summary>
AccountInactive = 4008,
/// <summary>
/// Maximum login attempts exceeded.
@@ -43,17 +63,32 @@ public enum SdErrorCode
MaxLoginAttempts = 4009,
/// <summary>
/// Temporary lockout.
/// Maximum unique IP attempts reached.
/// </summary>
TemporaryLockout = 4010,
MaxIPAttempts = 4010,
/// <summary>
/// Lineup change maximum reached.
/// </summary>
MaxScheduleRequests = 4100,
/// <summary>
/// Requested image not found.
/// </summary>
ImageNotFound = 5000,
/// <summary>
/// Maximum image downloads reached for the day.
/// </summary>
MaxImageDownloads = 5002,
/// <summary>
/// Trial specific maximum image downloads reached for the day.
/// </summary>
MaxImageDownloadsTrial = 5003,
/// <summary>
/// Maximum schedule/metadata requests reached for the day.
/// </summary>
MaxScheduleRequests = 5003
MaxInvalidImages = 5004
}