From ab532ac6dcc43ff3a30d886b61f4255a619fb77f Mon Sep 17 00:00:00 2001 From: max Date: Thu, 18 Sep 2025 00:30:35 +0200 Subject: [PATCH] [CHANGE] Fixed cache service && Download channel images from cache --- Manager.App/Services/LibraryService.cs | 26 +++++++------ Manager.App/Services/System/CacheService.cs | 43 ++++++++++++++++++--- 2 files changed, 52 insertions(+), 17 deletions(-) diff --git a/Manager.App/Services/LibraryService.cs b/Manager.App/Services/LibraryService.cs index f2004a5..75f69f8 100644 --- a/Manager.App/Services/LibraryService.cs +++ b/Manager.App/Services/LibraryService.cs @@ -3,9 +3,9 @@ using Manager.App.Constants; using Manager.App.Models.Library; using Manager.App.Models.Settings; using Manager.App.Models.System; +using Manager.App.Services.System; using Manager.Data.Contexts; using Manager.Data.Entities.LibraryContext; -using Manager.YouTube; using Manager.YouTube.Models.Innertube; using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Options; @@ -18,15 +18,16 @@ public class LibraryService : ILibraryService private readonly LibrarySettings _librarySettings; private readonly IDbContextFactory _dbContextFactory; private readonly DirectoryInfo _libraryDirectory; + private readonly CacheService _cacheService; - - public LibraryService(ILogger logger, IOptions librarySettings, IDbContextFactory contextFactory) + public LibraryService(ILogger logger, IOptions librarySettings, IDbContextFactory contextFactory, CacheService cacheService) { _logger = logger; _librarySettings = librarySettings.Value; _dbContextFactory = contextFactory; + _cacheService = cacheService; _libraryDirectory = Directory.CreateDirectory(_librarySettings.Path); - logger.LogDebug("Working dir for library: {LibraryWorkingDir}", _libraryDirectory.FullName); + logger.LogDebug("Library directory: {LibraryWorkingDir}", _libraryDirectory.FullName); Directory.CreateDirectory(Path.Combine(_librarySettings.Path, LibraryConstants.Directories.SubDirMedia)); Directory.CreateDirectory(Path.Combine(_librarySettings.Path, LibraryConstants.Directories.SubDirChannels)); } @@ -65,32 +66,33 @@ public class LibraryService : ILibraryService continue; } - var downloadResult = await NetworkService.DownloadBytesAsync(new HttpRequestMessage(HttpMethod.Get, image.Url)); - if (!downloadResult.IsSuccess) + var cacheResult = await _cacheService.CacheFromUrl(image.Url); + if (!cacheResult.IsSuccess) { + _logger.LogWarning("Failed to get image {ImageUrl}", image.Url); continue; } - var download = downloadResult.Value; + var cachedFile = cacheResult.Value; var fileId = Guid.NewGuid(); - var fileName = download.FileName ?? $"{fileId}.{download.ContentType?.Split('/').Last() ?? "unknown"}"; + var fileName = cachedFile.OriginalFileName ?? $"{fileId}.{cachedFile.ContentType?.Split('/').Last() ?? "unknown"}"; var relativePath = Path.Combine(foreignKey, libSubDir, $"{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}_{fileName}"); var savePath = Path.Combine(_libraryDirectory.FullName, subDir, relativePath); Directory.CreateDirectory(Path.GetDirectoryName(savePath) ?? savePath); await using var fileStream = File.Create(savePath); - await fileStream.WriteAsync(download.Data.AsMemory(0, download.Data.Length)); + await fileStream.WriteAsync(cachedFile.Data.AsMemory(0, cachedFile.Data.Length)); var file = new FileEntity { Id = fileId, OriginalUrl = image.Url, - OriginalFileName = download.FileName, + OriginalFileName = cachedFile.OriginalFileName, ForeignKey = foreignKey, FileType = fileType, RelativePath = relativePath.Replace('\\', '/'), - MimeType = download.ContentType, - SizeBytes = download.ContentLength, + MimeType = cachedFile.ContentType, + SizeBytes = cachedFile.Data.Length, Height = image.Height, Width = image.Width }; diff --git a/Manager.App/Services/System/CacheService.cs b/Manager.App/Services/System/CacheService.cs index 7e8f423..956dfb8 100644 --- a/Manager.App/Services/System/CacheService.cs +++ b/Manager.App/Services/System/CacheService.cs @@ -10,7 +10,7 @@ using Microsoft.EntityFrameworkCore.Infrastructure; namespace Manager.App.Services.System; -public class CacheService(ILogger logger, IHostEnvironment environment) : ExtendedBackgroundService(nameof(CacheService), "Manages caching.", logger, TimeSpan.FromDays(1)) +public class CacheService(ILogger logger, IHostEnvironment environment) : ExtendedBackgroundService(nameof(CacheService), "Manages caching.", logger, TimeSpan.FromHours(5)) { private DirectoryInfo? _cacheDirectory; private PooledDbContextFactory? _dbContextFactory; @@ -131,9 +131,14 @@ public class CacheService(ILogger logger, IHostEnvironment environ throw new InvalidOperationException("No DbContext factory configured."); } + if (_cacheDirectory == null) + { + throw new InvalidOperationException("No cache directory configured."); + } + await using var dbContext = await _dbContextFactory.CreateDbContextAsync(cancellationToken); - var toRemove = dbContext.Cache.Where(c => c.CachedAtUtc >= DateTime.UtcNow.AddDays(-1)); + var toRemove = dbContext.Cache.Where(c => c.CachedAtUtc < DateTime.UtcNow.AddDays(-1)); if (!toRemove.Any()) { LogEvent("No items found to purge from cache."); @@ -142,9 +147,37 @@ public class CacheService(ILogger logger, IHostEnvironment environ var totalToRemove = toRemove.Count(); LogEvent($"Found {totalToRemove} cache items that are older than 1 day(s)"); - dbContext.RemoveRange(toRemove); - var deleted = await dbContext.SaveChangesAsync(cancellationToken); - LogEvent($"Removed {deleted}/{totalToRemove} items"); + + var deleted = new List(); + foreach (var entity in toRemove) + { + var pathToFile = Path.Combine(_cacheDirectory.FullName, DataSubDir, $"{entity.Id}.cache"); + if (!File.Exists(pathToFile)) + { + deleted.Add(entity); + continue; + } + + try + { + File.Delete(pathToFile); + } + catch (Exception e) + { + logger.LogError(e, "Failed to delete cache entity with id: {EntityId}. Skipping cache entity...", entity.Id); + continue; + } + deleted.Add(entity); + } + + dbContext.RemoveRange(deleted); + var dbDeleted = await dbContext.SaveChangesAsync(cancellationToken); + if (dbDeleted < deleted.Count) + { + LogEvent("Could not delete all files from cache.", LogSeverity.Warning); + } + + LogEvent($"Removed {dbDeleted}/{totalToRemove} items"); } }