diff options
| author | Shadowghost <Ghost_of_Stone@web.de> | 2026-02-22 11:32:55 +0100 |
|---|---|---|
| committer | Shadowghost <Ghost_of_Stone@web.de> | 2026-02-22 11:32:55 +0100 |
| commit | ed43ad09688d11ed09b9b45be409455c33bc0e6a (patch) | |
| tree | 849c758a057d6091535ffba996c272bdb41daf5d /src | |
| parent | 27396bffc6d2cc0595ffba4dd400a9e5bbfafc0f (diff) | |
Persistence
Diffstat (limited to 'src')
| -rw-r--r-- | src/Jellyfin.LiveTv/Listings/SchedulesDirect.cs | 86 |
1 files changed, 50 insertions, 36 deletions
diff --git a/src/Jellyfin.LiveTv/Listings/SchedulesDirect.cs b/src/Jellyfin.LiveTv/Listings/SchedulesDirect.cs index 39ad746877..04589b3a8d 100644 --- a/src/Jellyfin.LiveTv/Listings/SchedulesDirect.cs +++ b/src/Jellyfin.LiveTv/Listings/SchedulesDirect.cs @@ -50,7 +50,8 @@ namespace Jellyfin.LiveTv.Listings private bool _disposed = false; private byte[] _countriesCache; - private DateTime? _dailyLimitHitDate; + private DateTime? _imageLimitHitDate; + private DateTime? _metadataLimitHitDate; public SchedulesDirect( ILogger<SchedulesDirect> logger, @@ -60,13 +61,16 @@ namespace Jellyfin.LiveTv.Listings _logger = logger; _httpClientFactory = httpClientFactory; _appPaths = appPaths; - _dailyLimitHitDate = LoadDailyLimitHitDate(); + _imageLimitHitDate = LoadDailyLimitFile(ImageLimitFilePath); + _metadataLimitHitDate = LoadDailyLimitFile(MetadataLimitFilePath); } /// <inheritdoc /> public string Name => "Schedules Direct"; - private string DailyLimitFilePath => Path.Combine(_appPaths.CachePath, "sd-daily-limit.txt"); + private string ImageLimitFilePath => Path.Combine(_appPaths.CachePath, "sd-image-limit.txt"); + + private string MetadataLimitFilePath => Path.Combine(_appPaths.CachePath, "sd-metadata-limit.txt"); /// <inheritdoc /> public string Type => nameof(SchedulesDirect); @@ -89,6 +93,11 @@ namespace Jellyfin.LiveTv.Listings public async Task<IEnumerable<ProgramInfo>> GetProgramsAsync(ListingsProviderInfo info, string channelId, DateTime startDateUtc, DateTime endDateUtc, CancellationToken cancellationToken) { + if (IsDailyLimitActive(ref _metadataLimitHitDate, MetadataLimitFilePath)) + { + return []; + } + ArgumentException.ThrowIfNullOrEmpty(channelId); // Normalize incoming input @@ -464,6 +473,11 @@ namespace Jellyfin.LiveTv.Listings IReadOnlyList<string> programIds, CancellationToken cancellationToken) { + if (IsDailyLimitActive(ref _imageLimitHitDate, ImageLimitFilePath)) + { + return []; + } + var token = await GetToken(info, cancellationToken).ConfigureAwait(false); if (string.IsNullOrEmpty(token) || programIds.Count == 0) @@ -565,19 +579,6 @@ namespace Jellyfin.LiveTv.Listings return null; } - // Daily usage limit hit (e.g. 5003) — wait until the SD counter resets at 00:00 UTC. - if (_dailyLimitHitDate.HasValue) - { - if (_dailyLimitHitDate.Value.Date < DateTime.UtcNow.Date) - { - ClearDailyLimitHitDate(); - } - else - { - return null; - } - } - // Avoid hammering SD after transient login failures (e.g. max attempts / temporary lockout) if ((DateTime.UtcNow - _lastErrorResponse).TotalMinutes < 30) { @@ -687,12 +688,15 @@ namespace Jellyfin.LiveTv.Listings _tokens.Clear(); _lastErrorResponse = DateTime.UtcNow; } - else if (sdCode is 5002 or 5003) + else if (sdCode is 5002) { - // Daily usage limits — stop requests until SD resets at 00:00 UTC. - // 5002=max image downloads - // 5003=max schedule/metadata requests - SetDailyLimitHitDate(); + // Max image downloads — stop image requests until SD resets at 00:00 UTC. + SetDailyLimitHitDate(ref _imageLimitHitDate, ImageLimitFilePath); + } + else if (sdCode is 5003) + { + // Max schedule/metadata requests — stop metadata requests until SD resets at 00:00 UTC. + SetDailyLimitHitDate(ref _metadataLimitHitDate, MetadataLimitFilePath); } else if (enableRetry && (int)response.StatusCode < 500 @@ -831,9 +835,8 @@ namespace Jellyfin.LiveTv.Listings return bytes; } - private DateTime? LoadDailyLimitHitDate() + private static DateTime? LoadDailyLimitFile(string path) { - var path = DailyLimitFilePath; if (!File.Exists(path)) { return null; @@ -863,36 +866,47 @@ namespace Jellyfin.LiveTv.Listings return null; } - private static void TryDeleteFile(string path) + private bool IsDailyLimitActive(ref DateTime? hitDate, string filePath) { - try + if (!hitDate.HasValue) { - File.Delete(path); + return false; } - catch (IOException) + + if (hitDate.Value.Date < DateTime.UtcNow.Date) { - // Best effort. + hitDate = null; + TryDeleteFile(filePath); + return false; } + + return true; } - private void SetDailyLimitHitDate() + private void SetDailyLimitHitDate(ref DateTime? hitDate, string filePath) { - _dailyLimitHitDate = DateTime.UtcNow; + hitDate = DateTime.UtcNow; try { - Directory.CreateDirectory(Path.GetDirectoryName(DailyLimitFilePath)!); - File.WriteAllText(DailyLimitFilePath, DateTime.UtcNow.ToString("O", CultureInfo.InvariantCulture)); + Directory.CreateDirectory(Path.GetDirectoryName(filePath)!); + File.WriteAllText(filePath, DateTime.UtcNow.ToString("O", CultureInfo.InvariantCulture)); } catch (IOException ex) { - _logger.LogWarning(ex, "Failed to persist SD daily limit hit date"); + _logger.LogWarning(ex, "Failed to persist SD daily limit to {Path}", filePath); } } - private void ClearDailyLimitHitDate() + private static void TryDeleteFile(string path) { - _dailyLimitHitDate = null; - TryDeleteFile(DailyLimitFilePath); + try + { + File.Delete(path); + } + catch (IOException) + { + // Best effort. + } } public async Task Validate(ListingsProviderInfo info, bool validateLogin, bool validateListings) |
