From 879fbd4a53361b22bd0132ae874f26b0eaad5951 Mon Sep 17 00:00:00 2001 From: Michal Vrba Date: Sun, 14 Dec 2025 16:39:00 +0100 Subject: [PATCH] Lazily create session directories on first MP3 save Session directories are now created only when the first MP3 file is saved, not at session creation. Added EnsureSessionDirectoryExists to ISessionService and SessionService to handle this logic. Updated VideoService to call this method before saving files. Cleanup now logs when no directory exists for expired sessions. --- TuneRipper.Api/Services/ISessionService.cs | 1 + TuneRipper.Api/Services/SessionService.cs | 45 +++++++++++++++++++--- TuneRipper.Api/Services/VideoService.cs | 6 ++- 3 files changed, 45 insertions(+), 7 deletions(-) diff --git a/TuneRipper.Api/Services/ISessionService.cs b/TuneRipper.Api/Services/ISessionService.cs index 4f92364..1695b04 100644 --- a/TuneRipper.Api/Services/ISessionService.cs +++ b/TuneRipper.Api/Services/ISessionService.cs @@ -7,4 +7,5 @@ public interface ISessionService bool IsValidSession(string sessionId); void CleanupExpiredSessions(); string GetSessionDownloadsPath(string sessionId); + void EnsureSessionDirectoryExists(string sessionId); } \ No newline at end of file diff --git a/TuneRipper.Api/Services/SessionService.cs b/TuneRipper.Api/Services/SessionService.cs index 84257d0..6a99063 100644 --- a/TuneRipper.Api/Services/SessionService.cs +++ b/TuneRipper.Api/Services/SessionService.cs @@ -26,15 +26,18 @@ public class SessionService : ISessionService ); } + /// + /// Creates a new session with a unique ID. + /// Note: The session directory is NOT created at this point - it will be created + /// lazily when the first MP3 file is saved using EnsureSessionDirectoryExists(). + /// + /// The unique session ID public string CreateSession() { var sessionId = Guid.NewGuid().ToString("N")[..16]; // Use first 16 characters for shorter IDs _sessions[sessionId] = DateTime.UtcNow; - // Ensure session directory exists - var sessionPath = GetSessionDownloadsPath(sessionId); - Directory.CreateDirectory(sessionPath); - + // Don't create directory here - it will be created when first MP3 is saved _logger.LogInformation("Created new session: {SessionId}", sessionId); return sessionId; } @@ -83,7 +86,7 @@ public class SessionService : ISessionService { if (_sessions.TryRemove(sessionId, out _)) { - // Clean up session directory + // Clean up session directory if it exists var sessionPath = GetSessionDownloadsPath(sessionId); if (Directory.Exists(sessionPath)) { @@ -97,6 +100,10 @@ public class SessionService : ISessionService _logger.LogWarning(ex, "Failed to delete expired session directory: {SessionId}", sessionId); } } + else + { + _logger.LogDebug("No directory to clean up for expired session: {SessionId} (no MP3 files were downloaded)", sessionId); + } } } @@ -117,6 +124,34 @@ public class SessionService : ISessionService return Path.Combine(downloadsRoot, sessionId); } + /// + /// Ensures that the session directory exists, creating it if necessary. + /// This method should be called just before saving the first MP3 file in a session. + /// + /// The session ID + /// Thrown when sessionId is null or empty + /// Thrown when session is invalid or expired + public void EnsureSessionDirectoryExists(string sessionId) + { + if (string.IsNullOrWhiteSpace(sessionId)) + { + throw new ArgumentException("Session ID cannot be null or empty", nameof(sessionId)); + } + + if (!IsValidSession(sessionId)) + { + throw new InvalidOperationException($"Invalid session ID: {sessionId}"); + } + + var sessionPath = GetSessionDownloadsPath(sessionId); + + if (!Directory.Exists(sessionPath)) + { + Directory.CreateDirectory(sessionPath); + _logger.LogInformation("Created session directory for session: {SessionId} at {Path}", sessionId, sessionPath); + } + } + public void Dispose() { _cleanupTimer?.Dispose(); diff --git a/TuneRipper.Api/Services/VideoService.cs b/TuneRipper.Api/Services/VideoService.cs index caba0ce..a2dd0a5 100644 --- a/TuneRipper.Api/Services/VideoService.cs +++ b/TuneRipper.Api/Services/VideoService.cs @@ -104,9 +104,11 @@ public class VideoService : IVideoService throw new FileNotFoundException($"yt-dlp.exe not found at {ytDlpPath}"); } - // Get session-specific download directory + // Ensure session directory exists only when we're about to save the first MP3 file + _sessionService.EnsureSessionDirectoryExists(sessionId); + + // Get session-specific download directory (now guaranteed to exist) var downloadDir = _sessionService.GetSessionDownloadsPath(sessionId); - Directory.CreateDirectory(downloadDir); // Get video details first for better filename var videoDetails = await GetVideoDetailsAsync(url);