From f450edf0330d04151c5ef83545a71e577157614d Mon Sep 17 00:00:00 2001 From: Sergey Gladkovskiy Date: Sun, 5 Apr 2026 17:47:05 +0300 Subject: [PATCH] feat: resolve Manual Import mode to Copy when copyUsingHardlinks is enabled When ImportMode is Auto and copyUsingHardlinks is true in Media Management settings, resolve Manual Import mode to Copy instead of letting it fall through to Move. This prevents breaking active torrents when using a hardlink-based workflow. Fixes #11418 --- .../MovieImport/Manual/ManualImportService.cs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/NzbDrone.Core/MediaFiles/MovieImport/Manual/ManualImportService.cs b/src/NzbDrone.Core/MediaFiles/MovieImport/Manual/ManualImportService.cs index 3c70885b10..e321e4bff0 100644 --- a/src/NzbDrone.Core/MediaFiles/MovieImport/Manual/ManualImportService.cs +++ b/src/NzbDrone.Core/MediaFiles/MovieImport/Manual/ManualImportService.cs @@ -6,6 +6,7 @@ using NzbDrone.Common.Disk; using NzbDrone.Common.Extensions; using NzbDrone.Common.Instrumentation.Extensions; +using NzbDrone.Core.Configuration; using NzbDrone.Core.CustomFormats; using NzbDrone.Core.Download; using NzbDrone.Core.Download.TrackedDownloads; @@ -40,6 +41,7 @@ public class ManualImportService : IExecute, IManualImportS private readonly IDownloadedMovieImportService _downloadedMovieImportService; private readonly IMediaFileService _mediaFileService; private readonly ICustomFormatCalculationService _formatCalculator; + private readonly IConfigService _configService; private readonly IEventAggregator _eventAggregator; private readonly Logger _logger; @@ -54,6 +56,7 @@ public ManualImportService(IDiskProvider diskProvider, IDownloadedMovieImportService downloadedMovieImportService, IMediaFileService mediaFileService, ICustomFormatCalculationService formatCalculator, + IConfigService configService, IEventAggregator eventAggregator, Logger logger) { @@ -68,6 +71,7 @@ public ManualImportService(IDiskProvider diskProvider, _downloadedMovieImportService = downloadedMovieImportService; _mediaFileService = mediaFileService; _formatCalculator = formatCalculator; + _configService = configService; _eventAggregator = eventAggregator; _logger = logger; } @@ -406,6 +410,16 @@ public void Execute(ManualImportCommand message) { _logger.ProgressTrace("Manually importing {0} files using mode {1}", message.Files.Count, message.ImportMode); + var importMode = message.ImportMode; + + // When ImportMode is Auto and CopyUsingHardlinks is enabled, default to Copy + // to preserve original files for seeding and use hardlinks instead of moving. + if (importMode == ImportMode.Auto && _configService.CopyUsingHardlinks) + { + importMode = ImportMode.Copy; + _logger.Debug("ImportMode Auto resolved to Copy because CopyUsingHardlinks is enabled"); + } + var imported = new List(); var importedTrackedDownload = new List(); @@ -463,11 +477,11 @@ public void Execute(ManualImportCommand message) if (trackedDownload == null) { - imported.AddRange(_importApprovedMovie.Import(new List { importDecision }, !existingFile, null, message.ImportMode)); + imported.AddRange(_importApprovedMovie.Import(new List { importDecision }, !existingFile, null, importMode)); } else { - var importResult = _importApprovedMovie.Import(new List { importDecision }, true, trackedDownload.DownloadItem, message.ImportMode).First(); + var importResult = _importApprovedMovie.Import(new List { importDecision }, true, trackedDownload.DownloadItem, importMode).First(); imported.Add(importResult);