mirror of
https://github.com/Radarr/Radarr.git
synced 2024-10-27 06:02:33 +01:00
Fixed: Get actual file names from QBittorrent API (#5226)
* Fixed: Get actual file names from QBittorrent API Previously we were assuming that the output filename was the category output dir + the torrent name. This isn't true if the torrent has been renamed or sanitized.
This commit is contained in:
parent
b7719662a7
commit
3e795d290b
@ -37,6 +37,7 @@ public void Setup()
|
|||||||
|
|
||||||
_trackedDownload = Builder<TrackedDownload>.CreateNew()
|
_trackedDownload = Builder<TrackedDownload>.CreateNew()
|
||||||
.With(c => c.State = TrackedDownloadState.Downloading)
|
.With(c => c.State = TrackedDownloadState.Downloading)
|
||||||
|
.With(c => c.ImportItem = completed)
|
||||||
.With(c => c.DownloadItem = completed)
|
.With(c => c.DownloadItem = completed)
|
||||||
.With(c => c.RemoteMovie = remoteMovie)
|
.With(c => c.RemoteMovie = remoteMovie)
|
||||||
.Build();
|
.Build();
|
||||||
|
@ -47,6 +47,10 @@ public void Setup()
|
|||||||
.Setup(c => c.Get(It.IsAny<int>()))
|
.Setup(c => c.Get(It.IsAny<int>()))
|
||||||
.Returns(Mocker.GetMock<IDownloadClient>().Object);
|
.Returns(Mocker.GetMock<IDownloadClient>().Object);
|
||||||
|
|
||||||
|
Mocker.GetMock<IProvideImportItemService>()
|
||||||
|
.Setup(c => c.ProvideImportItem(It.IsAny<DownloadClientItem>(), It.IsAny<DownloadClientItem>()))
|
||||||
|
.Returns((DownloadClientItem item, DownloadClientItem previous) => item);
|
||||||
|
|
||||||
Mocker.GetMock<IHistoryService>()
|
Mocker.GetMock<IHistoryService>()
|
||||||
.Setup(s => s.MostRecentForDownloadId(_trackedDownload.DownloadItem.DownloadId))
|
.Setup(s => s.MostRecentForDownloadId(_trackedDownload.DownloadItem.DownloadId))
|
||||||
.Returns(new MovieHistory());
|
.Returns(new MovieHistory());
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using Moq;
|
using Moq;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Common.Disk;
|
||||||
using NzbDrone.Common.Http;
|
using NzbDrone.Common.Http;
|
||||||
using NzbDrone.Core.Download;
|
using NzbDrone.Core.Download;
|
||||||
using NzbDrone.Core.Download.Clients.QBittorrent;
|
using NzbDrone.Core.Download.Clients.QBittorrent;
|
||||||
@ -124,6 +126,24 @@ protected virtual void GivenTorrents(List<QBittorrentTorrent> torrents)
|
|||||||
Mocker.GetMock<IQBittorrentProxy>()
|
Mocker.GetMock<IQBittorrentProxy>()
|
||||||
.Setup(s => s.GetTorrents(It.IsAny<QBittorrentSettings>()))
|
.Setup(s => s.GetTorrents(It.IsAny<QBittorrentSettings>()))
|
||||||
.Returns(torrents);
|
.Returns(torrents);
|
||||||
|
|
||||||
|
foreach (var torrent in torrents)
|
||||||
|
{
|
||||||
|
Mocker.GetMock<IQBittorrentProxy>()
|
||||||
|
.Setup(s => s.GetTorrentProperties(torrent.Hash.ToLower(), It.IsAny<QBittorrentSettings>()))
|
||||||
|
.Returns(new QBittorrentTorrentProperties { SavePath = torrent.SavePath });
|
||||||
|
|
||||||
|
Mocker.GetMock<IQBittorrentProxy>()
|
||||||
|
.Setup(s => s.GetTorrentFiles(torrent.Hash.ToLower(), It.IsAny<QBittorrentSettings>()))
|
||||||
|
.Returns(new List<QBittorrentTorrentFile> { new QBittorrentTorrentFile { Name = torrent.Name } });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenTorrentFiles(string hash, List<QBittorrentTorrentFile> files)
|
||||||
|
{
|
||||||
|
Mocker.GetMock<IQBittorrentProxy>()
|
||||||
|
.Setup(s => s.GetTorrentFiles(hash.ToLower(), It.IsAny<QBittorrentSettings>()))
|
||||||
|
.Returns(files);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -259,6 +279,78 @@ public void stalledDL_item_should_have_required_properties()
|
|||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
public void single_file_torrent_outputpath_should_have_sanitised_name()
|
||||||
|
{
|
||||||
|
var torrent = new QBittorrentTorrent
|
||||||
|
{
|
||||||
|
Hash = "HASH",
|
||||||
|
Name = @"Droned.S01E01.Test\'s.1080p.WEB-DL-DRONE.mkv",
|
||||||
|
Size = 1000,
|
||||||
|
Progress = 0.7,
|
||||||
|
Eta = 8640000,
|
||||||
|
State = "stalledDL",
|
||||||
|
Label = "",
|
||||||
|
SavePath = @"C:\Torrents".AsOsAgnostic()
|
||||||
|
};
|
||||||
|
|
||||||
|
var file = new QBittorrentTorrentFile
|
||||||
|
{
|
||||||
|
Name = "Droned.S01E01.Tests.1080p.WEB-DL-DRONE.mkv"
|
||||||
|
};
|
||||||
|
|
||||||
|
GivenTorrents(new List<QBittorrentTorrent> { torrent });
|
||||||
|
GivenTorrentFiles(torrent.Hash, new List<QBittorrentTorrentFile> { file });
|
||||||
|
|
||||||
|
var item = new DownloadClientItem
|
||||||
|
{
|
||||||
|
DownloadId = torrent.Hash
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = Subject.GetImportItem(item, null);
|
||||||
|
|
||||||
|
result.OutputPath.FullPath.Should().Be(Path.Combine(torrent.SavePath, file.Name));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void multi_file_torrent_outputpath_should_have_sanitised_name()
|
||||||
|
{
|
||||||
|
var torrent = new QBittorrentTorrent
|
||||||
|
{
|
||||||
|
Hash = "HASH",
|
||||||
|
Name = @"Droned.S01.\1/2",
|
||||||
|
Size = 1000,
|
||||||
|
Progress = 0.7,
|
||||||
|
Eta = 8640000,
|
||||||
|
State = "stalledDL",
|
||||||
|
Label = "",
|
||||||
|
SavePath = @"C:\Torrents".AsOsAgnostic()
|
||||||
|
};
|
||||||
|
|
||||||
|
var files = new List<QBittorrentTorrentFile>
|
||||||
|
{
|
||||||
|
new QBittorrentTorrentFile
|
||||||
|
{
|
||||||
|
Name = @"Droned.S01.12\E01.mkv".AsOsAgnostic()
|
||||||
|
},
|
||||||
|
new QBittorrentTorrentFile
|
||||||
|
{
|
||||||
|
Name = @"Droned.S01.12\E02.mkv".AsOsAgnostic()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
GivenTorrents(new List<QBittorrentTorrent> { torrent });
|
||||||
|
GivenTorrentFiles(torrent.Hash, files);
|
||||||
|
|
||||||
|
var item = new DownloadClientItem
|
||||||
|
{
|
||||||
|
DownloadId = torrent.Hash
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = Subject.GetImportItem(item, null);
|
||||||
|
|
||||||
|
result.OutputPath.FullPath.Should().Be(Path.Combine(torrent.SavePath, "Droned.S01.12"));
|
||||||
|
}
|
||||||
|
|
||||||
public void missingFiles_item_should_have_required_properties()
|
public void missingFiles_item_should_have_required_properties()
|
||||||
{
|
{
|
||||||
var torrent = new QBittorrentTorrent
|
var torrent = new QBittorrentTorrent
|
||||||
@ -279,6 +371,39 @@ public void missingFiles_item_should_have_required_properties()
|
|||||||
item.RemainingTime.Should().NotHaveValue();
|
item.RemainingTime.Should().NotHaveValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void api_261_should_use_content_path()
|
||||||
|
{
|
||||||
|
var torrent = new QBittorrentTorrent
|
||||||
|
{
|
||||||
|
Hash = "HASH",
|
||||||
|
Name = @"Droned.S01.\1/2",
|
||||||
|
Size = 1000,
|
||||||
|
Progress = 0.7,
|
||||||
|
Eta = 8640000,
|
||||||
|
State = "stalledDL",
|
||||||
|
Label = "",
|
||||||
|
SavePath = @"C:\Torrents".AsOsAgnostic(),
|
||||||
|
ContentPath = @"C:\Torrents\Droned.S01.12".AsOsAgnostic()
|
||||||
|
};
|
||||||
|
|
||||||
|
GivenTorrents(new List<QBittorrentTorrent> { torrent });
|
||||||
|
|
||||||
|
Mocker.GetMock<IQBittorrentProxy>()
|
||||||
|
.Setup(v => v.GetApiVersion(It.IsAny<QBittorrentSettings>()))
|
||||||
|
.Returns(new Version(2, 6, 1));
|
||||||
|
|
||||||
|
var item = new DownloadClientItem
|
||||||
|
{
|
||||||
|
DownloadId = torrent.Hash,
|
||||||
|
OutputPath = new OsPath(torrent.ContentPath)
|
||||||
|
};
|
||||||
|
|
||||||
|
var result = Subject.GetImportItem(item, null);
|
||||||
|
|
||||||
|
result.OutputPath.FullPath.Should().Be(torrent.ContentPath);
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void Download_should_return_unique_id()
|
public void Download_should_return_unique_id()
|
||||||
{
|
{
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using FluentValidation.Results;
|
using FluentValidation.Results;
|
||||||
using NLog;
|
using NLog;
|
||||||
@ -122,6 +123,7 @@ protected override string AddFromTorrentFile(RemoteMovie remoteMovie, string has
|
|||||||
|
|
||||||
public override IEnumerable<DownloadClientItem> GetItems()
|
public override IEnumerable<DownloadClientItem> GetItems()
|
||||||
{
|
{
|
||||||
|
var version = Proxy.GetApiVersion(Settings);
|
||||||
var config = Proxy.GetConfig(Settings);
|
var config = Proxy.GetConfig(Settings);
|
||||||
var torrents = Proxy.GetTorrents(Settings);
|
var torrents = Proxy.GetTorrents(Settings);
|
||||||
|
|
||||||
@ -138,19 +140,18 @@ public override IEnumerable<DownloadClientItem> GetItems()
|
|||||||
DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this),
|
DownloadClientInfo = DownloadClientItemClientInfo.FromDownloadClient(this),
|
||||||
RemainingSize = (long)(torrent.Size * (1.0 - torrent.Progress)),
|
RemainingSize = (long)(torrent.Size * (1.0 - torrent.Progress)),
|
||||||
RemainingTime = GetRemainingTime(torrent),
|
RemainingTime = GetRemainingTime(torrent),
|
||||||
SeedRatio = torrent.Ratio,
|
SeedRatio = torrent.Ratio
|
||||||
OutputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(torrent.SavePath)),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (version >= new Version("2.6.1"))
|
||||||
|
{
|
||||||
|
item.OutputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, new OsPath(torrent.ContentPath));
|
||||||
|
}
|
||||||
|
|
||||||
// Avoid removing torrents that haven't reached the global max ratio.
|
// Avoid removing torrents that haven't reached the global max ratio.
|
||||||
// Removal also requires the torrent to be paused, in case a higher max ratio was set on the torrent itself (which is not exposed by the api).
|
// Removal also requires the torrent to be paused, in case a higher max ratio was set on the torrent itself (which is not exposed by the api).
|
||||||
item.CanMoveFiles = item.CanBeRemoved = torrent.State == "pausedUP" && HasReachedSeedLimit(torrent, config);
|
item.CanMoveFiles = item.CanBeRemoved = torrent.State == "pausedUP" && HasReachedSeedLimit(torrent, config);
|
||||||
|
|
||||||
if (!item.OutputPath.IsEmpty && item.OutputPath.FileName != torrent.Name)
|
|
||||||
{
|
|
||||||
item.OutputPath += torrent.Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (torrent.State)
|
switch (torrent.State)
|
||||||
{
|
{
|
||||||
case "error": // some error occurred, applies to paused torrents
|
case "error": // some error occurred, applies to paused torrents
|
||||||
@ -224,6 +225,49 @@ public override void RemoveItem(string hash, bool deleteData)
|
|||||||
Proxy.RemoveTorrent(hash.ToLower(), deleteData, Settings);
|
Proxy.RemoveTorrent(hash.ToLower(), deleteData, Settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override DownloadClientItem GetImportItem(DownloadClientItem item, DownloadClientItem previousImportAttempt)
|
||||||
|
{
|
||||||
|
// On API version >= 2.6.1 this is already set correctly
|
||||||
|
if (!item.OutputPath.IsEmpty)
|
||||||
|
{
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
var files = Proxy.GetTorrentFiles(item.DownloadId.ToLower(), Settings);
|
||||||
|
if (!files.Any())
|
||||||
|
{
|
||||||
|
_logger.Debug($"No files found for torrent {item.Title} in qBittorrent");
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
var properties = Proxy.GetTorrentProperties(item.DownloadId.ToLower(), Settings);
|
||||||
|
var savePath = new OsPath(properties.SavePath);
|
||||||
|
|
||||||
|
var result = item.Clone();
|
||||||
|
|
||||||
|
OsPath outputPath;
|
||||||
|
if (files.Count == 1)
|
||||||
|
{
|
||||||
|
outputPath = savePath + files[0].Name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// we have multiple files in the torrent so just get
|
||||||
|
// the first subdirectory
|
||||||
|
var relativePath = new OsPath(files[0].Name);
|
||||||
|
while (!relativePath.Directory.IsEmpty)
|
||||||
|
{
|
||||||
|
relativePath = relativePath.Directory;
|
||||||
|
}
|
||||||
|
|
||||||
|
outputPath = savePath + relativePath.FileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.OutputPath = _remotePathMappingService.RemapRemoteToLocal(Settings.Host, outputPath);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public override DownloadClientInfo GetStatus()
|
public override DownloadClientInfo GetStatus()
|
||||||
{
|
{
|
||||||
var config = Proxy.GetConfig(Settings);
|
var config = Proxy.GetConfig(Settings);
|
||||||
|
@ -16,6 +16,7 @@ public interface IQBittorrentProxy
|
|||||||
QBittorrentPreferences GetConfig(QBittorrentSettings settings);
|
QBittorrentPreferences GetConfig(QBittorrentSettings settings);
|
||||||
List<QBittorrentTorrent> GetTorrents(QBittorrentSettings settings);
|
List<QBittorrentTorrent> GetTorrents(QBittorrentSettings settings);
|
||||||
QBittorrentTorrentProperties GetTorrentProperties(string hash, QBittorrentSettings settings);
|
QBittorrentTorrentProperties GetTorrentProperties(string hash, QBittorrentSettings settings);
|
||||||
|
List<QBittorrentTorrentFile> GetTorrentFiles(string hash, QBittorrentSettings settings);
|
||||||
|
|
||||||
void AddTorrentFromUrl(string torrentUrl, QBittorrentSettings settings);
|
void AddTorrentFromUrl(string torrentUrl, QBittorrentSettings settings);
|
||||||
void AddTorrentFromFile(string fileName, byte[] fileContent, QBittorrentSettings settings);
|
void AddTorrentFromFile(string fileName, byte[] fileContent, QBittorrentSettings settings);
|
||||||
|
@ -105,6 +105,14 @@ public QBittorrentTorrentProperties GetTorrentProperties(string hash, QBittorren
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<QBittorrentTorrentFile> GetTorrentFiles(string hash, QBittorrentSettings settings)
|
||||||
|
{
|
||||||
|
var request = BuildRequest(settings).Resource($"/query/propertiesFiles/{hash}");
|
||||||
|
var response = ProcessRequest<List<QBittorrentTorrentFile>>(request, settings);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
public void AddTorrentFromUrl(string torrentUrl, QBittorrentSettings settings)
|
public void AddTorrentFromUrl(string torrentUrl, QBittorrentSettings settings)
|
||||||
{
|
{
|
||||||
var request = BuildRequest(settings).Resource("/command/download")
|
var request = BuildRequest(settings).Resource("/command/download")
|
||||||
|
@ -110,6 +110,15 @@ public QBittorrentTorrentProperties GetTorrentProperties(string hash, QBittorren
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<QBittorrentTorrentFile> GetTorrentFiles(string hash, QBittorrentSettings settings)
|
||||||
|
{
|
||||||
|
var request = BuildRequest(settings).Resource("/api/v2/torrents/files")
|
||||||
|
.AddQueryParam("hash", hash);
|
||||||
|
var response = ProcessRequest<List<QBittorrentTorrentFile>>(request, settings);
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
public void AddTorrentFromUrl(string torrentUrl, QBittorrentSettings settings)
|
public void AddTorrentFromUrl(string torrentUrl, QBittorrentSettings settings)
|
||||||
{
|
{
|
||||||
var request = BuildRequest(settings).Resource("/api/v2/torrents/add")
|
var request = BuildRequest(settings).Resource("/api/v2/torrents/add")
|
||||||
|
@ -24,6 +24,9 @@ public class QBittorrentTorrent
|
|||||||
[JsonProperty(PropertyName = "save_path")]
|
[JsonProperty(PropertyName = "save_path")]
|
||||||
public string SavePath { get; set; } // Torrent save path
|
public string SavePath { get; set; } // Torrent save path
|
||||||
|
|
||||||
|
[JsonProperty(PropertyName = "content_path")]
|
||||||
|
public string ContentPath { get; set; } // Torrent save path
|
||||||
|
|
||||||
public float Ratio { get; set; } // Torrent share ratio
|
public float Ratio { get; set; } // Torrent share ratio
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "ratio_limit")] // Per torrent seeding ratio limit (-2 = use global, -1 = unlimited)
|
[JsonProperty(PropertyName = "ratio_limit")] // Per torrent seeding ratio limit (-2 = use global, -1 = unlimited)
|
||||||
@ -40,7 +43,15 @@ public class QBittorrentTorrentProperties
|
|||||||
{
|
{
|
||||||
public string Hash { get; set; } // Torrent hash
|
public string Hash { get; set; } // Torrent hash
|
||||||
|
|
||||||
|
[JsonProperty(PropertyName = "save_path")]
|
||||||
|
public string SavePath { get; set; }
|
||||||
|
|
||||||
[JsonProperty(PropertyName = "seeding_time")]
|
[JsonProperty(PropertyName = "seeding_time")]
|
||||||
public long SeedingTime { get; set; } // Torrent seeding time
|
public long SeedingTime { get; set; } // Torrent seeding time
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class QBittorrentTorrentFile
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,7 @@ public class CompletedDownloadService : ICompletedDownloadService
|
|||||||
{
|
{
|
||||||
private readonly IEventAggregator _eventAggregator;
|
private readonly IEventAggregator _eventAggregator;
|
||||||
private readonly IHistoryService _historyService;
|
private readonly IHistoryService _historyService;
|
||||||
|
private readonly IProvideImportItemService _importItemService;
|
||||||
private readonly IDownloadedMovieImportService _downloadedMovieImportService;
|
private readonly IDownloadedMovieImportService _downloadedMovieImportService;
|
||||||
private readonly IParsingService _parsingService;
|
private readonly IParsingService _parsingService;
|
||||||
private readonly IMovieService _movieService;
|
private readonly IMovieService _movieService;
|
||||||
@ -35,6 +36,7 @@ public class CompletedDownloadService : ICompletedDownloadService
|
|||||||
|
|
||||||
public CompletedDownloadService(IEventAggregator eventAggregator,
|
public CompletedDownloadService(IEventAggregator eventAggregator,
|
||||||
IHistoryService historyService,
|
IHistoryService historyService,
|
||||||
|
IProvideImportItemService importItemService,
|
||||||
IDownloadedMovieImportService downloadedMovieImportService,
|
IDownloadedMovieImportService downloadedMovieImportService,
|
||||||
IParsingService parsingService,
|
IParsingService parsingService,
|
||||||
IMovieService movieService,
|
IMovieService movieService,
|
||||||
@ -43,6 +45,7 @@ public CompletedDownloadService(IEventAggregator eventAggregator,
|
|||||||
{
|
{
|
||||||
_eventAggregator = eventAggregator;
|
_eventAggregator = eventAggregator;
|
||||||
_historyService = historyService;
|
_historyService = historyService;
|
||||||
|
_importItemService = importItemService;
|
||||||
_downloadedMovieImportService = downloadedMovieImportService;
|
_downloadedMovieImportService = downloadedMovieImportService;
|
||||||
_parsingService = parsingService;
|
_parsingService = parsingService;
|
||||||
_movieService = movieService;
|
_movieService = movieService;
|
||||||
@ -57,6 +60,8 @@ public void Check(TrackedDownload trackedDownload)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trackedDownload.ImportItem = _importItemService.ProvideImportItem(trackedDownload.DownloadItem, trackedDownload.ImportItem);
|
||||||
|
|
||||||
// Only process tracked downloads that are still downloading
|
// Only process tracked downloads that are still downloading
|
||||||
if (trackedDownload.State != TrackedDownloadState.Downloading)
|
if (trackedDownload.State != TrackedDownloadState.Downloading)
|
||||||
{
|
{
|
||||||
@ -71,7 +76,7 @@ public void Check(TrackedDownload trackedDownload)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var downloadItemOutputPath = trackedDownload.DownloadItem.OutputPath;
|
var downloadItemOutputPath = trackedDownload.ImportItem.OutputPath;
|
||||||
|
|
||||||
if (downloadItemOutputPath.IsEmpty)
|
if (downloadItemOutputPath.IsEmpty)
|
||||||
{
|
{
|
||||||
@ -109,7 +114,7 @@ public void Import(TrackedDownload trackedDownload)
|
|||||||
{
|
{
|
||||||
trackedDownload.State = TrackedDownloadState.Importing;
|
trackedDownload.State = TrackedDownloadState.Importing;
|
||||||
|
|
||||||
var outputPath = trackedDownload.DownloadItem.OutputPath.FullPath;
|
var outputPath = trackedDownload.ImportItem.OutputPath.FullPath;
|
||||||
|
|
||||||
if (trackedDownload.RemoteMovie?.Movie == null)
|
if (trackedDownload.RemoteMovie?.Movie == null)
|
||||||
{
|
{
|
||||||
@ -183,7 +188,7 @@ public bool VerifyImport(TrackedDownload trackedDownload, List<ImportResult> imp
|
|||||||
.Property("MovieId", trackedDownload.RemoteMovie.Movie.Id)
|
.Property("MovieId", trackedDownload.RemoteMovie.Movie.Id)
|
||||||
.Property("DownloadId", trackedDownload.DownloadItem.DownloadId)
|
.Property("DownloadId", trackedDownload.DownloadItem.DownloadId)
|
||||||
.Property("Title", trackedDownload.DownloadItem.Title)
|
.Property("Title", trackedDownload.DownloadItem.Title)
|
||||||
.Property("Path", trackedDownload.DownloadItem.OutputPath.ToString())
|
.Property("Path", trackedDownload.ImportItem.OutputPath.ToString())
|
||||||
.WriteSentryWarn("DownloadHistoryIncomplete")
|
.WriteSentryWarn("DownloadHistoryIncomplete")
|
||||||
.Write();
|
.Write();
|
||||||
}
|
}
|
||||||
|
@ -66,6 +66,12 @@ public abstract DownloadProtocol Protocol
|
|||||||
|
|
||||||
public abstract string Download(RemoteMovie remoteMovie);
|
public abstract string Download(RemoteMovie remoteMovie);
|
||||||
public abstract IEnumerable<DownloadClientItem> GetItems();
|
public abstract IEnumerable<DownloadClientItem> GetItems();
|
||||||
|
|
||||||
|
public virtual DownloadClientItem GetImportItem(DownloadClientItem item, DownloadClientItem previousImportAttempt)
|
||||||
|
{
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
public abstract void RemoveItem(string downloadId, bool deleteData);
|
public abstract void RemoveItem(string downloadId, bool deleteData);
|
||||||
public abstract DownloadClientInfo GetStatus();
|
public abstract DownloadClientInfo GetStatus();
|
||||||
|
|
||||||
|
@ -25,6 +25,11 @@ public class DownloadClientItem
|
|||||||
public bool CanMoveFiles { get; set; }
|
public bool CanMoveFiles { get; set; }
|
||||||
public bool CanBeRemoved { get; set; }
|
public bool CanBeRemoved { get; set; }
|
||||||
public bool Removed { get; set; }
|
public bool Removed { get; set; }
|
||||||
|
|
||||||
|
public DownloadClientItem Clone()
|
||||||
|
{
|
||||||
|
return MemberwiseClone() as DownloadClientItem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DownloadClientItemClientInfo
|
public class DownloadClientItemClientInfo
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using NzbDrone.Common.Disk;
|
||||||
using NzbDrone.Core.Indexers;
|
using NzbDrone.Core.Indexers;
|
||||||
using NzbDrone.Core.Parser.Model;
|
using NzbDrone.Core.Parser.Model;
|
||||||
using NzbDrone.Core.ThingiProvider;
|
using NzbDrone.Core.ThingiProvider;
|
||||||
@ -10,6 +11,7 @@ public interface IDownloadClient : IProvider
|
|||||||
DownloadProtocol Protocol { get; }
|
DownloadProtocol Protocol { get; }
|
||||||
string Download(RemoteMovie remoteMovie);
|
string Download(RemoteMovie remoteMovie);
|
||||||
IEnumerable<DownloadClientItem> GetItems();
|
IEnumerable<DownloadClientItem> GetItems();
|
||||||
|
DownloadClientItem GetImportItem(DownloadClientItem item, DownloadClientItem previousImportAttempt);
|
||||||
void RemoveItem(string downloadId, bool deleteData);
|
void RemoveItem(string downloadId, bool deleteData);
|
||||||
DownloadClientInfo GetStatus();
|
DownloadClientInfo GetStatus();
|
||||||
void MarkItemAsImported(DownloadClientItem downloadClientItem);
|
void MarkItemAsImported(DownloadClientItem downloadClientItem);
|
||||||
|
24
src/NzbDrone.Core/Download/PrepareImportService.cs
Normal file
24
src/NzbDrone.Core/Download/PrepareImportService.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
namespace NzbDrone.Core.Download
|
||||||
|
{
|
||||||
|
public interface IProvideImportItemService
|
||||||
|
{
|
||||||
|
DownloadClientItem ProvideImportItem(DownloadClientItem item, DownloadClientItem previousImportAttempt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ProvideImportItemService : IProvideImportItemService
|
||||||
|
{
|
||||||
|
private readonly IProvideDownloadClient _downloadClientProvider;
|
||||||
|
|
||||||
|
public ProvideImportItemService(IProvideDownloadClient downloadClientProvider)
|
||||||
|
{
|
||||||
|
_downloadClientProvider = downloadClientProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DownloadClientItem ProvideImportItem(DownloadClientItem item, DownloadClientItem previousImportAttempt)
|
||||||
|
{
|
||||||
|
var client = _downloadClientProvider.Get(item.DownloadClientInfo.Id);
|
||||||
|
|
||||||
|
return client.GetImportItem(item, previousImportAttempt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,7 @@ public class TrackedDownload
|
|||||||
{
|
{
|
||||||
public int DownloadClient { get; set; }
|
public int DownloadClient { get; set; }
|
||||||
public DownloadClientItem DownloadItem { get; set; }
|
public DownloadClientItem DownloadItem { get; set; }
|
||||||
|
public DownloadClientItem ImportItem { get; set; }
|
||||||
public TrackedDownloadState State { get; set; }
|
public TrackedDownloadState State { get; set; }
|
||||||
public TrackedDownloadStatus Status { get; private set; }
|
public TrackedDownloadStatus Status { get; private set; }
|
||||||
public RemoteMovie RemoteMovie { get; set; }
|
public RemoteMovie RemoteMovie { get; set; }
|
||||||
|
@ -73,7 +73,7 @@ public List<ManualImportItem> GetMediaFiles(string path, string downloadId, int?
|
|||||||
return new List<ManualImportItem>();
|
return new List<ManualImportItem>();
|
||||||
}
|
}
|
||||||
|
|
||||||
path = trackedDownload.DownloadItem.OutputPath.FullPath;
|
path = trackedDownload.ImportItem.OutputPath.FullPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_diskProvider.FolderExists(path))
|
if (!_diskProvider.FolderExists(path))
|
||||||
@ -305,14 +305,15 @@ public void Execute(ManualImportCommand message)
|
|||||||
var trackedDownload = groupedTrackedDownload.First().TrackedDownload;
|
var trackedDownload = groupedTrackedDownload.First().TrackedDownload;
|
||||||
|
|
||||||
var importMovie = groupedTrackedDownload.First().ImportResult.ImportDecision.LocalMovie.Movie;
|
var importMovie = groupedTrackedDownload.First().ImportResult.ImportDecision.LocalMovie.Movie;
|
||||||
|
var outputPath = trackedDownload.ImportItem.OutputPath.FullPath;
|
||||||
|
|
||||||
if (_diskProvider.FolderExists(trackedDownload.DownloadItem.OutputPath.FullPath))
|
if (_diskProvider.FolderExists(outputPath))
|
||||||
{
|
{
|
||||||
if (_downloadedMovieImportService.ShouldDeleteFolder(
|
if (_downloadedMovieImportService.ShouldDeleteFolder(
|
||||||
new DirectoryInfo(trackedDownload.DownloadItem.OutputPath.FullPath),
|
new DirectoryInfo(outputPath),
|
||||||
importMovie) && trackedDownload.DownloadItem.CanMoveFiles)
|
importMovie) && trackedDownload.DownloadItem.CanMoveFiles)
|
||||||
{
|
{
|
||||||
_diskProvider.DeleteFolder(trackedDownload.DownloadItem.OutputPath.FullPath, true);
|
_diskProvider.DeleteFolder(outputPath, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user