diff options
| author | Shadowghost <Ghost_of_Stone@web.de> | 2026-04-11 18:00:41 +0200 |
|---|---|---|
| committer | Shadowghost <Ghost_of_Stone@web.de> | 2026-04-11 18:00:41 +0200 |
| commit | 60e01e1f22fa6fc3505469abd96d85d64b05fac1 (patch) | |
| tree | d39c4ffea1c36735013f95ef69d20536ad354a42 | |
| parent | e0f50f504afe5713f64d644a464f39e903d9ef6b (diff) | |
Apply review suggestions
| -rw-r--r-- | MediaBrowser.Controller/LiveTv/ISchedulesDirectService.cs | 7 | ||||
| -rw-r--r-- | src/Jellyfin.LiveTv/Guide/GuideManager.cs | 8 | ||||
| -rw-r--r-- | src/Jellyfin.LiveTv/Listings/SchedulesDirect.cs | 26 |
3 files changed, 36 insertions, 5 deletions
diff --git a/MediaBrowser.Controller/LiveTv/ISchedulesDirectService.cs b/MediaBrowser.Controller/LiveTv/ISchedulesDirectService.cs index a33b4422b2..6953650952 100644 --- a/MediaBrowser.Controller/LiveTv/ISchedulesDirectService.cs +++ b/MediaBrowser.Controller/LiveTv/ISchedulesDirectService.cs @@ -21,4 +21,11 @@ public interface ISchedulesDirectService /// </summary> /// <returns><c>true</c> if the image limit has been hit and has not yet reset; otherwise <c>false</c>.</returns> bool IsImageDailyLimitActive(); + + /// <summary> + /// Gets a value indicating whether the Schedules Direct service is available. + /// Returns <c>false</c> if a permanent account error has occurred or a transient backoff is active. + /// </summary> + /// <returns><c>true</c> if the service can accept requests; otherwise <c>false</c>.</returns> + bool IsServiceAvailable(); } diff --git a/src/Jellyfin.LiveTv/Guide/GuideManager.cs b/src/Jellyfin.LiveTv/Guide/GuideManager.cs index a659cc020b..556516674b 100644 --- a/src/Jellyfin.LiveTv/Guide/GuideManager.cs +++ b/src/Jellyfin.LiveTv/Guide/GuideManager.cs @@ -738,6 +738,14 @@ public class GuideManager : IGuideManager _cacheParallelOptions, async (program, cancellationToken) => { + // Re-check: limit may have been set by a parallel task since the LINQ filter ran. + if (_schedulesDirectService.IsImageDailyLimitActive() + && program.ImageInfos.All( + img => img.IsLocalFile || img.Path.Contains("schedulesdirect", StringComparison.OrdinalIgnoreCase))) + { + return; + } + for (var i = 0; i < program.ImageInfos.Length; i++) { if (cancellationToken.IsCancellationRequested) diff --git a/src/Jellyfin.LiveTv/Listings/SchedulesDirect.cs b/src/Jellyfin.LiveTv/Listings/SchedulesDirect.cs index 7b97dcc8db..3aa0f0408b 100644 --- a/src/Jellyfin.LiveTv/Listings/SchedulesDirect.cs +++ b/src/Jellyfin.LiveTv/Listings/SchedulesDirect.cs @@ -45,8 +45,8 @@ namespace Jellyfin.LiveTv.Listings private readonly ConcurrentDictionary<string, NameValuePair> _tokens = new(); private readonly JsonSerializerOptions _jsonOptions = JsonDefaults.Options; - private DateTime _lastErrorResponse; - private bool _accountError; + private long _lastErrorResponseTicks; + private volatile bool _accountError; private bool _disposed = false; private byte[] _countriesCache; @@ -594,7 +594,7 @@ namespace Jellyfin.LiveTv.Listings } // Avoid hammering SD after transient login failures (e.g. max attempts / temporary lockout) - if ((DateTime.UtcNow - _lastErrorResponse).TotalMinutes < 30) + if ((DateTime.UtcNow - new DateTime(Interlocked.Read(ref _lastErrorResponseTicks), DateTimeKind.Utc)).TotalMinutes < 30) { return null; } @@ -635,7 +635,7 @@ namespace Jellyfin.LiveTv.Listings && (int)ex.StatusCode.Value < 500) { _tokens.Clear(); - _lastErrorResponse = DateTime.UtcNow; + Interlocked.Exchange(ref _lastErrorResponseTicks, DateTime.UtcNow.Ticks); } throw; @@ -695,7 +695,7 @@ namespace Jellyfin.LiveTv.Listings { // Transient login errors — back off for 30 minutes, then allow retry. _tokens.Clear(); - _lastErrorResponse = DateTime.UtcNow; + Interlocked.Exchange(ref _lastErrorResponseTicks, DateTime.UtcNow.Ticks); } else if (sdCode is SdErrorCode.MaxImageDownloads) { @@ -877,6 +877,22 @@ namespace Jellyfin.LiveTv.Listings } /// <inheritdoc /> + public bool IsServiceAvailable() + { + if (_accountError) + { + return false; + } + + if ((DateTime.UtcNow - new DateTime(Interlocked.Read(ref _lastErrorResponseTicks), DateTimeKind.Utc)).TotalMinutes < 30) + { + return false; + } + + return true; + } + + /// <inheritdoc /> public bool IsImageDailyLimitActive() { if (!_imageLimitHitDate.HasValue) |
