mirror of https://github.com/lidarr/Lidarr
New: Only scan files that are new or updated (#760)
* New: Only scan files that are new or updated Pass through filter correctly Add more tests Add tests for migration 30 * Fix windows disk provider * Don't publish deleted event for unmapped file * Fix test on windows
This commit is contained in:
parent
8fe8aec97c
commit
166fc90454
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using Nancy;
|
||||
using NzbDrone.Common.Disk;
|
||||
|
@ -62,9 +63,9 @@ namespace Lidarr.Api.V1.FileSystem
|
|||
}
|
||||
|
||||
return _diskScanService.GetAudioFiles(path).Select(f => new {
|
||||
Path = f,
|
||||
RelativePath = path.GetRelativePath(f),
|
||||
Name = Path.GetFileName(f)
|
||||
Path = f.FullName,
|
||||
RelativePath = path.GetRelativePath(f.FullName),
|
||||
Name = f.Name
|
||||
}).AsResponse();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,6 +72,9 @@
|
|||
<Reference Include="NodaTime, Version=1.3.0.0, Culture=neutral, PublicKeyToken=4226afe0d9b296d1, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Ical.Net.2.2.32\lib\net46\NodaTime.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.Abstractions, Version=4.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IO.Abstractions.4.0.11\lib\net40\System.IO.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
|
|
|
@ -7,6 +7,7 @@ using NzbDrone.Core.Music;
|
|||
using NLog;
|
||||
using Nancy;
|
||||
using Lidarr.Http;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
|
||||
namespace Lidarr.Api.V1.ManualImport
|
||||
{
|
||||
|
@ -43,10 +44,10 @@ namespace Lidarr.Api.V1.ManualImport
|
|||
{
|
||||
var folder = (string)Request.Query.folder;
|
||||
var downloadId = (string)Request.Query.downloadId;
|
||||
var filterExistingFiles = Request.GetBooleanQueryParameter("filterExistingFiles", true);
|
||||
var filter = Request.GetBooleanQueryParameter("filterExistingFiles", true) ? FilterFilesType.Matched : FilterFilesType.None;
|
||||
var replaceExistingFiles = Request.GetBooleanQueryParameter("replaceExistingFiles", true);
|
||||
|
||||
return _manualImportService.GetMediaFiles(folder, downloadId, filterExistingFiles, replaceExistingFiles).ToResource().Select(AddQualityWeight).ToList();
|
||||
return _manualImportService.GetMediaFiles(folder, downloadId, filter, replaceExistingFiles).ToResource().Select(AddQualityWeight).ToList();
|
||||
}
|
||||
|
||||
private ManualImportResource AddQualityWeight(ManualImportResource item)
|
||||
|
|
|
@ -150,7 +150,6 @@ namespace Lidarr.Api.V1.TrackFiles
|
|||
}
|
||||
|
||||
var artist = trackFile.Artist.Value;
|
||||
var fullPath = Path.Combine(artist.Path, trackFile.RelativePath);
|
||||
|
||||
_mediaFileDeletionService.DeleteTrackFile(artist, trackFile);
|
||||
}
|
||||
|
@ -163,8 +162,6 @@ namespace Lidarr.Api.V1.TrackFiles
|
|||
|
||||
foreach (var trackFile in trackFiles)
|
||||
{
|
||||
var fullPath = Path.Combine(artist.Path, trackFile.RelativePath);
|
||||
|
||||
_mediaFileDeletionService.DeleteTrackFile(artist, trackFile);
|
||||
}
|
||||
|
||||
|
@ -173,6 +170,12 @@ namespace Lidarr.Api.V1.TrackFiles
|
|||
|
||||
public void Handle(TrackFileAddedEvent message)
|
||||
{
|
||||
// don't process files that are added but not matched
|
||||
if (message.TrackFile.AlbumId == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BroadcastResourceChange(ModelAction.Updated, message.TrackFile.ToResource(message.TrackFile.Artist.Value, _upgradableSpecification));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using NzbDrone.Core.DecisionEngine.Specifications;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using Lidarr.Http.REST;
|
||||
using NzbDrone.Common.Extensions;
|
||||
|
||||
namespace Lidarr.Api.V1.TrackFiles
|
||||
{
|
||||
|
@ -38,8 +38,8 @@ namespace Lidarr.Api.V1.TrackFiles
|
|||
|
||||
ArtistId = model.Artist.Value.Id,
|
||||
AlbumId = model.AlbumId,
|
||||
RelativePath = model.RelativePath,
|
||||
//Path
|
||||
RelativePath = model.Artist.Value.Path.GetRelativePath(model.Path),
|
||||
Path = model.Path,
|
||||
Size = model.Size,
|
||||
DateAdded = model.DateAdded,
|
||||
// SceneName = model.SceneName,
|
||||
|
@ -61,8 +61,8 @@ namespace Lidarr.Api.V1.TrackFiles
|
|||
|
||||
ArtistId = artist.Id,
|
||||
AlbumId = model.AlbumId,
|
||||
RelativePath = model.RelativePath,
|
||||
Path = Path.Combine(artist.Path, model.RelativePath),
|
||||
Path = model.Path,
|
||||
RelativePath = artist.Path.GetRelativePath(model.Path),
|
||||
Size = model.Size,
|
||||
DateAdded = model.DateAdded,
|
||||
//SceneName = model.SceneName,
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
|
@ -15,7 +16,7 @@ namespace NzbDrone.Common.Test.DiskTests
|
|||
private const string RECYCLING_BIN = "$Recycle.Bin";
|
||||
private const string SYSTEM_VOLUME_INFORMATION = "System Volume Information";
|
||||
private const string WINDOWS = "Windows";
|
||||
private List<DirectoryInfo> _folders;
|
||||
private List<IDirectoryInfo> _folders;
|
||||
|
||||
private void SetupFolders(string root)
|
||||
{
|
||||
|
@ -36,7 +37,7 @@ namespace NzbDrone.Common.Test.DiskTests
|
|||
WINDOWS
|
||||
};
|
||||
|
||||
_folders = folders.Select(f => new DirectoryInfo(Path.Combine(root, f))).ToList();
|
||||
_folders = folders.Select(f => (DirectoryInfoBase)new DirectoryInfo(Path.Combine(root, f))).ToList<IDirectoryInfo>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using FluentAssertions;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Disk;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
|
@ -981,48 +982,50 @@ namespace NzbDrone.Common.Test.DiskTests
|
|||
|
||||
// Note: never returns anything.
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(v => v.GetDirectoryInfos(It.IsAny<string>()))
|
||||
.Returns(new List<DirectoryInfo>());
|
||||
.Setup(v => v.GetDirectoryInfos(It.IsAny<string>()))
|
||||
.Returns(new List<IDirectoryInfo>());
|
||||
|
||||
// Note: never returns anything.
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(v => v.GetFileInfos(It.IsAny<string>()))
|
||||
.Returns(new List<FileInfo>());
|
||||
.Setup(v => v.GetFileInfos(It.IsAny<string>(), It.IsAny<SearchOption>()))
|
||||
.Returns(new List<IFileInfo>());
|
||||
}
|
||||
|
||||
private void WithRealDiskProvider()
|
||||
{
|
||||
IFileSystem _fileSystem = new FileSystem();
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(v => v.FolderExists(It.IsAny<string>()))
|
||||
.Returns<string>(v => Directory.Exists(v));
|
||||
.Returns<string>(v => _fileSystem.Directory.Exists(v));
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(v => v.FileExists(It.IsAny<string>()))
|
||||
.Returns<string>(v => File.Exists(v));
|
||||
.Returns<string>(v => _fileSystem.File.Exists(v));
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(v => v.CreateFolder(It.IsAny<string>()))
|
||||
.Callback<string>(v => Directory.CreateDirectory(v));
|
||||
.Callback<string>(v => _fileSystem.Directory.CreateDirectory(v));
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(v => v.DeleteFolder(It.IsAny<string>(), It.IsAny<bool>()))
|
||||
.Callback<string, bool>((v, r) => Directory.Delete(v, r));
|
||||
.Callback<string, bool>((v, r) => _fileSystem.Directory.Delete(v, r));
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(v => v.DeleteFile(It.IsAny<string>()))
|
||||
.Callback<string>(v => File.Delete(v));
|
||||
.Callback<string>(v => _fileSystem.File.Delete(v));
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(v => v.GetDirectoryInfos(It.IsAny<string>()))
|
||||
.Returns<string>(v => new DirectoryInfo(v).GetDirectories().ToList());
|
||||
.Returns<string>(v => _fileSystem.DirectoryInfo.FromDirectoryName(v).GetDirectories().ToList());
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(v => v.GetFileInfos(It.IsAny<string>()))
|
||||
.Returns<string>(v => new DirectoryInfo(v).GetFiles().ToList());
|
||||
.Setup(v => v.GetFileInfos(It.IsAny<string>(), It.IsAny<SearchOption>()))
|
||||
.Returns((string v, SearchOption option) => _fileSystem.DirectoryInfo.FromDirectoryName(v).GetFiles("*", option).ToList());
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(v => v.GetFileSize(It.IsAny<string>()))
|
||||
.Returns<string>(v => new FileInfo(v).Length);
|
||||
.Returns<string>(v => _fileSystem.FileInfo.FromFileName(v).Length);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(v => v.TryCreateHardLink(It.IsAny<string>(), It.IsAny<string>()))
|
||||
|
@ -1030,13 +1033,13 @@ namespace NzbDrone.Common.Test.DiskTests
|
|||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(v => v.CopyFile(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>()))
|
||||
.Callback<string, string, bool>((s, d, o) => File.Copy(s, d, o));
|
||||
.Callback<string, string, bool>((s, d, o) => _fileSystem.File.Copy(s, d, o));
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(v => v.MoveFile(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<bool>()))
|
||||
.Callback<string, string, bool>((s, d, o) => {
|
||||
if (File.Exists(d) && o) File.Delete(d);
|
||||
File.Move(s, d);
|
||||
if (_fileSystem.File.Exists(d) && o) _fileSystem.File.Delete(d);
|
||||
_fileSystem.File.Move(s, d);
|
||||
});
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
|
|
|
@ -55,6 +55,12 @@
|
|||
<Reference Include="nunit.framework, Version=3.11.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NUnit.3.11.0\lib\net45\nunit.framework.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.Abstractions, Version=4.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IO.Abstractions.4.0.11\lib\net40\System.IO.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Practices.Unity, Version=2.1.505.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\Unity.2.1.505.2\lib\NET35\Microsoft.Practices.Unity.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data" />
|
||||
|
|
|
@ -43,6 +43,7 @@ namespace NzbDrone.Common.Test
|
|||
result.Should().Be(clean);
|
||||
}
|
||||
|
||||
[TestCase(@"/", @"/")]
|
||||
[TestCase(@"/test/", @"/test")]
|
||||
[TestCase(@"//test/", @"/test")]
|
||||
[TestCase(@"//test//", @"/test")]
|
||||
|
|
|
@ -4,4 +4,6 @@
|
|||
<package id="Moq" version="4.0.10827" targetFramework="net461" />
|
||||
<package id="NLog" version="4.5.4" targetFramework="net461" />
|
||||
<package id="NUnit" version="3.11.0" targetFramework="net461" />
|
||||
</packages>
|
||||
<package id="Unity" version="2.1.505.2" targetFramework="net461" />
|
||||
<package id="System.IO.Abstractions" version="4.0.11" targetFramework="net461" />
|
||||
</packages>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using System.Security.AccessControl;
|
||||
using System.Security.Principal;
|
||||
|
@ -15,6 +16,12 @@ namespace NzbDrone.Common.Disk
|
|||
public abstract class DiskProviderBase : IDiskProvider
|
||||
{
|
||||
private static readonly Logger Logger = NzbDroneLogger.GetLogger(typeof(DiskProviderBase));
|
||||
protected readonly IFileSystem _fileSystem;
|
||||
|
||||
public DiskProviderBase(IFileSystem fileSystem)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
}
|
||||
|
||||
public static StringComparison PathStringComparison
|
||||
{
|
||||
|
@ -38,7 +45,7 @@ namespace NzbDrone.Common.Disk
|
|||
{
|
||||
CheckFolderExists(path);
|
||||
|
||||
return new DirectoryInfo(path).CreationTimeUtc;
|
||||
return _fileSystem.DirectoryInfo.FromDirectoryName(path).CreationTimeUtc;
|
||||
}
|
||||
|
||||
public DateTime FolderGetLastWrite(string path)
|
||||
|
@ -49,17 +56,17 @@ namespace NzbDrone.Common.Disk
|
|||
|
||||
if (!dirFiles.Any())
|
||||
{
|
||||
return new DirectoryInfo(path).LastWriteTimeUtc;
|
||||
return _fileSystem.DirectoryInfo.FromDirectoryName(path).LastWriteTimeUtc;
|
||||
}
|
||||
|
||||
return dirFiles.Select(f => new FileInfo(f)).Max(c => c.LastWriteTimeUtc);
|
||||
return dirFiles.Select(f => _fileSystem.FileInfo.FromFileName(f)).Max(c => c.LastWriteTimeUtc);
|
||||
}
|
||||
|
||||
public DateTime FileGetLastWrite(string path)
|
||||
{
|
||||
CheckFileExists(path);
|
||||
|
||||
return new FileInfo(path).LastWriteTimeUtc;
|
||||
return _fileSystem.FileInfo.FromFileName(path).LastWriteTimeUtc;
|
||||
}
|
||||
|
||||
private void CheckFolderExists(string path)
|
||||
|
@ -93,7 +100,7 @@ namespace NzbDrone.Common.Disk
|
|||
public bool FolderExists(string path)
|
||||
{
|
||||
Ensure.That(path, () => path).IsValidPath();
|
||||
return Directory.Exists(path);
|
||||
return _fileSystem.Directory.Exists(path);
|
||||
}
|
||||
|
||||
public bool FileExists(string path)
|
||||
|
@ -112,11 +119,11 @@ namespace NzbDrone.Common.Disk
|
|||
case StringComparison.InvariantCulture:
|
||||
case StringComparison.Ordinal:
|
||||
{
|
||||
return File.Exists(path) && path == path.GetActualCasing();
|
||||
return _fileSystem.File.Exists(path) && path == path.GetActualCasing();
|
||||
}
|
||||
default:
|
||||
{
|
||||
return File.Exists(path);
|
||||
return _fileSystem.File.Exists(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -129,8 +136,8 @@ namespace NzbDrone.Common.Disk
|
|||
{
|
||||
var testPath = Path.Combine(path, "lidarr_write_test.txt");
|
||||
var testContent = $"This file was created to verify if '{path}' is writable. It should've been automatically deleted. Feel free to delete it.";
|
||||
File.WriteAllText(testPath, testContent);
|
||||
File.Delete(testPath);
|
||||
_fileSystem.File.WriteAllText(testPath, testContent);
|
||||
_fileSystem.File.Delete(testPath);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -144,21 +151,21 @@ namespace NzbDrone.Common.Disk
|
|||
{
|
||||
Ensure.That(path, () => path).IsValidPath();
|
||||
|
||||
return Directory.GetDirectories(path);
|
||||
return _fileSystem.Directory.GetDirectories(path);
|
||||
}
|
||||
|
||||
public string[] GetFiles(string path, SearchOption searchOption)
|
||||
{
|
||||
Ensure.That(path, () => path).IsValidPath();
|
||||
|
||||
return Directory.GetFiles(path, "*.*", searchOption);
|
||||
return _fileSystem.Directory.GetFiles(path, "*.*", searchOption);
|
||||
}
|
||||
|
||||
public long GetFolderSize(string path)
|
||||
{
|
||||
Ensure.That(path, () => path).IsValidPath();
|
||||
|
||||
return GetFiles(path, SearchOption.AllDirectories).Sum(e => new FileInfo(e).Length);
|
||||
return GetFiles(path, SearchOption.AllDirectories).Sum(e => _fileSystem.FileInfo.FromFileName(e).Length);
|
||||
}
|
||||
|
||||
public long GetFileSize(string path)
|
||||
|
@ -170,14 +177,14 @@ namespace NzbDrone.Common.Disk
|
|||
throw new FileNotFoundException("File doesn't exist: " + path);
|
||||
}
|
||||
|
||||
var fi = new FileInfo(path);
|
||||
var fi = _fileSystem.FileInfo.FromFileName(path);
|
||||
return fi.Length;
|
||||
}
|
||||
|
||||
public void CreateFolder(string path)
|
||||
{
|
||||
Ensure.That(path, () => path).IsValidPath();
|
||||
Directory.CreateDirectory(path);
|
||||
_fileSystem.Directory.CreateDirectory(path);
|
||||
}
|
||||
|
||||
public void DeleteFile(string path)
|
||||
|
@ -187,7 +194,7 @@ namespace NzbDrone.Common.Disk
|
|||
|
||||
RemoveReadOnly(path);
|
||||
|
||||
File.Delete(path);
|
||||
_fileSystem.File.Delete(path);
|
||||
}
|
||||
|
||||
public void CopyFile(string source, string destination, bool overwrite = false)
|
||||
|
@ -205,7 +212,7 @@ namespace NzbDrone.Common.Disk
|
|||
|
||||
protected virtual void CopyFileInternal(string source, string destination, bool overwrite = false)
|
||||
{
|
||||
File.Copy(source, destination, overwrite);
|
||||
_fileSystem.File.Copy(source, destination, overwrite);
|
||||
}
|
||||
|
||||
public void MoveFile(string source, string destination, bool overwrite = false)
|
||||
|
@ -237,7 +244,7 @@ namespace NzbDrone.Common.Disk
|
|||
|
||||
protected virtual void MoveFileInternal(string source, string destination)
|
||||
{
|
||||
File.Move(source, destination);
|
||||
_fileSystem.File.Move(source, destination);
|
||||
}
|
||||
|
||||
public abstract bool TryCreateHardLink(string source, string destination);
|
||||
|
@ -246,45 +253,45 @@ namespace NzbDrone.Common.Disk
|
|||
{
|
||||
Ensure.That(path, () => path).IsValidPath();
|
||||
|
||||
var files = Directory.GetFiles(path, "*.*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
|
||||
var files = _fileSystem.Directory.GetFiles(path, "*.*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
|
||||
Array.ForEach(files, RemoveReadOnly);
|
||||
|
||||
Directory.Delete(path, recursive);
|
||||
_fileSystem.Directory.Delete(path, recursive);
|
||||
}
|
||||
|
||||
public string ReadAllText(string filePath)
|
||||
{
|
||||
Ensure.That(filePath, () => filePath).IsValidPath();
|
||||
|
||||
return File.ReadAllText(filePath);
|
||||
return _fileSystem.File.ReadAllText(filePath);
|
||||
}
|
||||
|
||||
public void WriteAllText(string filename, string contents)
|
||||
{
|
||||
Ensure.That(filename, () => filename).IsValidPath();
|
||||
RemoveReadOnly(filename);
|
||||
File.WriteAllText(filename, contents);
|
||||
_fileSystem.File.WriteAllText(filename, contents);
|
||||
}
|
||||
|
||||
public void FolderSetLastWriteTime(string path, DateTime dateTime)
|
||||
{
|
||||
Ensure.That(path, () => path).IsValidPath();
|
||||
|
||||
Directory.SetLastWriteTimeUtc(path, dateTime);
|
||||
_fileSystem.Directory.SetLastWriteTimeUtc(path, dateTime);
|
||||
}
|
||||
|
||||
public void FileSetLastWriteTime(string path, DateTime dateTime)
|
||||
{
|
||||
Ensure.That(path, () => path).IsValidPath();
|
||||
|
||||
File.SetLastWriteTime(path, dateTime);
|
||||
_fileSystem.File.SetLastWriteTime(path, dateTime);
|
||||
}
|
||||
|
||||
public bool IsFileLocked(string file)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (File.Open(file, FileMode.Open, FileAccess.Read, FileShare.None))
|
||||
using (_fileSystem.File.Open(file, FileMode.Open, FileAccess.Read, FileShare.None))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -306,7 +313,7 @@ namespace NzbDrone.Common.Disk
|
|||
{
|
||||
Ensure.That(path, () => path).IsValidPath();
|
||||
|
||||
var parent = Directory.GetParent(path.TrimEnd(Path.DirectorySeparatorChar));
|
||||
var parent = _fileSystem.Directory.GetParent(path.TrimEnd(Path.DirectorySeparatorChar));
|
||||
|
||||
if (parent == null)
|
||||
{
|
||||
|
@ -322,7 +329,7 @@ namespace NzbDrone.Common.Disk
|
|||
{
|
||||
var sid = new SecurityIdentifier(accountSid, null);
|
||||
|
||||
var directoryInfo = new DirectoryInfo(filename);
|
||||
var directoryInfo = _fileSystem.DirectoryInfo.FromDirectoryName(filename);
|
||||
var directorySecurity = directoryInfo.GetAccessControl(AccessControlSections.Access);
|
||||
|
||||
var rules = directorySecurity.GetAccessRules(true, false, typeof(SecurityIdentifier));
|
||||
|
@ -368,7 +375,7 @@ namespace NzbDrone.Common.Disk
|
|||
|
||||
public FileAttributes GetFileAttributes(string path)
|
||||
{
|
||||
return File.GetAttributes(path);
|
||||
return _fileSystem.File.GetAttributes(path);
|
||||
}
|
||||
|
||||
public void EmptyFolder(string path)
|
||||
|
@ -410,12 +417,12 @@ namespace NzbDrone.Common.Disk
|
|||
throw new FileNotFoundException("Unable to find file: " + path, path);
|
||||
}
|
||||
|
||||
return new FileStream(path, FileMode.Open, FileAccess.Read);
|
||||
return (FileStream) _fileSystem.FileStream.Create(path, FileMode.Open, FileAccess.Read);
|
||||
}
|
||||
|
||||
public FileStream OpenWriteStream(string path)
|
||||
{
|
||||
return new FileStream(path, FileMode.Create);
|
||||
return (FileStream) _fileSystem.FileStream.Create(path, FileMode.Create);
|
||||
}
|
||||
|
||||
public List<IMount> GetMounts()
|
||||
|
@ -454,29 +461,41 @@ namespace NzbDrone.Common.Disk
|
|||
}
|
||||
}
|
||||
|
||||
protected List<DriveInfo> GetDriveInfoMounts()
|
||||
protected List<IDriveInfo> GetDriveInfoMounts()
|
||||
{
|
||||
return DriveInfo.GetDrives()
|
||||
.Where(d => d.IsReady)
|
||||
.ToList();
|
||||
return _fileSystem.DriveInfo.GetDrives()
|
||||
.Where(d => d.IsReady)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public List<DirectoryInfo> GetDirectoryInfos(string path)
|
||||
public List<IDirectoryInfo> GetDirectoryInfos(string path)
|
||||
{
|
||||
Ensure.That(path, () => path).IsValidPath();
|
||||
|
||||
var di = new DirectoryInfo(path);
|
||||
var di = _fileSystem.DirectoryInfo.FromDirectoryName(path);
|
||||
|
||||
return di.GetDirectories().ToList();
|
||||
}
|
||||
|
||||
public List<FileInfo> GetFileInfos(string path)
|
||||
public IDirectoryInfo GetDirectoryInfo(string path)
|
||||
{
|
||||
Ensure.That(path, () => path).IsValidPath();
|
||||
return _fileSystem.DirectoryInfo.FromDirectoryName(path);
|
||||
}
|
||||
|
||||
public List<IFileInfo> GetFileInfos(string path, SearchOption searchOption = SearchOption.TopDirectoryOnly)
|
||||
{
|
||||
Ensure.That(path, () => path).IsValidPath();
|
||||
|
||||
var di = new DirectoryInfo(path);
|
||||
var di = _fileSystem.DirectoryInfo.FromDirectoryName(path);
|
||||
|
||||
return di.GetFiles().ToList();
|
||||
return di.GetFiles("*", searchOption).ToList();
|
||||
}
|
||||
|
||||
public IFileInfo GetFileInfo(string path)
|
||||
{
|
||||
Ensure.That(path, () => path).IsValidPath();
|
||||
return _fileSystem.FileInfo.FromFileName(path);
|
||||
}
|
||||
|
||||
public void RemoveEmptySubfolders(string path)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using NLog;
|
||||
|
@ -594,7 +595,7 @@ namespace NzbDrone.Common.Disk
|
|||
}
|
||||
}
|
||||
|
||||
private bool ShouldIgnore(DirectoryInfo folder)
|
||||
private bool ShouldIgnore(IDirectoryInfo folder)
|
||||
{
|
||||
if (folder.Name.StartsWith(".nfs"))
|
||||
{
|
||||
|
@ -605,7 +606,7 @@ namespace NzbDrone.Common.Disk
|
|||
return false;
|
||||
}
|
||||
|
||||
private bool ShouldIgnore(FileInfo file)
|
||||
private bool ShouldIgnore(IFileInfo file)
|
||||
{
|
||||
if (file.Name.StartsWith(".nfs") || file.Name == "debug.log" || file.Name.EndsWith(".socket"))
|
||||
{
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using NzbDrone.Common.Extensions;
|
||||
|
||||
namespace NzbDrone.Common.Disk
|
||||
{
|
||||
public class DriveInfoMount : IMount
|
||||
{
|
||||
private readonly DriveInfo _driveInfo;
|
||||
private readonly IDriveInfo _driveInfo;
|
||||
private readonly DriveType _driveType;
|
||||
|
||||
public DriveInfoMount(DriveInfo driveInfo, DriveType driveType = DriveType.Unknown, MountOptions mountOptions = null)
|
||||
public DriveInfoMount(IDriveInfo driveInfo, DriveType driveType = DriveType.Unknown, MountOptions mountOptions = null)
|
||||
{
|
||||
_driveInfo = driveInfo;
|
||||
_driveType = driveType;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Security.AccessControl;
|
||||
using System.Security.Principal;
|
||||
|
||||
|
@ -46,8 +47,10 @@ namespace NzbDrone.Common.Disk
|
|||
FileStream OpenWriteStream(string path);
|
||||
List<IMount> GetMounts();
|
||||
IMount GetMount(string path);
|
||||
List<DirectoryInfo> GetDirectoryInfos(string path);
|
||||
List<FileInfo> GetFileInfos(string path);
|
||||
IDirectoryInfo GetDirectoryInfo(string path);
|
||||
List<IDirectoryInfo> GetDirectoryInfos(string path);
|
||||
IFileInfo GetFileInfo(string path);
|
||||
List<IFileInfo> GetFileInfos(string path, SearchOption searchOption = SearchOption.TopDirectoryOnly);
|
||||
void RemoveEmptySubfolders(string path);
|
||||
void SaveStream(Stream stream, string path);
|
||||
}
|
||||
|
|
|
@ -38,6 +38,11 @@ namespace NzbDrone.Common.Extensions
|
|||
return info.FullName.TrimEnd('/', '\\', ' ');
|
||||
}
|
||||
|
||||
if (OsInfo.IsNotWindows && info.FullName.TrimEnd('/').Length == 0)
|
||||
{
|
||||
return "/";
|
||||
}
|
||||
|
||||
return info.FullName.TrimEnd('/').Trim('\\', ' ');
|
||||
}
|
||||
|
||||
|
|
|
@ -66,6 +66,9 @@
|
|||
<Reference Include="System.Collections.Immutable, Version=1.2.3.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Collections.Immutable.1.5.0\lib\netstandard2.0\System.Collections.Immutable.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.Abstractions, Version=4.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IO.Abstractions.4.0.11\lib\net40\System.IO.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="SocksWebProxy, Version=1.3.4.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\DotNet4.SocksProxy.1.3.4.0\lib\net40\SocksWebProxy.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
|
|
|
@ -8,4 +8,5 @@
|
|||
<package id="Sentry.PlatformAbstractions" version="1.0.0" targetFramework="net461" />
|
||||
<package id="Sentry.Protocol" version="1.0.3" targetFramework="net461" />
|
||||
<package id="System.Collections.Immutable" version="1.5.0" targetFramework="net461" />
|
||||
<package id="System.IO.Abstractions" version="4.0.11" targetFramework="net461" />
|
||||
</packages>
|
||||
|
|
|
@ -0,0 +1,321 @@
|
|||
using NUnit.Framework;
|
||||
using NzbDrone.Core.Datastore.Migration;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Common.Serializer;
|
||||
using NzbDrone.Test.Common;
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using System.IO;
|
||||
|
||||
namespace NzbDrone.Core.Test.Datastore.Migration
|
||||
{
|
||||
[TestFixture]
|
||||
public class add_mediafilerepository_mtimeFixture : MigrationTest<add_mediafilerepository_mtime>
|
||||
{
|
||||
private string _artistPath = null;
|
||||
|
||||
private void GivenArtist(add_mediafilerepository_mtime c, int id, string name)
|
||||
{
|
||||
_artistPath = $"/mnt/data/path/{name}".AsOsAgnostic();
|
||||
c.Insert.IntoTable("Artists").Row(new
|
||||
{
|
||||
Id = id,
|
||||
CleanName = name,
|
||||
Path = _artistPath,
|
||||
Monitored = 1,
|
||||
AlbumFolder = 1,
|
||||
LanguageProfileId = 1,
|
||||
MetadataProfileId = 1,
|
||||
ArtistMetadataId = id
|
||||
});
|
||||
}
|
||||
|
||||
private void GivenAlbum(add_mediafilerepository_mtime c, int id, int artistMetadataId, string title)
|
||||
{
|
||||
c.Insert.IntoTable("Albums").Row(new
|
||||
{
|
||||
Id = id,
|
||||
ForeignAlbumId = id.ToString(),
|
||||
ArtistMetadataId = artistMetadataId,
|
||||
Title = title,
|
||||
CleanTitle = title,
|
||||
Images = "",
|
||||
Monitored = 1,
|
||||
AlbumType = "Studio",
|
||||
AnyReleaseOk = 1
|
||||
});
|
||||
}
|
||||
|
||||
private void GivenAlbumRelease(add_mediafilerepository_mtime c, int id, int albumId, bool monitored)
|
||||
{
|
||||
c.Insert.IntoTable("AlbumReleases").Row(new
|
||||
{
|
||||
Id = id,
|
||||
ForeignReleaseId = id.ToString(),
|
||||
AlbumId = albumId,
|
||||
Title = "Title",
|
||||
Status = "Status",
|
||||
Duration = 0,
|
||||
Monitored = monitored
|
||||
});
|
||||
}
|
||||
|
||||
private void GivenTrackFiles(add_mediafilerepository_mtime c, List<string> tracks, int albumReleaseId, int albumId, int firstId = 1, bool addTracks = true)
|
||||
{
|
||||
int id = firstId;
|
||||
foreach (var track in tracks)
|
||||
{
|
||||
c.Insert.IntoTable("TrackFiles").Row(new
|
||||
{
|
||||
Id = id,
|
||||
RelativePath = track?.AsOsAgnostic(),
|
||||
Size = 100,
|
||||
DateAdded = DateTime.UtcNow,
|
||||
Quality = new QualityModel(Quality.FLAC).ToJson(),
|
||||
Language = 1,
|
||||
AlbumId = albumId
|
||||
});
|
||||
|
||||
if (addTracks)
|
||||
{
|
||||
c.Insert.IntoTable("Tracks").Row(new
|
||||
{
|
||||
Id = id,
|
||||
ForeignTrackId = id.ToString(),
|
||||
Explicit = 0,
|
||||
TrackFileId = id,
|
||||
Duration = 100,
|
||||
MediumNumber = 1,
|
||||
AbsoluteTrackNumber = 1,
|
||||
ForeignRecordingId = id.ToString(),
|
||||
AlbumReleaseId = albumReleaseId,
|
||||
ArtistMetadataId = 0
|
||||
});
|
||||
}
|
||||
|
||||
id++;
|
||||
}
|
||||
}
|
||||
|
||||
private void VerifyTracksFiles(IDirectDataMapper db, int albumId, List<string> expectedPaths)
|
||||
{
|
||||
var tracks = db.Query("SELECT TrackFiles.* FROM TrackFiles " +
|
||||
"WHERE TrackFiles.AlbumId = " + albumId);
|
||||
|
||||
TestLogger.Debug($"Got {tracks.Count} tracks");
|
||||
|
||||
tracks.Select(x => x["Path"]).Should().BeEquivalentTo(expectedPaths);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void migration_030_simple_case()
|
||||
{
|
||||
var tracks = new List<string> {
|
||||
"folder/track1.mp3",
|
||||
"folder/track2.mp3",
|
||||
};
|
||||
|
||||
var db = WithMigrationTestDb(c => {
|
||||
GivenArtist(c, 1, "TestArtist");
|
||||
GivenAlbum(c, 1, 1, "TestAlbum");
|
||||
GivenAlbumRelease(c, 1, 1, true);
|
||||
GivenTrackFiles(c, tracks, 1, 1);
|
||||
});
|
||||
|
||||
var expected = tracks.Select(x => Path.Combine(_artistPath, x)).ToList();
|
||||
|
||||
VerifyTracksFiles(db, 1, expected);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void migration_030_missing_path()
|
||||
{
|
||||
var tracks = new List<string> {
|
||||
"folder/track1.mp3",
|
||||
null,
|
||||
};
|
||||
|
||||
var db = WithMigrationTestDb(c => {
|
||||
GivenArtist(c, 1, "TestArtist");
|
||||
GivenAlbum(c, 1, 1, "TestAlbum");
|
||||
GivenAlbumRelease(c, 1, 1, true);
|
||||
GivenTrackFiles(c, tracks, 1, 1);
|
||||
});
|
||||
|
||||
var expected = tracks.GetRange(0, 1).Select(x => Path.Combine(_artistPath, x)).ToList();
|
||||
|
||||
VerifyTracksFiles(db, 1, expected);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void migration_030_bad_albumrelease_id()
|
||||
{
|
||||
var tracks = new List<string> {
|
||||
"folder/track1.mp3",
|
||||
"folder/track2.mp3"
|
||||
};
|
||||
|
||||
var db = WithMigrationTestDb(c => {
|
||||
GivenArtist(c, 1, "TestArtist");
|
||||
GivenAlbum(c, 1, 1, "TestAlbum");
|
||||
GivenAlbumRelease(c, 1, 1, true);
|
||||
GivenTrackFiles(c, tracks, 2, 1);
|
||||
});
|
||||
|
||||
VerifyTracksFiles(db, 1, new List<string>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void migration_030_bad_album_id()
|
||||
{
|
||||
var tracks = new List<string> {
|
||||
"folder/track1.mp3",
|
||||
"folder/track2.mp3"
|
||||
};
|
||||
|
||||
var db = WithMigrationTestDb(c => {
|
||||
GivenArtist(c, 1, "TestArtist");
|
||||
GivenAlbum(c, 1, 1, "TestAlbum");
|
||||
GivenAlbumRelease(c, 1, 1, true);
|
||||
GivenTrackFiles(c, tracks, 1, 2);
|
||||
});
|
||||
|
||||
VerifyTracksFiles(db, 1, new List<string>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void migration_030_bad_artist_metadata_id()
|
||||
{
|
||||
var tracks = new List<string> {
|
||||
"folder/track1.mp3",
|
||||
"folder/track2.mp3"
|
||||
};
|
||||
|
||||
var db = WithMigrationTestDb(c => {
|
||||
GivenArtist(c, 1, "TestArtist");
|
||||
GivenAlbum(c, 1, 2, "TestAlbum");
|
||||
GivenAlbumRelease(c, 1, 1, true);
|
||||
GivenTrackFiles(c, tracks, 1, 1);
|
||||
});
|
||||
|
||||
VerifyTracksFiles(db, 1, new List<string>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void migration_030_missing_artist()
|
||||
{
|
||||
var tracks = new List<string> {
|
||||
"folder/track1.mp3",
|
||||
"folder/track2.mp3"
|
||||
};
|
||||
|
||||
var db = WithMigrationTestDb(c => {
|
||||
GivenAlbum(c, 1, 1, "TestAlbum");
|
||||
GivenAlbumRelease(c, 1, 1, true);
|
||||
GivenTrackFiles(c, tracks, 1, 1);
|
||||
});
|
||||
|
||||
VerifyTracksFiles(db, 1, new List<string>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void migration_030_missing_tracks()
|
||||
{
|
||||
var tracks = new List<string> {
|
||||
"folder/track1.mp3",
|
||||
"folder/track2.mp3"
|
||||
};
|
||||
|
||||
var db = WithMigrationTestDb(c => {
|
||||
GivenArtist(c, 1, "TestArtist");
|
||||
GivenAlbum(c, 1, 1, "TestAlbum");
|
||||
GivenAlbumRelease(c, 1, 1, true);
|
||||
GivenTrackFiles(c, tracks, 1, 1, addTracks: false);
|
||||
});
|
||||
|
||||
VerifyTracksFiles(db, 1, new List<string>());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void migration_030_duplicate_files()
|
||||
{
|
||||
var tracks = new List<string> {
|
||||
"folder/track1.mp3",
|
||||
"folder/track2.mp3",
|
||||
"folder/track1.mp3",
|
||||
};
|
||||
|
||||
var db = WithMigrationTestDb(c => {
|
||||
GivenArtist(c, 1, "TestArtist");
|
||||
GivenAlbum(c, 1, 1, "TestAlbum");
|
||||
GivenAlbumRelease(c, 1, 1, true);
|
||||
GivenTrackFiles(c, tracks, 1, 1);
|
||||
});
|
||||
|
||||
var expected = tracks.GetRange(0, 2).Select(x => Path.Combine(_artistPath, x)).ToList();
|
||||
|
||||
VerifyTracksFiles(db, 1, expected);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void migration_030_unmonitored_release_duplicate()
|
||||
{
|
||||
var monitored_tracks = new List<string> {
|
||||
"folder/track1.mp3",
|
||||
"folder/track2.mp3",
|
||||
};
|
||||
|
||||
var unmonitored_tracks = new List<string> {
|
||||
"folder/track1.mp3",
|
||||
"folder/track2.mp3",
|
||||
};
|
||||
|
||||
var db = WithMigrationTestDb(c => {
|
||||
GivenArtist(c, 1, "TestArtist");
|
||||
GivenAlbum(c, 1, 1, "TestAlbum");
|
||||
|
||||
GivenAlbumRelease(c, 1, 1, true);
|
||||
GivenTrackFiles(c, monitored_tracks, 1, 1);
|
||||
|
||||
GivenAlbumRelease(c, 2, 1, false);
|
||||
GivenTrackFiles(c, unmonitored_tracks, 2, 1, firstId: 100);
|
||||
});
|
||||
|
||||
var expected = monitored_tracks.Select(x => Path.Combine(_artistPath, x)).ToList();
|
||||
|
||||
VerifyTracksFiles(db, 1, expected);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void migration_030_unmonitored_release_distinct()
|
||||
{
|
||||
var monitored_tracks = new List<string> {
|
||||
"folder/track1.mp3",
|
||||
"folder/track2.mp3",
|
||||
};
|
||||
|
||||
var unmonitored_tracks = new List<string> {
|
||||
"folder/track3.mp3",
|
||||
"folder/track4.mp3",
|
||||
};
|
||||
|
||||
var db = WithMigrationTestDb(c => {
|
||||
GivenArtist(c, 1, "TestArtist");
|
||||
GivenAlbum(c, 1, 1, "TestAlbum");
|
||||
|
||||
GivenAlbumRelease(c, 1, 1, true);
|
||||
GivenTrackFiles(c, monitored_tracks, 1, 1);
|
||||
|
||||
GivenAlbumRelease(c, 2, 1, false);
|
||||
GivenTrackFiles(c, unmonitored_tracks, 2, 1, firstId: 100);
|
||||
});
|
||||
|
||||
var expected = monitored_tracks.Select(x => Path.Combine(_artistPath, x)).ToList();
|
||||
|
||||
VerifyTracksFiles(db, 1, expected);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -34,7 +34,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
|
|||
_firstFile =
|
||||
new TrackFile{
|
||||
Id = 1,
|
||||
RelativePath = "My.Artist.S01E01.mp3",
|
||||
Path = "/My.Artist.S01E01.mp3",
|
||||
Quality = new QualityModel(Quality.FLAC, new Revision(version: 1)),
|
||||
DateAdded = DateTime.Now,
|
||||
AlbumId = 1
|
||||
|
@ -43,7 +43,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
|
|||
_secondFile =
|
||||
new TrackFile{
|
||||
Id = 2,
|
||||
RelativePath = "My.Artist.S01E02.mp3",
|
||||
Path = "/My.Artist.S01E02.mp3",
|
||||
Quality = new QualityModel(Quality.FLAC, new Revision(version: 1)),
|
||||
DateAdded = DateTime.Now,
|
||||
AlbumId = 2
|
||||
|
@ -97,7 +97,7 @@ namespace NzbDrone.Core.Test.DecisionEngineTests.RssSync
|
|||
|
||||
private void WithExistingFile(TrackFile trackFile)
|
||||
{
|
||||
var path = Path.Combine(@"C:\Music\My.Artist".AsOsAgnostic(), trackFile.RelativePath);
|
||||
var path = trackFile.Path;
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(v => v.FileExists(path))
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using FluentAssertions;
|
||||
|
@ -37,7 +38,10 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
|
|||
.Returns(1000000);
|
||||
|
||||
Mocker.GetMock<IDiskScanService>().Setup(c => c.FilterFiles(It.IsAny<string>(), It.IsAny<IEnumerable<string>>()))
|
||||
.Returns<string, IEnumerable<string>>((b, s) => s.ToList());
|
||||
.Returns<string, IEnumerable<string>>((b, s) => s.ToList());
|
||||
|
||||
Mocker.GetMock<IDiskScanService>().Setup(c => c.FilterFiles(It.IsAny<string>(), It.IsAny<IEnumerable<IFileInfo>>()))
|
||||
.Returns<string, IEnumerable<IFileInfo>>((b, s) => s.ToList());
|
||||
}
|
||||
|
||||
protected void GivenChangedItem()
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using FluentAssertions;
|
||||
|
@ -52,6 +53,9 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
|
|||
|
||||
Mocker.GetMock<IDiskScanService>().Setup(c => c.FilterFiles(It.IsAny<string>(), It.IsAny<IEnumerable<string>>()))
|
||||
.Returns<string, IEnumerable<string>>((b, s) => s.ToList());
|
||||
|
||||
Mocker.GetMock<IDiskScanService>().Setup(c => c.FilterFiles(It.IsAny<string>(), It.IsAny<IEnumerable<IFileInfo>>()))
|
||||
.Returns<string, IEnumerable<IFileInfo>>((b, s) => s.ToList());
|
||||
}
|
||||
|
||||
protected void GivenFailedDownload()
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using FluentAssertions;
|
||||
|
@ -46,6 +47,9 @@ namespace NzbDrone.Core.Test.Download.DownloadClientTests.Blackhole
|
|||
|
||||
Mocker.GetMock<IDiskScanService>().Setup(c => c.FilterFiles(It.IsAny<string>(), It.IsAny<IEnumerable<string>>()))
|
||||
.Returns<string, IEnumerable<string>>((b, s) => s.ToList());
|
||||
|
||||
Mocker.GetMock<IDiskScanService>().Setup(c => c.FilterFiles(It.IsAny<string>(), It.IsAny<IEnumerable<IFileInfo>>()))
|
||||
.Returns<string, IEnumerable<IFileInfo>>((b, s) => s.ToList());
|
||||
}
|
||||
|
||||
protected void GivenFailedDownload()
|
||||
|
|
|
@ -88,7 +88,7 @@ namespace NzbDrone.Core.Test.Framework
|
|||
value = dataRow.ItemArray[i];
|
||||
}
|
||||
|
||||
item[columnName] = dataRow.ItemArray[i];
|
||||
item[columnName] = value;
|
||||
}
|
||||
|
||||
return item;
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
using NUnit.Framework;
|
||||
using System.IO.Abstractions.TestingHelpers;
|
||||
using Microsoft.Practices.Unity;
|
||||
using NzbDrone.Common.Disk;
|
||||
namespace NzbDrone.Core.Test.Framework
|
||||
{
|
||||
public abstract class FileSystemTest<TSubject> : CoreTest<TSubject> where TSubject : class
|
||||
{
|
||||
protected MockFileSystem FileSystem { get; private set; }
|
||||
protected IDiskProvider DiskProvider { get; private set; }
|
||||
|
||||
[SetUp]
|
||||
public void FileSystemTestSetup()
|
||||
{
|
||||
FileSystem = new MockFileSystem();
|
||||
|
||||
DiskProvider = Mocker.Resolve<IDiskProvider>("ActualDiskProvider", new ResolverOverride[] {
|
||||
new ParameterOverride("fileSystem", FileSystem)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,24 +14,26 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
|
|||
public class CleanupOrphanedTrackFilesFixture : DbTest<CleanupOrphanedTrackFiles, TrackFile>
|
||||
{
|
||||
[Test]
|
||||
public void should_delete_orphaned_track_files()
|
||||
public void should_unlink_orphaned_track_files()
|
||||
{
|
||||
var trackFile = Builder<TrackFile>.CreateNew()
|
||||
.With(h => h.Quality = new QualityModel())
|
||||
.BuildNew();
|
||||
.With(h => h.Quality = new QualityModel())
|
||||
.With(h => h.AlbumId = 1)
|
||||
.BuildNew();
|
||||
|
||||
Db.Insert(trackFile);
|
||||
Subject.Clean();
|
||||
AllStoredModels.Should().BeEmpty();
|
||||
AllStoredModels[0].AlbumId.Should().Be(0);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_delete_unorphaned_track_files()
|
||||
public void should_not_unlink_unorphaned_track_files()
|
||||
{
|
||||
var trackFiles = Builder<TrackFile>.CreateListOfSize(2)
|
||||
.All()
|
||||
.With(h => h.Quality = new QualityModel())
|
||||
.BuildListOfNew();
|
||||
.All()
|
||||
.With(h => h.Quality = new QualityModel())
|
||||
.With(h => h.AlbumId = 1)
|
||||
.BuildListOfNew();
|
||||
|
||||
Db.InsertMany(trackFiles);
|
||||
|
||||
|
@ -42,7 +44,8 @@ namespace NzbDrone.Core.Test.Housekeeping.Housekeepers
|
|||
Db.Insert(track);
|
||||
|
||||
Subject.Clean();
|
||||
AllStoredModels.Should().HaveCount(1);
|
||||
AllStoredModels.Where(x => x.AlbumId == 1).Should().HaveCount(1);
|
||||
|
||||
Db.All<Track>().Should().Contain(e => e.TrackFileId == AllStoredModels.First().Id);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -119,11 +119,11 @@ namespace NzbDrone.Core.Test.Instrumentation
|
|||
public void null_string_as_arg_should_not_fail()
|
||||
{
|
||||
var epFile = new TrackFile();
|
||||
_logger.Debug("File {0} no longer exists on disk. removing from database.", epFile.RelativePath);
|
||||
_logger.Debug("File {0} no longer exists on disk. removing from database.", epFile.Path);
|
||||
|
||||
Thread.Sleep(600);
|
||||
|
||||
epFile.RelativePath.Should().BeNull();
|
||||
epFile.Path.Should().BeNull();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -186,10 +186,7 @@ namespace NzbDrone.Core.Test.MediaFiles.AudioTagServiceFixture
|
|||
var path = copiedFile;
|
||||
|
||||
var track = new TrackFile {
|
||||
Artist = new Artist {
|
||||
Path = Path.GetDirectoryName(path)
|
||||
},
|
||||
RelativePath = Path.GetFileName(path)
|
||||
Path = path
|
||||
};
|
||||
|
||||
testTags.Write(path);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using Moq;
|
||||
|
@ -13,11 +14,16 @@ using NzbDrone.Core.Music;
|
|||
using NzbDrone.Core.RootFolders;
|
||||
using NzbDrone.Test.Common;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using FluentAssertions;
|
||||
using System.IO.Abstractions.TestingHelpers;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using System;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class ScanFixture : CoreTest<DiskScanService>
|
||||
public class ScanFixture : FileSystemTest<DiskScanService>
|
||||
{
|
||||
private Artist _artist;
|
||||
private string _rootFolder;
|
||||
|
@ -34,42 +40,34 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
|
|||
.With(s => s.Path = artistFolder)
|
||||
.Build();
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.FolderExists(It.IsAny<string>()))
|
||||
.Returns(false);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.GetParentFolder(It.IsAny<string>()))
|
||||
.Returns((string path) => Directory.GetParent(path).FullName);
|
||||
|
||||
Mocker.GetMock<IRootFolderService>()
|
||||
.Setup(s => s.GetBestRootFolderPath(It.IsAny<string>()))
|
||||
.Returns(_rootFolder);
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Setup(v => v.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Artist>(), It.IsAny<bool>()))
|
||||
.Setup(v => v.GetImportDecisions(It.IsAny<List<IFileInfo>>(), It.IsAny<Artist>(), It.IsAny<FilterFilesType>(), It.IsAny<bool>()))
|
||||
.Returns(new List<ImportDecision<LocalTrack>>());
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Setup(v => v.GetFilesByArtist(It.IsAny<int>()))
|
||||
.Returns(new List<TrackFile>());
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Setup(v => v.GetFilesWithBasePath(It.IsAny<string>()))
|
||||
.Returns(new List<TrackFile>());
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Setup(v => v.FilterUnchangedFiles(It.IsAny<List<IFileInfo>>(), It.IsAny<Artist>(), It.IsAny<FilterFilesType>()))
|
||||
.Returns((List<IFileInfo> files, Artist artist) => files);
|
||||
}
|
||||
|
||||
private void GivenRootFolder(params string[] subfolders)
|
||||
{
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.FolderExists(_rootFolder))
|
||||
.Returns(true);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.GetDirectories(_rootFolder))
|
||||
.Returns(subfolders);
|
||||
FileSystem.AddDirectory(_rootFolder);
|
||||
|
||||
foreach (var folder in subfolders)
|
||||
{
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.FolderExists(folder))
|
||||
.Returns(true);
|
||||
FileSystem.AddDirectory(folder);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,11 +76,36 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
|
|||
GivenRootFolder(_artist.Path);
|
||||
}
|
||||
|
||||
private void GivenFiles(IEnumerable<string> files)
|
||||
private List<IFileInfo> GivenFiles(IEnumerable<string> files, DateTimeOffset? lastWrite = null)
|
||||
{
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.GetFiles(It.IsAny<string>(), SearchOption.AllDirectories))
|
||||
.Returns(files.ToArray());
|
||||
if (lastWrite == null)
|
||||
{
|
||||
TestLogger.Debug("Using default lastWrite");
|
||||
lastWrite = new DateTime(2019, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
}
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
FileSystem.AddFile(file, new MockFileData(string.Empty) { LastWriteTime = lastWrite.Value });
|
||||
}
|
||||
|
||||
return files.Select(x => DiskProvider.GetFileInfo(x)).ToList();
|
||||
}
|
||||
|
||||
private void GivenKnownFiles(IEnumerable<string> files, DateTimeOffset? lastWrite = null)
|
||||
{
|
||||
if (lastWrite == null)
|
||||
{
|
||||
TestLogger.Debug("Using default lastWrite");
|
||||
lastWrite = new DateTime(2019, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
}
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Setup(x => x.GetFilesWithBasePath(_artist.Path))
|
||||
.Returns(files.Select(x => new TrackFile {
|
||||
Path = x,
|
||||
Modified = lastWrite.Value.UtcDateTime
|
||||
}).ToList());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -115,7 +138,7 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
|
|||
.Verify(v => v.Clean(It.IsAny<Artist>(), It.IsAny<List<string>>()), Times.Never());
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Verify(v => v.GetImportDecisions(It.IsAny<List<string>>(), _artist, false), Times.Never());
|
||||
.Verify(v => v.GetImportDecisions(It.IsAny<List<IFileInfo>>(), _artist, FilterFilesType.Known, true), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -129,8 +152,7 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
|
|||
|
||||
Subject.Scan(_artist);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Verify(v => v.CreateFolder(_artist.Path), Times.Once());
|
||||
DiskProvider.FolderExists(_artist.Path).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -144,8 +166,7 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
|
|||
|
||||
Subject.Scan(_artist);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Verify(v => v.CreateFolder(_artist.Path), Times.Never());
|
||||
DiskProvider.FolderExists(_artist.Path).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -155,14 +176,13 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
|
|||
|
||||
Subject.Scan(_artist);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Verify(v => v.FolderExists(_artist.Path), Times.Once());
|
||||
DiskProvider.FolderExists(_artist.Path).Should().BeFalse();
|
||||
|
||||
Mocker.GetMock<IMediaFileTableCleanupService>()
|
||||
.Verify(v => v.Clean(It.IsAny<Artist>(), It.IsAny<List<string>>()), Times.Once());
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Verify(v => v.GetImportDecisions(It.IsAny<List<string>>(), _artist, false), Times.Never());
|
||||
.Verify(v => v.GetImportDecisions(It.IsAny<List<IFileInfo>>(), _artist, FilterFilesType.Known, true), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -180,7 +200,7 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
|
|||
.Verify(v => v.Clean(It.IsAny<Artist>(), It.IsAny<List<string>>()), Times.Once());
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Verify(v => v.GetImportDecisions(It.IsAny<List<string>>(), _artist, false), Times.Never());
|
||||
.Verify(v => v.GetImportDecisions(It.IsAny<List<IFileInfo>>(), _artist, FilterFilesType.Known, true), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -190,14 +210,14 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
|
|||
|
||||
GivenFiles(new List<string>
|
||||
{
|
||||
Path.Combine(_artist.Path, "file1.flac").AsOsAgnostic(),
|
||||
Path.Combine(_artist.Path, "s01e01.flac").AsOsAgnostic()
|
||||
Path.Combine(_artist.Path, "file1.flac"),
|
||||
Path.Combine(_artist.Path, "s01e01.flac")
|
||||
});
|
||||
|
||||
Subject.Scan(_artist);
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<string>>(l => l.Count == 2), _artist, false), Times.Once());
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<IFileInfo>>(l => l.Count == 2), _artist, FilterFilesType.Known, true), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -207,20 +227,17 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
|
|||
|
||||
GivenFiles(new List<string>
|
||||
{
|
||||
Path.Combine(_artist.Path, "EXTRAS", "file1.flac").AsOsAgnostic(),
|
||||
Path.Combine(_artist.Path, "Extras", "file2.flac").AsOsAgnostic(),
|
||||
Path.Combine(_artist.Path, "EXTRAs", "file3.flac").AsOsAgnostic(),
|
||||
Path.Combine(_artist.Path, "ExTrAs", "file4.flac").AsOsAgnostic(),
|
||||
Path.Combine(_artist.Path, "Season 1", "s01e01.flac").AsOsAgnostic()
|
||||
Path.Combine(_artist.Path, "EXTRAS", "file1.flac"),
|
||||
Path.Combine(_artist.Path, "Extras", "file2.flac"),
|
||||
Path.Combine(_artist.Path, "EXTRAs", "file3.flac"),
|
||||
Path.Combine(_artist.Path, "ExTrAs", "file4.flac"),
|
||||
Path.Combine(_artist.Path, "Season 1", "s01e01.flac")
|
||||
});
|
||||
|
||||
Subject.Scan(_artist);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Verify(v => v.GetFiles(It.IsAny<string>(), It.IsAny<SearchOption>()), Times.Once());
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<string>>(l => l.Count == 1), _artist, false), Times.Once());
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<IFileInfo>>(l => l.Count == 1), _artist, FilterFilesType.Known, true), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -230,15 +247,15 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
|
|||
|
||||
GivenFiles(new List<string>
|
||||
{
|
||||
Path.Combine(_artist.Path, ".AppleDouble", "file1.flac").AsOsAgnostic(),
|
||||
Path.Combine(_artist.Path, ".appledouble", "file2.flac").AsOsAgnostic(),
|
||||
Path.Combine(_artist.Path, "Season 1", "s01e01.flac").AsOsAgnostic()
|
||||
Path.Combine(_artist.Path, ".AppleDouble", "file1.flac"),
|
||||
Path.Combine(_artist.Path, ".appledouble", "file2.flac"),
|
||||
Path.Combine(_artist.Path, "Season 1", "s01e01.flac")
|
||||
});
|
||||
|
||||
Subject.Scan(_artist);
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<string>>(l => l.Count == 1), _artist, false), Times.Once());
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<IFileInfo>>(l => l.Count == 1), _artist, FilterFilesType.Known, true), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -250,18 +267,18 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
|
|||
|
||||
GivenFiles(new List<string>
|
||||
{
|
||||
Path.Combine(_artist.Path, "Extras", "file1.flac").AsOsAgnostic(),
|
||||
Path.Combine(_artist.Path, ".AppleDouble", "file2.flac").AsOsAgnostic(),
|
||||
Path.Combine(_artist.Path, "Season 1", "s01e01.flac").AsOsAgnostic(),
|
||||
Path.Combine(_artist.Path, "Season 1", "s01e02.flac").AsOsAgnostic(),
|
||||
Path.Combine(_artist.Path, "Season 2", "s02e01.flac").AsOsAgnostic(),
|
||||
Path.Combine(_artist.Path, "Season 2", "s02e02.flac").AsOsAgnostic(),
|
||||
Path.Combine(_artist.Path, "Extras", "file1.flac"),
|
||||
Path.Combine(_artist.Path, ".AppleDouble", "file2.flac"),
|
||||
Path.Combine(_artist.Path, "Season 1", "s01e01.flac"),
|
||||
Path.Combine(_artist.Path, "Season 1", "s01e02.flac"),
|
||||
Path.Combine(_artist.Path, "Season 2", "s02e01.flac"),
|
||||
Path.Combine(_artist.Path, "Season 2", "s02e02.flac"),
|
||||
});
|
||||
|
||||
Subject.Scan(_artist);
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<string>>(l => l.Count == 4), _artist, false), Times.Once());
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<IFileInfo>>(l => l.Count == 4), _artist, FilterFilesType.Known, true), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -271,13 +288,13 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
|
|||
|
||||
GivenFiles(new List<string>
|
||||
{
|
||||
Path.Combine(_artist.Path, "Album 1", ".t01.mp3").AsOsAgnostic()
|
||||
Path.Combine(_artist.Path, "Album 1", ".t01.mp3")
|
||||
});
|
||||
|
||||
Subject.Scan(_artist);
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<string>>(l => l.Count == 1), _artist, false), Times.Once());
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<IFileInfo>>(l => l.Count == 1), _artist, FilterFilesType.Known, true), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -287,16 +304,16 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
|
|||
|
||||
GivenFiles(new List<string>
|
||||
{
|
||||
Path.Combine(_artist.Path, ".@__thumb", "file1.flac").AsOsAgnostic(),
|
||||
Path.Combine(_artist.Path, ".@__THUMB", "file2.flac").AsOsAgnostic(),
|
||||
Path.Combine(_artist.Path, ".hidden", "file2.flac").AsOsAgnostic(),
|
||||
Path.Combine(_artist.Path, "Season 1", "s01e01.flac").AsOsAgnostic()
|
||||
Path.Combine(_artist.Path, ".@__thumb", "file1.flac"),
|
||||
Path.Combine(_artist.Path, ".@__THUMB", "file2.flac"),
|
||||
Path.Combine(_artist.Path, ".hidden", "file2.flac"),
|
||||
Path.Combine(_artist.Path, "Season 1", "s01e01.flac")
|
||||
});
|
||||
|
||||
Subject.Scan(_artist);
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<string>>(l => l.Count == 1), _artist, false), Times.Once());
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<IFileInfo>>(l => l.Count == 1), _artist, FilterFilesType.Known, true), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -306,17 +323,17 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
|
|||
|
||||
GivenFiles(new List<string>
|
||||
{
|
||||
Path.Combine(_artist.Path, "Season 1", ".@__thumb", "file1.flac").AsOsAgnostic(),
|
||||
Path.Combine(_artist.Path, "Season 1", ".@__THUMB", "file2.flac").AsOsAgnostic(),
|
||||
Path.Combine(_artist.Path, "Season 1", ".hidden", "file2.flac").AsOsAgnostic(),
|
||||
Path.Combine(_artist.Path, "Season 1", ".AppleDouble", "s01e01.flac").AsOsAgnostic(),
|
||||
Path.Combine(_artist.Path, "Season 1", "s01e01.flac").AsOsAgnostic()
|
||||
Path.Combine(_artist.Path, "Season 1", ".@__thumb", "file1.flac"),
|
||||
Path.Combine(_artist.Path, "Season 1", ".@__THUMB", "file2.flac"),
|
||||
Path.Combine(_artist.Path, "Season 1", ".hidden", "file2.flac"),
|
||||
Path.Combine(_artist.Path, "Season 1", ".AppleDouble", "s01e01.flac"),
|
||||
Path.Combine(_artist.Path, "Season 1", "s01e01.flac")
|
||||
});
|
||||
|
||||
Subject.Scan(_artist);
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<string>>(l => l.Count == 1), _artist, false), Times.Once());
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<IFileInfo>>(l => l.Count == 1), _artist, FilterFilesType.Known, true), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -326,14 +343,14 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
|
|||
|
||||
GivenFiles(new List<string>
|
||||
{
|
||||
Path.Combine(_artist.Path, "@eaDir", "file1.flac").AsOsAgnostic(),
|
||||
Path.Combine(_artist.Path, "Season 1", "s01e01.flac").AsOsAgnostic()
|
||||
Path.Combine(_artist.Path, "@eaDir", "file1.flac"),
|
||||
Path.Combine(_artist.Path, "Season 1", "s01e01.flac")
|
||||
});
|
||||
|
||||
Subject.Scan(_artist);
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<string>>(l => l.Count == 1), _artist, false), Times.Once());
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<IFileInfo>>(l => l.Count == 1), _artist, FilterFilesType.Known, true), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -343,14 +360,14 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
|
|||
|
||||
GivenFiles(new List<string>
|
||||
{
|
||||
Path.Combine(_artist.Path, ".@__thumb", "file1.flac").AsOsAgnostic(),
|
||||
Path.Combine(_artist.Path, "Season 1", "s01e01.flac").AsOsAgnostic()
|
||||
Path.Combine(_artist.Path, ".@__thumb", "file1.flac"),
|
||||
Path.Combine(_artist.Path, "Season 1", "s01e01.flac")
|
||||
});
|
||||
|
||||
Subject.Scan(_artist);
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<string>>(l => l.Count == 1), _artist, false), Times.Once());
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<IFileInfo>>(l => l.Count == 1), _artist, FilterFilesType.Known, true), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -362,14 +379,14 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
|
|||
|
||||
GivenFiles(new List<string>
|
||||
{
|
||||
Path.Combine(_artist.Path, "Season 1", "file1.flac").AsOsAgnostic(),
|
||||
Path.Combine(_artist.Path, "Season 1", "s01e01.flac").AsOsAgnostic()
|
||||
Path.Combine(_artist.Path, "Season 1", "file1.flac"),
|
||||
Path.Combine(_artist.Path, "Season 1", "s01e01.flac")
|
||||
});
|
||||
|
||||
Subject.Scan(_artist);
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<string>>(l => l.Count == 2), _artist, false), Times.Once());
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<IFileInfo>>(l => l.Count == 2), _artist, FilterFilesType.Known, true), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -379,15 +396,173 @@ namespace NzbDrone.Core.Test.MediaFiles.DiskScanServiceTests
|
|||
|
||||
GivenFiles(new List<string>
|
||||
{
|
||||
Path.Combine(_artist.Path, ".DS_STORE").AsOsAgnostic(),
|
||||
Path.Combine(_artist.Path, "._24 The Status Quo Combustion.flac").AsOsAgnostic(),
|
||||
Path.Combine(_artist.Path, "24 The Status Quo Combustion.flac").AsOsAgnostic()
|
||||
Path.Combine(_artist.Path, ".DS_STORE"),
|
||||
Path.Combine(_artist.Path, "._24 The Status Quo Combustion.flac"),
|
||||
Path.Combine(_artist.Path, "24 The Status Quo Combustion.flac")
|
||||
});
|
||||
|
||||
Subject.Scan(_artist);
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<string>>(l => l.Count == 1), _artist, false), Times.Once());
|
||||
.Verify(v => v.GetImportDecisions(It.Is<List<IFileInfo>>(l => l.Count == 1), _artist, FilterFilesType.Known, true), Times.Once());
|
||||
}
|
||||
|
||||
private void GivenRejections()
|
||||
{
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Setup(x => x.GetImportDecisions(It.IsAny<List<IFileInfo>>(), It.IsAny<Artist>(), It.IsAny<FilterFilesType>(), It.IsAny<bool>()))
|
||||
.Returns((List<IFileInfo> fileList, Artist artist, FilterFilesType filter, bool includeExisting) =>
|
||||
fileList.Select(x => new LocalTrack {
|
||||
Artist = artist,
|
||||
Path = x.FullName,
|
||||
Modified = x.LastWriteTimeUtc,
|
||||
FileTrackInfo = new ParsedTrackInfo()
|
||||
})
|
||||
.Select(x => new ImportDecision<LocalTrack>(x, new Rejection("Reject")))
|
||||
.ToList());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_insert_new_unmatched_files_when_all_new()
|
||||
{
|
||||
var files = new List<string> {
|
||||
Path.Combine(_artist.Path, "Season 1", "file1.flac"),
|
||||
Path.Combine(_artist.Path, "Season 1", "s01e01.flac")
|
||||
};
|
||||
|
||||
GivenFiles(files);
|
||||
GivenKnownFiles(new List<string>());
|
||||
GivenRejections();
|
||||
|
||||
Subject.Scan(_artist);
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Verify(x => x.AddMany(It.Is<List<TrackFile>>(l => l.Select(t => t.Path).SequenceEqual(files))),
|
||||
Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_insert_new_unmatched_files_when_some_known()
|
||||
{
|
||||
var files = new List<string> {
|
||||
Path.Combine(_artist.Path, "Season 1", "file1.flac"),
|
||||
Path.Combine(_artist.Path, "Season 1", "s01e01.flac")
|
||||
};
|
||||
|
||||
GivenFiles(files);
|
||||
GivenKnownFiles(files.GetRange(1, 1));
|
||||
GivenRejections();
|
||||
|
||||
Subject.Scan(_artist);
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Verify(x => x.AddMany(It.Is<List<TrackFile>>(l => l.Select(t => t.Path).SequenceEqual(files.GetRange(0, 1)))),
|
||||
Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_insert_files_when_all_known()
|
||||
{
|
||||
var files = new List<string> {
|
||||
Path.Combine(_artist.Path, "Season 1", "file1.flac"),
|
||||
Path.Combine(_artist.Path, "Season 1", "s01e01.flac")
|
||||
};
|
||||
|
||||
GivenFiles(files);
|
||||
GivenKnownFiles(files);
|
||||
GivenRejections();
|
||||
|
||||
Subject.Scan(_artist);
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Verify(x => x.AddMany(It.Is<List<TrackFile>>(l => l.Count == 0)),
|
||||
Times.Once());
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Verify(x => x.AddMany(It.Is<List<TrackFile>>(l => l.Count > 0)),
|
||||
Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_not_update_info_for_unchanged_known_files()
|
||||
{
|
||||
var files = new List<string> {
|
||||
Path.Combine(_artist.Path, "Season 1", "file1.flac"),
|
||||
Path.Combine(_artist.Path, "Season 1", "s01e01.flac")
|
||||
};
|
||||
|
||||
GivenFiles(files);
|
||||
GivenKnownFiles(files);
|
||||
GivenRejections();
|
||||
|
||||
Subject.Scan(_artist);
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Verify(x => x.Update(It.Is<List<TrackFile>>(l => l.Count == 0)),
|
||||
Times.Once());
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Verify(x => x.Update(It.Is<List<TrackFile>>(l => l.Count > 0)),
|
||||
Times.Never());
|
||||
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_update_info_for_changed_known_files()
|
||||
{
|
||||
var files = new List<string> {
|
||||
Path.Combine(_artist.Path, "Season 1", "file1.flac"),
|
||||
Path.Combine(_artist.Path, "Season 1", "s01e01.flac")
|
||||
};
|
||||
|
||||
GivenFiles(files, new DateTime(2019, 2, 1));
|
||||
GivenKnownFiles(files);
|
||||
GivenRejections();
|
||||
|
||||
Subject.Scan(_artist);
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Verify(x => x.Update(It.Is<List<TrackFile>>(l => l.Count == 2)),
|
||||
Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_update_fields_for_updated_files()
|
||||
{
|
||||
var files = new List<string> {
|
||||
Path.Combine(_artist.Path, "Season 1", "file1.flac"),
|
||||
};
|
||||
|
||||
GivenKnownFiles(files);
|
||||
|
||||
FileSystem.AddFile(files[0], new MockFileData("".PadRight(100)) { LastWriteTime = new DateTime(2019, 2, 1) });
|
||||
|
||||
var localTrack = Builder<LocalTrack>.CreateNew()
|
||||
.With(x => x.Path = files[0])
|
||||
.With(x => x.Modified = new DateTime(2019, 2, 1))
|
||||
.With(x => x.Size = 100)
|
||||
.With(x => x.Quality = new QualityModel(Quality.FLAC))
|
||||
.With(x => x.FileTrackInfo = new ParsedTrackInfo {
|
||||
MediaInfo = Builder<MediaInfoModel>.CreateNew().Build()
|
||||
})
|
||||
.Build();
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Setup(x => x.GetImportDecisions(It.IsAny<List<IFileInfo>>(), It.IsAny<Artist>(), It.IsAny<FilterFilesType>(), It.IsAny<bool>()))
|
||||
.Returns(new List<ImportDecision<LocalTrack>> { new ImportDecision<LocalTrack>(localTrack, new Rejection("Reject")) });
|
||||
|
||||
Subject.Scan(_artist);
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Verify(x => x.Update(It.Is<List<TrackFile>>(
|
||||
l => l.Count == 1 &&
|
||||
l[0].Path == localTrack.Path &&
|
||||
l[0].Modified == localTrack.Modified &&
|
||||
l[0].Size == localTrack.Size &&
|
||||
l[0].Quality.Equals(localTrack.Quality) &&
|
||||
l[0].MediaInfo.AudioFormat == localTrack.FileTrackInfo.MediaInfo.AudioFormat
|
||||
)),
|
||||
Times.Once());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using FizzWare.NBuilder;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Download.TrackedDownloads;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
|
@ -14,11 +13,12 @@ using NzbDrone.Core.Parser.Model;
|
|||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Music;
|
||||
using NzbDrone.Test.Common;
|
||||
using System.IO.Abstractions.TestingHelpers;
|
||||
|
||||
namespace NzbDrone.Core.Test.MediaFiles
|
||||
{
|
||||
[TestFixture]
|
||||
public class DownloadedAlbumsCommandServiceFixture : CoreTest<DownloadedAlbumsCommandService>
|
||||
public class DownloadedAlbumsCommandServiceFixture : FileSystemTest<DownloadedAlbumsCommandService>
|
||||
{
|
||||
private string _downloadFolder = "c:\\drop_other\\Show.S01E01\\".AsOsAgnostic();
|
||||
private string _downloadFile = "c:\\drop_other\\Show.S01E01.mkv".AsOsAgnostic();
|
||||
|
@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
{
|
||||
|
||||
Mocker.GetMock<IDownloadedTracksImportService>()
|
||||
.Setup(v => v.ProcessRootFolder(It.IsAny<DirectoryInfo>()))
|
||||
.Setup(v => v.ProcessRootFolder(It.IsAny<IDirectoryInfo>()))
|
||||
.Returns(new List<ImportResult>());
|
||||
|
||||
Mocker.GetMock<IDownloadedTracksImportService>()
|
||||
|
@ -56,14 +56,12 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
|
||||
private void GivenExistingFolder(string path)
|
||||
{
|
||||
Mocker.GetMock<IDiskProvider>().Setup(c => c.FolderExists(It.IsAny<string>()))
|
||||
.Returns(true);
|
||||
FileSystem.AddDirectory(path);
|
||||
}
|
||||
|
||||
private void GivenExistingFile(string path)
|
||||
{
|
||||
Mocker.GetMock<IDiskProvider>().Setup(c => c.FileExists(It.IsAny<string>()))
|
||||
.Returns(true);
|
||||
FileSystem.AddFile(path, new MockFileData(string.Empty));
|
||||
}
|
||||
|
||||
private void GivenValidQueueItem()
|
||||
|
@ -78,7 +76,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
{
|
||||
Assert.Throws<ArgumentException>(() => Subject.Execute(new DownloadedAlbumsScanCommand()));
|
||||
|
||||
Mocker.GetMock<IDownloadedTracksImportService>().Verify(c => c.ProcessRootFolder(It.IsAny<DirectoryInfo>()), Times.Never());
|
||||
Mocker.GetMock<IDownloadedTracksImportService>().Verify(c => c.ProcessRootFolder(It.IsAny<IDirectoryInfo>()), Times.Never());
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
|
@ -12,36 +12,33 @@ using NzbDrone.Core.MediaFiles;
|
|||
using NzbDrone.Core.MediaFiles.TrackImport;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Music;
|
||||
using NzbDrone.Test.Common;
|
||||
using System.IO.Abstractions.TestingHelpers;
|
||||
using System.IO;
|
||||
|
||||
namespace NzbDrone.Core.Test.MediaFiles
|
||||
{
|
||||
[TestFixture]
|
||||
public class DownloadedTracksImportServiceFixture : CoreTest<DownloadedTracksImportService>
|
||||
public class DownloadedTracksImportServiceFixture : FileSystemTest<DownloadedTracksImportService>
|
||||
{
|
||||
private string _droneFactory = "c:\\drop\\".AsOsAgnostic();
|
||||
private string[] _subFolders = new[] { "c:\\root\\foldername".AsOsAgnostic() };
|
||||
private string[] _audioFiles = new[] { "c:\\root\\foldername\\01 the first track.ext".AsOsAgnostic() };
|
||||
private string[] _subFolders = new[] { "c:\\drop\\foldername".AsOsAgnostic() };
|
||||
private string[] _audioFiles = new[] { "c:\\drop\\foldername\\01 the first track.ext".AsOsAgnostic() };
|
||||
|
||||
private TrackedDownload _trackedDownload;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
GivenAudioFiles(_audioFiles, 10);
|
||||
|
||||
Mocker.GetMock<IDiskScanService>().Setup(c => c.GetAudioFiles(It.IsAny<string>(), It.IsAny<bool>()))
|
||||
.Returns(_audioFiles);
|
||||
.Returns(_audioFiles.Select(x => DiskProvider.GetFileInfo(x)).ToArray());
|
||||
|
||||
Mocker.GetMock<IDiskScanService>().Setup(c => c.FilterFiles(It.IsAny<string>(), It.IsAny<IEnumerable<string>>()))
|
||||
.Returns<string, IEnumerable<string>>((b, s) => s.ToList());
|
||||
|
||||
Mocker.GetMock<IDiskProvider>().Setup(c => c.GetDirectories(It.IsAny<string>()))
|
||||
.Returns(_subFolders);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>().Setup(c => c.FolderExists(It.IsAny<string>()))
|
||||
.Returns(true);
|
||||
Mocker.GetMock<IDiskScanService>().Setup(c => c.FilterFiles(It.IsAny<string>(), It.IsAny<IEnumerable<IFileInfo>>()))
|
||||
.Returns<string, IEnumerable<IFileInfo>>((b, s) => s.ToList());
|
||||
|
||||
Mocker.GetMock<IImportApprovedTracks>()
|
||||
.Setup(s => s.Import(It.IsAny<List<ImportDecision<LocalTrack>>>(), true, null, ImportMode.Auto))
|
||||
|
@ -65,6 +62,14 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
};
|
||||
}
|
||||
|
||||
private void GivenAudioFiles(string[] files, long filesize)
|
||||
{
|
||||
foreach (var file in files)
|
||||
{
|
||||
FileSystem.AddFile(file, new MockFileData("".PadRight((int)filesize)));
|
||||
}
|
||||
}
|
||||
|
||||
private void GivenValidArtist()
|
||||
{
|
||||
Mocker.GetMock<IParsingService>()
|
||||
|
@ -80,7 +85,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
imported.Add(new ImportDecision<LocalTrack>(localTrack));
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Artist>(), null))
|
||||
.Setup(s => s.GetImportDecisions(It.IsAny<List<IFileInfo>>(), It.IsAny<Artist>(), null))
|
||||
.Returns(imported);
|
||||
|
||||
Mocker.GetMock<IImportApprovedTracks>()
|
||||
|
@ -92,13 +97,13 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
private void WasImportedResponse()
|
||||
{
|
||||
Mocker.GetMock<IDiskScanService>().Setup(c => c.GetAudioFiles(It.IsAny<string>(), It.IsAny<bool>()))
|
||||
.Returns(new string[0]);
|
||||
.Returns(new IFileInfo[0]);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_search_for_artist_using_folder_name()
|
||||
{
|
||||
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
|
||||
Subject.ProcessRootFolder(DiskProvider.GetDirectoryInfo(_droneFactory));
|
||||
|
||||
Mocker.GetMock<IParsingService>().Verify(c => c.GetArtist("foldername"), Times.Once());
|
||||
}
|
||||
|
@ -108,10 +113,12 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
{
|
||||
GivenValidArtist();
|
||||
|
||||
Mocker.GetMock<IDiskProvider>().Setup(c => c.IsFileLocked(It.IsAny<string>()))
|
||||
.Returns(true);
|
||||
foreach (var file in _audioFiles)
|
||||
{
|
||||
FileSystem.AddFile(file, new MockFileData("".PadRight(10)) { AllowedFileShare = FileShare.None });
|
||||
}
|
||||
|
||||
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
|
||||
Subject.ProcessRootFolder(DiskProvider.GetDirectoryInfo(_droneFactory));
|
||||
|
||||
VerifyNoImport();
|
||||
}
|
||||
|
@ -121,10 +128,10 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
{
|
||||
Mocker.GetMock<IParsingService>().Setup(c => c.GetArtist("foldername")).Returns((Artist)null);
|
||||
|
||||
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
|
||||
Subject.ProcessRootFolder(DiskProvider.GetDirectoryInfo(_droneFactory));
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Verify(c => c.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Artist>(), It.IsAny<ParsedTrackInfo>()),
|
||||
.Verify(c => c.GetImportDecisions(It.IsAny<List<IFileInfo>>(), It.IsAny<Artist>(), It.IsAny<ParsedTrackInfo>()),
|
||||
Times.Never());
|
||||
|
||||
VerifyNoImport();
|
||||
|
@ -141,9 +148,9 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
|
||||
Mocker.GetMock<IDiskScanService>()
|
||||
.Setup(c => c.GetAudioFiles(It.IsAny<string>(), It.IsAny<bool>()))
|
||||
.Returns(new string[0]);
|
||||
.Returns(new IFileInfo[0]);
|
||||
|
||||
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
|
||||
Subject.ProcessRootFolder(DiskProvider.GetDirectoryInfo(_droneFactory));
|
||||
|
||||
Mocker.GetMock<IDiskScanService>()
|
||||
.Verify(v => v.GetAudioFiles(It.IsAny<string>(), true), Times.Never());
|
||||
|
@ -158,7 +165,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
.Setup(s => s.Import(It.IsAny<List<ImportDecision<LocalTrack>>>(), false, null, ImportMode.Auto))
|
||||
.Returns(new List<ImportResult>());
|
||||
|
||||
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
|
||||
Subject.ProcessRootFolder(DiskProvider.GetDirectoryInfo(_droneFactory));
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Verify(v => v.GetFolderSize(It.IsAny<string>()), Times.Never());
|
||||
|
@ -175,14 +182,14 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
imported.Add(new ImportDecision<LocalTrack>(localTrack));
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Artist>(), null))
|
||||
.Setup(s => s.GetImportDecisions(It.IsAny<List<IFileInfo>>(), It.IsAny<Artist>(), null))
|
||||
.Returns(imported);
|
||||
|
||||
Mocker.GetMock<IImportApprovedTracks>()
|
||||
.Setup(s => s.Import(It.IsAny<List<ImportDecision<LocalTrack>>>(), true, null, ImportMode.Auto))
|
||||
.Returns(imported.Select(i => new ImportResult(i)).ToList());
|
||||
|
||||
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
|
||||
Subject.ProcessRootFolder(DiskProvider.GetDirectoryInfo(_droneFactory));
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Verify(v => v.DeleteFolder(It.IsAny<string>(), true), Times.Never());
|
||||
|
@ -195,13 +202,9 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
public void should_remove_unpack_from_folder_name(string prefix)
|
||||
{
|
||||
var folderName = "Alien Ant Farm - Truant (2003)";
|
||||
var folders = new[] { string.Format(@"C:\Test\Unsorted\{0}{1}", prefix, folderName).AsOsAgnostic() };
|
||||
FileSystem.AddDirectory(string.Format(@"C:\drop\{0}{1}", prefix, folderName).AsOsAgnostic());
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(c => c.GetDirectories(It.IsAny<string>()))
|
||||
.Returns(folders);
|
||||
|
||||
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
|
||||
Subject.ProcessRootFolder(DiskProvider.GetDirectoryInfo(_droneFactory));
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
.Verify(v => v.GetArtist(folderName), Times.Once());
|
||||
|
@ -213,13 +216,8 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
[Test]
|
||||
public void should_return_importresult_on_unknown_artist()
|
||||
{
|
||||
Mocker.GetMock<IDiskProvider>().Setup(c => c.FolderExists(It.IsAny<string>()))
|
||||
.Returns(false);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>().Setup(c => c.FileExists(It.IsAny<string>()))
|
||||
.Returns(true);
|
||||
|
||||
var fileName = @"C:\folder\file.mkv".AsOsAgnostic();
|
||||
FileSystem.AddFile(fileName, new MockFileData(string.Empty));
|
||||
|
||||
var result = Subject.ProcessPath(fileName);
|
||||
|
||||
|
@ -241,33 +239,18 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
imported.Add(new ImportDecision<LocalTrack>(localTrack));
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Artist>(), null))
|
||||
.Setup(s => s.GetImportDecisions(It.IsAny<List<IFileInfo>>(), It.IsAny<Artist>(), null))
|
||||
.Returns(imported);
|
||||
|
||||
Mocker.GetMock<IImportApprovedTracks>()
|
||||
.Setup(s => s.Import(It.IsAny<List<ImportDecision<LocalTrack>>>(), true, null, ImportMode.Auto))
|
||||
.Returns(imported.Select(i => new ImportResult(i)).ToList());
|
||||
|
||||
//Mocker.GetMock<IDetectSample>()
|
||||
// .Setup(s => s.IsSample(It.IsAny<Artist>(),
|
||||
// It.IsAny<QualityModel>(),
|
||||
// It.IsAny<string>(),
|
||||
// It.IsAny<long>(),
|
||||
// It.IsAny<bool>()))
|
||||
// .Returns(true);
|
||||
GivenAudioFiles(new []{ _audioFiles.First().Replace(".ext", ".rar") }, 15.Megabytes());
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.GetFiles(It.IsAny<string>(), SearchOption.AllDirectories))
|
||||
.Returns(new []{ _audioFiles.First().Replace(".ext", ".rar") });
|
||||
Subject.ProcessRootFolder(DiskProvider.GetDirectoryInfo(_droneFactory));
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.GetFileSize(It.IsAny<string>()))
|
||||
.Returns(15.Megabytes());
|
||||
|
||||
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Verify(v => v.DeleteFolder(It.IsAny<string>(), true), Times.Never());
|
||||
DiskProvider.FolderExists(_subFolders[0]).Should().BeTrue();
|
||||
|
||||
ExceptionVerification.ExpectedWarns(1);
|
||||
}
|
||||
|
@ -277,12 +260,6 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
{
|
||||
var folderName = @"C:\media\ba09030e-1234-1234-1234-123456789abc\[HorribleSubs] Maria the Virgin Witch - 09 [720p]".AsOsAgnostic();
|
||||
|
||||
Mocker.GetMock<IDiskProvider>().Setup(c => c.FolderExists(folderName))
|
||||
.Returns(false);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>().Setup(c => c.FileExists(folderName))
|
||||
.Returns(false);
|
||||
|
||||
Subject.ProcessPath(folderName).Should().BeEmpty();
|
||||
|
||||
Mocker.GetMock<IParsingService>()
|
||||
|
@ -302,26 +279,16 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
imported.Add(new ImportDecision<LocalTrack>(localTrack));
|
||||
|
||||
Mocker.GetMock<IMakeImportDecision>()
|
||||
.Setup(s => s.GetImportDecisions(It.IsAny<List<string>>(), It.IsAny<Artist>(), null))
|
||||
.Setup(s => s.GetImportDecisions(It.IsAny<List<IFileInfo>>(), It.IsAny<Artist>(), null))
|
||||
.Returns(imported);
|
||||
|
||||
Mocker.GetMock<IImportApprovedTracks>()
|
||||
.Setup(s => s.Import(It.IsAny<List<ImportDecision<LocalTrack>>>(), true, null, ImportMode.Auto))
|
||||
.Returns(new List<ImportResult>());
|
||||
|
||||
//Mocker.GetMock<IDetectSample>()
|
||||
// .Setup(s => s.IsSample(It.IsAny<Artist>(),
|
||||
// It.IsAny<QualityModel>(),
|
||||
// It.IsAny<string>(),
|
||||
// It.IsAny<long>(),
|
||||
// It.IsAny<bool>()))
|
||||
// .Returns(true);
|
||||
Subject.ProcessRootFolder(DiskProvider.GetDirectoryInfo(_droneFactory));
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.GetFileSize(It.IsAny<string>()))
|
||||
.Returns(15.Megabytes());
|
||||
|
||||
Subject.ProcessRootFolder(new DirectoryInfo(_droneFactory));
|
||||
DiskProvider.FolderExists(_subFolders[0]).Should().BeTrue();
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Verify(v => v.DeleteFolder(It.IsAny<string>(), true), Times.Never());
|
||||
|
@ -338,8 +305,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
|
||||
Subject.ProcessPath(_droneFactory, ImportMode.Auto, _trackedDownload.RemoteAlbum.Artist, _trackedDownload.DownloadItem);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Verify(v => v.DeleteFolder(It.IsAny<string>(), true), Times.Never());
|
||||
DiskProvider.FolderExists(_subFolders[0]).Should().BeTrue();
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -353,8 +319,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
|
||||
Subject.ProcessPath(_droneFactory, ImportMode.Move, _trackedDownload.RemoteAlbum.Artist, _trackedDownload.DownloadItem);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Verify(v => v.DeleteFolder(It.IsAny<string>(), true), Times.Once());
|
||||
DiskProvider.FolderExists(_subFolders[0]).Should().BeFalse();
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -368,8 +333,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
|
||||
Subject.ProcessPath(_droneFactory, ImportMode.Copy, _trackedDownload.RemoteAlbum.Artist, _trackedDownload.DownloadItem);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Verify(v => v.DeleteFolder(It.IsAny<string>(), true), Times.Never());
|
||||
DiskProvider.FolderExists(_subFolders[0]).Should().BeTrue();
|
||||
}
|
||||
|
||||
private void VerifyNoImport()
|
||||
|
|
|
@ -89,10 +89,6 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
|
||||
_downloadClientItem = Builder<DownloadClientItem>.CreateNew().Build();
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Setup(s => s.GetFilesWithRelativePath(It.IsAny<int>(), It.IsAny<string>()))
|
||||
.Returns(new List<TrackFile>());
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Setup(s => s.GetFilesByAlbum(It.IsAny<int>()))
|
||||
.Returns(new List<TrackFile>());
|
||||
|
@ -220,8 +216,8 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
public void should_delete_existing_trackfiles_with_the_same_path()
|
||||
{
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Setup(s => s.GetFilesWithRelativePath(It.IsAny<int>(), It.IsAny<string>()))
|
||||
.Returns(Builder<TrackFile>.CreateListOfSize(1).BuildList());
|
||||
.Setup(s => s.GetFileWithPath(It.IsAny<string>()))
|
||||
.Returns(Builder<TrackFile>.CreateNew().Build());
|
||||
|
||||
var track = _approvedDecisions.First();
|
||||
track.Item.ExistingFile = true;
|
||||
|
|
|
@ -26,8 +26,7 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaFileDeletionService
|
|||
.Build();
|
||||
|
||||
_trackFile = Builder<TrackFile>.CreateNew()
|
||||
.With(f => f.RelativePath = "Artist Name - Track01")
|
||||
.With(f => f.Path = Path.Combine(_artist.Path, "Artist Name - Track01"))
|
||||
.With(f => f.Path = "/Artist Name - Track01")
|
||||
.Build();
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
|
|
|
@ -117,28 +117,6 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
files.Should().HaveCount(4);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void get_files_by_relative_path()
|
||||
{
|
||||
VerifyData();
|
||||
var files = Subject.GetFilesWithRelativePath(artist.Id, "RelativePath2");
|
||||
VerifyEagerLoaded(files);
|
||||
|
||||
files.Should().OnlyContain(c => c.AlbumId == album.Id);
|
||||
files.Should().OnlyContain(c => c.RelativePath == "RelativePath2");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void get_files_by_relative_path_should_only_contain_monitored_releases()
|
||||
{
|
||||
VerifyData();
|
||||
|
||||
// file 5 is linked to an unmonitored release
|
||||
var files = Subject.GetFilesWithRelativePath(artist.Id, "RelativePath5");
|
||||
|
||||
files.Should().BeEmpty();
|
||||
}
|
||||
|
||||
private void VerifyData()
|
||||
{
|
||||
Db.All<Artist>().Should().HaveCount(1);
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
|
@ -8,13 +7,18 @@ using NzbDrone.Core.MediaFiles;
|
|||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Music;
|
||||
using NzbDrone.Test.Common;
|
||||
using System.IO.Abstractions.TestingHelpers;
|
||||
using System.IO.Abstractions;
|
||||
using System;
|
||||
using FizzWare.NBuilder;
|
||||
|
||||
namespace NzbDrone.Core.Test.MediaFiles.MediaFileServiceTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class FilterFixture : CoreTest<MediaFileService>
|
||||
public class FilterFixture : FileSystemTest<MediaFileService>
|
||||
{
|
||||
private Artist _artist;
|
||||
private DateTime _lastWrite = new DateTime(2019, 1, 1);
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
|
@ -26,125 +30,252 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaFileServiceTests
|
|||
};
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void filter_should_return_all_files_if_no_existing_files()
|
||||
private List<IFileInfo> GivenFiles(string[] files)
|
||||
{
|
||||
var files = new List<string>()
|
||||
foreach (var file in files)
|
||||
{
|
||||
"C:\\file1.avi".AsOsAgnostic(),
|
||||
"C:\\file2.avi".AsOsAgnostic(),
|
||||
"C:\\file3.avi".AsOsAgnostic()
|
||||
};
|
||||
|
||||
Mocker.GetMock<IMediaFileRepository>()
|
||||
.Setup(c => c.GetFilesByArtist(It.IsAny<int>()))
|
||||
.Returns(new List<TrackFile>());
|
||||
|
||||
|
||||
Subject.FilterExistingFiles(files, _artist).Should().BeEquivalentTo(files);
|
||||
FileSystem.AddFile(file, new MockFileData(string.Empty) { LastWriteTime = _lastWrite });
|
||||
}
|
||||
|
||||
return files.Select(x => DiskProvider.GetFileInfo(x)).ToList();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void filter_should_return_none_if_all_files_exist()
|
||||
[TestCase(FilterFilesType.Known)]
|
||||
[TestCase(FilterFilesType.Matched)]
|
||||
public void filter_should_return_all_files_if_no_existing_files(FilterFilesType filter)
|
||||
{
|
||||
var files = new List<string>()
|
||||
{
|
||||
"C:\\file1.avi".AsOsAgnostic(),
|
||||
"C:\\file2.avi".AsOsAgnostic(),
|
||||
"C:\\file3.avi".AsOsAgnostic()
|
||||
};
|
||||
|
||||
Mocker.GetMock<IMediaFileRepository>()
|
||||
.Setup(c => c.GetFilesByArtist(It.IsAny<int>()))
|
||||
.Returns(files.Select(f => new TrackFile { RelativePath = Path.GetFileName(f) }).ToList());
|
||||
|
||||
|
||||
Subject.FilterExistingFiles(files, _artist).Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void filter_should_return_none_existing_files()
|
||||
{
|
||||
var files = new List<string>()
|
||||
{
|
||||
"C:\\file1.avi".AsOsAgnostic(),
|
||||
"C:\\file2.avi".AsOsAgnostic(),
|
||||
"C:\\file3.avi".AsOsAgnostic()
|
||||
};
|
||||
|
||||
Mocker.GetMock<IMediaFileRepository>()
|
||||
.Setup(c => c.GetFilesByArtist(It.IsAny<int>()))
|
||||
.Returns(new List<TrackFile>
|
||||
var files = GivenFiles(new []
|
||||
{
|
||||
new TrackFile{ RelativePath = "file2.avi".AsOsAgnostic()}
|
||||
"C:\\file1.avi".AsOsAgnostic(),
|
||||
"C:\\file2.avi".AsOsAgnostic(),
|
||||
"C:\\file3.avi".AsOsAgnostic()
|
||||
});
|
||||
|
||||
Mocker.GetMock<IMediaFileRepository>()
|
||||
.Setup(c => c.GetFilesWithBasePath(It.IsAny<string>()))
|
||||
.Returns(new List<TrackFile>());
|
||||
|
||||
Subject.FilterExistingFiles(files, _artist).Should().HaveCount(2);
|
||||
Subject.FilterExistingFiles(files, _artist).Should().NotContain("C:\\file2.avi".AsOsAgnostic());
|
||||
Subject.FilterUnchangedFiles(files, _artist, filter).Should().BeEquivalentTo(files);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void filter_should_return_none_existing_files_ignoring_case()
|
||||
[TestCase(FilterFilesType.Known)]
|
||||
[TestCase(FilterFilesType.Matched)]
|
||||
public void filter_should_return_nothing_if_all_files_exist(FilterFilesType filter)
|
||||
{
|
||||
var files = GivenFiles(new []
|
||||
{
|
||||
"C:\\file1.avi".AsOsAgnostic(),
|
||||
"C:\\file2.avi".AsOsAgnostic(),
|
||||
"C:\\file3.avi".AsOsAgnostic()
|
||||
});
|
||||
|
||||
Mocker.GetMock<IMediaFileRepository>()
|
||||
.Setup(c => c.GetFilesWithBasePath(It.IsAny<string>()))
|
||||
.Returns(files.Select(f => new TrackFile {
|
||||
Path = f.FullName,
|
||||
Modified = _lastWrite
|
||||
}).ToList());
|
||||
|
||||
Subject.FilterUnchangedFiles(files, _artist, filter).Should().BeEmpty();
|
||||
}
|
||||
|
||||
[TestCase(FilterFilesType.Known)]
|
||||
[TestCase(FilterFilesType.Matched)]
|
||||
public void filter_should_not_return_existing_files(FilterFilesType filter)
|
||||
{
|
||||
var files = GivenFiles(new []
|
||||
{
|
||||
"C:\\file1.avi".AsOsAgnostic(),
|
||||
"C:\\file2.avi".AsOsAgnostic(),
|
||||
"C:\\file3.avi".AsOsAgnostic()
|
||||
});
|
||||
|
||||
Mocker.GetMock<IMediaFileRepository>()
|
||||
.Setup(c => c.GetFilesWithBasePath(It.IsAny<string>()))
|
||||
.Returns(new List<TrackFile>
|
||||
{
|
||||
new TrackFile{
|
||||
Path = "C:\\file2.avi".AsOsAgnostic(),
|
||||
Modified = _lastWrite
|
||||
}
|
||||
});
|
||||
|
||||
Subject.FilterUnchangedFiles(files, _artist, filter).Should().HaveCount(2);
|
||||
Subject.FilterUnchangedFiles(files, _artist, filter).Select(x => x.FullName).Should().NotContain("C:\\file2.avi".AsOsAgnostic());
|
||||
}
|
||||
|
||||
[TestCase(FilterFilesType.Known)]
|
||||
[TestCase(FilterFilesType.Matched)]
|
||||
public void filter_should_return_none_existing_files_ignoring_case(FilterFilesType filter)
|
||||
{
|
||||
WindowsOnly();
|
||||
|
||||
var files = new List<string>()
|
||||
{
|
||||
"C:\\file1.avi".AsOsAgnostic(),
|
||||
"C:\\FILE2.avi".AsOsAgnostic(),
|
||||
"C:\\file3.avi".AsOsAgnostic()
|
||||
};
|
||||
var files = GivenFiles(new []
|
||||
{
|
||||
"C:\\file1.avi".AsOsAgnostic(),
|
||||
"C:\\FILE2.avi".AsOsAgnostic(),
|
||||
"C:\\file3.avi".AsOsAgnostic()
|
||||
});
|
||||
|
||||
Mocker.GetMock<IMediaFileRepository>()
|
||||
.Setup(c => c.GetFilesByArtist(It.IsAny<int>()))
|
||||
.Setup(c => c.GetFilesWithBasePath(It.IsAny<string>()))
|
||||
.Returns(new List<TrackFile>
|
||||
{
|
||||
new TrackFile{ RelativePath = "file2.avi".AsOsAgnostic()}
|
||||
new TrackFile{
|
||||
Path = "C:\\file2.avi".AsOsAgnostic(),
|
||||
Modified = _lastWrite
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Subject.FilterExistingFiles(files, _artist).Should().HaveCount(2);
|
||||
Subject.FilterExistingFiles(files, _artist).Should().NotContain("C:\\file2.avi".AsOsAgnostic());
|
||||
Subject.FilterUnchangedFiles(files, _artist, filter).Should().HaveCount(2);
|
||||
Subject.FilterUnchangedFiles(files, _artist, filter).Select(x => x.FullName).Should().NotContain("C:\\file2.avi".AsOsAgnostic());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void filter_should_return_none_existing_files_not_ignoring_case()
|
||||
|
||||
[TestCase(FilterFilesType.Known)]
|
||||
[TestCase(FilterFilesType.Matched)]
|
||||
public void filter_should_return_none_existing_files_not_ignoring_case(FilterFilesType filter)
|
||||
{
|
||||
MonoOnly();
|
||||
|
||||
var files = new List<string>()
|
||||
{
|
||||
"C:\\file1.avi".AsOsAgnostic(),
|
||||
"C:\\FILE2.avi".AsOsAgnostic(),
|
||||
"C:\\file3.avi".AsOsAgnostic()
|
||||
};
|
||||
|
||||
Mocker.GetMock<IMediaFileRepository>()
|
||||
.Setup(c => c.GetFilesByArtist(It.IsAny<int>()))
|
||||
.Returns(new List<TrackFile>
|
||||
var files = GivenFiles(new []
|
||||
{
|
||||
new TrackFile{ RelativePath = "file2.avi".AsOsAgnostic()}
|
||||
"C:\\file1.avi".AsOsAgnostic(),
|
||||
"C:\\FILE2.avi".AsOsAgnostic(),
|
||||
"C:\\file3.avi".AsOsAgnostic()
|
||||
});
|
||||
|
||||
Subject.FilterExistingFiles(files, _artist).Should().HaveCount(3);
|
||||
Mocker.GetMock<IMediaFileRepository>()
|
||||
.Setup(c => c.GetFilesWithBasePath(It.IsAny<string>()))
|
||||
.Returns(new List<TrackFile>
|
||||
{
|
||||
new TrackFile{
|
||||
Path = "C:\\file2.avi".AsOsAgnostic(),
|
||||
Modified = _lastWrite
|
||||
}
|
||||
});
|
||||
|
||||
Subject.FilterUnchangedFiles(files, _artist, filter).Should().HaveCount(3);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void filter_should_not_change_casing()
|
||||
[TestCase(FilterFilesType.Known)]
|
||||
[TestCase(FilterFilesType.Matched)]
|
||||
public void filter_should_not_change_casing(FilterFilesType filter)
|
||||
{
|
||||
var files = new List<string>()
|
||||
{
|
||||
"C:\\FILE1.avi".AsOsAgnostic()
|
||||
};
|
||||
var files = GivenFiles(new []
|
||||
{
|
||||
"C:\\FILE1.avi".AsOsAgnostic()
|
||||
});
|
||||
|
||||
Mocker.GetMock<IMediaFileRepository>()
|
||||
.Setup(c => c.GetFilesByArtist(It.IsAny<int>()))
|
||||
.Setup(c => c.GetFilesWithBasePath(It.IsAny<string>()))
|
||||
.Returns(new List<TrackFile>());
|
||||
|
||||
Subject.FilterExistingFiles(files, _artist).Should().HaveCount(1);
|
||||
Subject.FilterExistingFiles(files, _artist).Should().NotContain(files.First().ToLower());
|
||||
Subject.FilterExistingFiles(files, _artist).Should().Contain(files.First());
|
||||
Subject.FilterUnchangedFiles(files, _artist, filter).Should().HaveCount(1);
|
||||
Subject.FilterUnchangedFiles(files, _artist, filter).Select(x => x.FullName).Should().NotContain(files.First().FullName.ToLower());
|
||||
Subject.FilterUnchangedFiles(files, _artist, filter).Should().Contain(files.First());
|
||||
}
|
||||
|
||||
|
||||
[TestCase(FilterFilesType.Known)]
|
||||
[TestCase(FilterFilesType.Matched)]
|
||||
public void filter_should_not_return_existing_file_if_size_unchanged(FilterFilesType filter)
|
||||
{
|
||||
FileSystem.AddFile("C:\\file1.avi".AsOsAgnostic(), new MockFileData("".PadRight(10)) { LastWriteTime = _lastWrite });
|
||||
FileSystem.AddFile("C:\\file2.avi".AsOsAgnostic(), new MockFileData("".PadRight(10)) { LastWriteTime = _lastWrite });
|
||||
FileSystem.AddFile("C:\\file3.avi".AsOsAgnostic(), new MockFileData("".PadRight(10)) { LastWriteTime = _lastWrite });
|
||||
|
||||
var files = FileSystem.AllFiles.Select(x => DiskProvider.GetFileInfo(x)).ToList();
|
||||
|
||||
Mocker.GetMock<IMediaFileRepository>()
|
||||
.Setup(c => c.GetFilesWithBasePath(It.IsAny<string>()))
|
||||
.Returns(new List<TrackFile>
|
||||
{
|
||||
new TrackFile{
|
||||
Path = "C:\\file2.avi".AsOsAgnostic(),
|
||||
Size = 10,
|
||||
Modified = _lastWrite
|
||||
}
|
||||
});
|
||||
|
||||
Subject.FilterUnchangedFiles(files, _artist, filter).Should().HaveCount(2);
|
||||
Subject.FilterUnchangedFiles(files, _artist, filter).Select(x => x.FullName).Should().NotContain("C:\\file2.avi".AsOsAgnostic());
|
||||
}
|
||||
|
||||
[TestCase(FilterFilesType.Matched)]
|
||||
public void filter_unmatched_should_return_existing_file_if_unmatched(FilterFilesType filter)
|
||||
{
|
||||
FileSystem.AddFile("C:\\file1.avi".AsOsAgnostic(), new MockFileData("".PadRight(10)) { LastWriteTime = _lastWrite });
|
||||
FileSystem.AddFile("C:\\file2.avi".AsOsAgnostic(), new MockFileData("".PadRight(10)) { LastWriteTime = _lastWrite });
|
||||
FileSystem.AddFile("C:\\file3.avi".AsOsAgnostic(), new MockFileData("".PadRight(10)) { LastWriteTime = _lastWrite });
|
||||
|
||||
var files = FileSystem.AllFiles.Select(x => DiskProvider.GetFileInfo(x)).ToList();
|
||||
|
||||
Mocker.GetMock<IMediaFileRepository>()
|
||||
.Setup(c => c.GetFilesWithBasePath(It.IsAny<string>()))
|
||||
.Returns(new List<TrackFile>
|
||||
{
|
||||
new TrackFile{
|
||||
Path = "C:\\file2.avi".AsOsAgnostic(),
|
||||
Size = 10,
|
||||
Modified = _lastWrite,
|
||||
Tracks = new List<Track>()
|
||||
}
|
||||
});
|
||||
|
||||
Subject.FilterUnchangedFiles(files, _artist, filter).Should().HaveCount(3);
|
||||
Subject.FilterUnchangedFiles(files, _artist, filter).Select(x => x.FullName).Should().Contain("C:\\file2.avi".AsOsAgnostic());
|
||||
}
|
||||
|
||||
[TestCase(FilterFilesType.Matched)]
|
||||
public void filter_unmatched_should_not_return_existing_file_if_matched(FilterFilesType filter)
|
||||
{
|
||||
FileSystem.AddFile("C:\\file1.avi".AsOsAgnostic(), new MockFileData("".PadRight(10)) { LastWriteTime = _lastWrite });
|
||||
FileSystem.AddFile("C:\\file2.avi".AsOsAgnostic(), new MockFileData("".PadRight(10)) { LastWriteTime = _lastWrite });
|
||||
FileSystem.AddFile("C:\\file3.avi".AsOsAgnostic(), new MockFileData("".PadRight(10)) { LastWriteTime = _lastWrite });
|
||||
|
||||
var files = FileSystem.AllFiles.Select(x => DiskProvider.GetFileInfo(x)).ToList();
|
||||
|
||||
Mocker.GetMock<IMediaFileRepository>()
|
||||
.Setup(c => c.GetFilesWithBasePath(It.IsAny<string>()))
|
||||
.Returns(new List<TrackFile>
|
||||
{
|
||||
new TrackFile{
|
||||
Path = "C:\\file2.avi".AsOsAgnostic(),
|
||||
Size = 10,
|
||||
Modified = _lastWrite,
|
||||
Tracks = Builder<Track>.CreateListOfSize(1).Build() as List<Track>
|
||||
}
|
||||
});
|
||||
|
||||
Subject.FilterUnchangedFiles(files, _artist, filter).Should().HaveCount(2);
|
||||
Subject.FilterUnchangedFiles(files, _artist, filter).Select(x => x.FullName).Should().NotContain("C:\\file2.avi".AsOsAgnostic());
|
||||
}
|
||||
|
||||
[TestCase(FilterFilesType.Known)]
|
||||
[TestCase(FilterFilesType.Matched)]
|
||||
public void filter_should_return_existing_file_if_size_changed(FilterFilesType filter)
|
||||
{
|
||||
FileSystem.AddFile("C:\\file1.avi".AsOsAgnostic(), new MockFileData("".PadRight(10)) { LastWriteTime = _lastWrite });
|
||||
FileSystem.AddFile("C:\\file2.avi".AsOsAgnostic(), new MockFileData("".PadRight(11)) { LastWriteTime = _lastWrite });
|
||||
FileSystem.AddFile("C:\\file3.avi".AsOsAgnostic(), new MockFileData("".PadRight(10)) { LastWriteTime = _lastWrite });
|
||||
|
||||
var files = FileSystem.AllFiles.Select(x => DiskProvider.GetFileInfo(x)).ToList();
|
||||
|
||||
Mocker.GetMock<IMediaFileRepository>()
|
||||
.Setup(c => c.GetFilesWithBasePath(It.IsAny<string>()))
|
||||
.Returns(new List<TrackFile>
|
||||
{
|
||||
new TrackFile{
|
||||
Path = "C:\\file2.avi".AsOsAgnostic(),
|
||||
Size = 10,
|
||||
Modified = _lastWrite
|
||||
}
|
||||
});
|
||||
|
||||
Subject.FilterUnchangedFiles(files, _artist, filter).Should().HaveCount(3);
|
||||
Subject.FilterUnchangedFiles(files, _artist, filter).Select(x => x.FullName).Should().Contain("C:\\file2.avi".AsOsAgnostic());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
{
|
||||
public class MediaFileTableCleanupServiceFixture : CoreTest<MediaFileTableCleanupService>
|
||||
{
|
||||
private const string DELETED_PATH = "ANY FILE WITH THIS PATH IS CONSIDERED DELETED!";
|
||||
private readonly string DELETED_PATH = @"c:\ANY FILE WITH THIS PATH IS CONSIDERED DELETED!".AsOsAgnostic();
|
||||
private List<Track> _tracks;
|
||||
private Artist _artist;
|
||||
|
||||
|
@ -56,13 +56,15 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
|
||||
private List<string> FilesOnDisk(IEnumerable<TrackFile> trackFiles)
|
||||
{
|
||||
return trackFiles.Select(e => Path.Combine(_artist.Path, e.RelativePath)).ToList();
|
||||
return trackFiles.Select(e => e.Path).ToList();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_skip_files_that_exist_in_disk()
|
||||
public void should_skip_files_that_exist_on_disk()
|
||||
{
|
||||
var trackFiles = Builder<TrackFile>.CreateListOfSize(10)
|
||||
.All()
|
||||
.With(x => x.Path = Path.Combine(@"c:\test".AsOsAgnostic(), Path.GetRandomFileName()))
|
||||
.Build();
|
||||
|
||||
GivenTrackFiles(trackFiles);
|
||||
|
@ -76,31 +78,17 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
public void should_delete_non_existent_files()
|
||||
{
|
||||
var trackFiles = Builder<TrackFile>.CreateListOfSize(10)
|
||||
.All()
|
||||
.With(x => x.Path = Path.Combine(@"c:\test".AsOsAgnostic(), Path.GetRandomFileName()))
|
||||
.Random(2)
|
||||
.With(c => c.RelativePath = DELETED_PATH)
|
||||
.With(c => c.Path = DELETED_PATH)
|
||||
.Build();
|
||||
|
||||
GivenTrackFiles(trackFiles);
|
||||
|
||||
Subject.Clean(_artist, FilesOnDisk(trackFiles.Where(e => e.RelativePath != DELETED_PATH)));
|
||||
Subject.Clean(_artist, FilesOnDisk(trackFiles.Where(e => e.Path != DELETED_PATH)));
|
||||
|
||||
Mocker.GetMock<IMediaFileService>().Verify(c => c.Delete(It.Is<TrackFile>(e => e.RelativePath == DELETED_PATH), DeleteMediaFileReason.MissingFromDisk), Times.Exactly(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_delete_files_that_dont_belong_to_any_tracks()
|
||||
{
|
||||
var trackFiles = Builder<TrackFile>.CreateListOfSize(10)
|
||||
.Random(10)
|
||||
.With(c => c.RelativePath = "ExistingPath")
|
||||
.Build();
|
||||
|
||||
GivenTrackFiles(trackFiles);
|
||||
GivenFilesAreNotAttachedToTrack();
|
||||
|
||||
Subject.Clean(_artist, FilesOnDisk(trackFiles));
|
||||
|
||||
Mocker.GetMock<IMediaFileService>().Verify(c => c.Delete(It.IsAny<TrackFile>(), DeleteMediaFileReason.NoLinkedEpisodes), Times.Exactly(10));
|
||||
Mocker.GetMock<IMediaFileService>().Verify(c => c.Delete(It.Is<TrackFile>(e => e.Path == DELETED_PATH), DeleteMediaFileReason.MissingFromDisk), Times.Exactly(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -118,7 +106,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
{
|
||||
var trackFiles = Builder<TrackFile>.CreateListOfSize(10)
|
||||
.Random(10)
|
||||
.With(c => c.RelativePath = "ExistingPath")
|
||||
.With(c => c.Path = "/ExistingPath".AsOsAgnostic())
|
||||
.Build();
|
||||
|
||||
GivenTrackFiles(trackFiles);
|
||||
|
|
|
@ -14,6 +14,7 @@ using NzbDrone.Core.Parser.Model;
|
|||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Music;
|
||||
using NzbDrone.Test.Common;
|
||||
using System.IO;
|
||||
|
||||
namespace NzbDrone.Core.Test.MediaFiles.TrackFileMovingServiceTests
|
||||
{
|
||||
|
@ -33,7 +34,7 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackFileMovingServiceTests
|
|||
|
||||
_trackFile = Builder<TrackFile>.CreateNew()
|
||||
.With(f => f.Path = null)
|
||||
.With(f => f.RelativePath = @"Album\File.mp3")
|
||||
.With(f => f.Path = Path.Combine(_artist.Path, @"Album\File.mp3"))
|
||||
.Build();
|
||||
|
||||
_localtrack = Builder<LocalTrack>.CreateNew()
|
||||
|
|
|
@ -3,11 +3,11 @@ using System.Linq;
|
|||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using System.IO.Abstractions;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.MediaFiles.TrackImport;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Profiles;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Music;
|
||||
|
@ -18,13 +18,14 @@ using NzbDrone.Core.MediaFiles.TrackImport.Aggregation;
|
|||
using NzbDrone.Core.Profiles.Qualities;
|
||||
using NzbDrone.Core.Profiles.Languages;
|
||||
using NzbDrone.Core.MediaFiles.TrackImport.Identification;
|
||||
using System.IO.Abstractions.TestingHelpers;
|
||||
|
||||
namespace NzbDrone.Core.Test.MediaFiles.TrackImport
|
||||
{
|
||||
[TestFixture]
|
||||
public class ImportDecisionMakerFixture : CoreTest<ImportDecisionMaker>
|
||||
public class ImportDecisionMakerFixture : FileSystemTest<ImportDecisionMaker>
|
||||
{
|
||||
private List<string> _audioFiles;
|
||||
private List<IFileInfo> _fileInfos;
|
||||
private LocalTrack _localTrack;
|
||||
private Artist _artist;
|
||||
private AlbumRelease _albumRelease;
|
||||
|
@ -112,8 +113,8 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport
|
|||
});
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Setup(c => c.FilterExistingFiles(It.IsAny<List<string>>(), It.IsAny<Artist>()))
|
||||
.Returns((List<string> files, Artist artist) => files);
|
||||
.Setup(c => c.FilterUnchangedFiles(It.IsAny<List<IFileInfo>>(), It.IsAny<Artist>(), It.IsAny<FilterFilesType>()))
|
||||
.Returns((List<IFileInfo> files, Artist artist) => files);
|
||||
|
||||
GivenSpecifications(_albumpass1);
|
||||
}
|
||||
|
@ -125,11 +126,12 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport
|
|||
|
||||
private void GivenAudioFiles(IEnumerable<string> videoFiles)
|
||||
{
|
||||
_audioFiles = videoFiles.ToList();
|
||||
foreach (var file in videoFiles)
|
||||
{
|
||||
FileSystem.AddFile(file, new MockFileData(string.Empty));
|
||||
}
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Setup(c => c.FilterExistingFiles(_audioFiles, It.IsAny<Artist>()))
|
||||
.Returns(_audioFiles);
|
||||
_fileInfos = videoFiles.Select(x => DiskProvider.GetFileInfo(x)).ToList();
|
||||
}
|
||||
|
||||
private void GivenAugmentationSuccess()
|
||||
|
@ -149,7 +151,7 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport
|
|||
GivenAugmentationSuccess();
|
||||
GivenSpecifications(_albumpass1, _albumpass2, _albumpass3, _albumfail1, _albumfail2, _albumfail3);
|
||||
|
||||
Subject.GetImportDecisions(_audioFiles, new Artist(), null, null, downloadClientItem, null, false, false, false, false);
|
||||
Subject.GetImportDecisions(_fileInfos, new Artist(), null, null, downloadClientItem, null, FilterFilesType.None, false, false, false);
|
||||
|
||||
_albumfail1.Verify(c => c.IsSatisfiedBy(It.IsAny<LocalAlbumRelease>()), Times.Once());
|
||||
_albumfail2.Verify(c => c.IsSatisfiedBy(It.IsAny<LocalAlbumRelease>()), Times.Once());
|
||||
|
@ -166,7 +168,7 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport
|
|||
GivenAugmentationSuccess();
|
||||
GivenSpecifications(_pass1, _pass2, _pass3, _fail1, _fail2, _fail3);
|
||||
|
||||
Subject.GetImportDecisions(_audioFiles, new Artist(), null, null, downloadClientItem, null, false, false, false, false);
|
||||
Subject.GetImportDecisions(_fileInfos, new Artist(), null, null, downloadClientItem, null, FilterFilesType.None, false, false, false);
|
||||
|
||||
_fail1.Verify(c => c.IsSatisfiedBy(It.IsAny<LocalTrack>()), Times.Once());
|
||||
_fail2.Verify(c => c.IsSatisfiedBy(It.IsAny<LocalTrack>()), Times.Once());
|
||||
|
@ -184,7 +186,7 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport
|
|||
GivenSpecifications(_albumpass1, _albumpass2, _albumpass3, _albumfail1, _albumfail2, _albumfail3);
|
||||
GivenSpecifications(_pass1, _pass2, _pass3, _fail1, _fail2, _fail3);
|
||||
|
||||
Subject.GetImportDecisions(_audioFiles, new Artist(), null, null, downloadClientItem, null, false, false, false, false);
|
||||
Subject.GetImportDecisions(_fileInfos, new Artist(), null, null, downloadClientItem, null, FilterFilesType.None, false, false, false);
|
||||
|
||||
_fail1.Verify(c => c.IsSatisfiedBy(It.IsAny<LocalTrack>()), Times.Never());
|
||||
_fail2.Verify(c => c.IsSatisfiedBy(It.IsAny<LocalTrack>()), Times.Never());
|
||||
|
@ -200,7 +202,7 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport
|
|||
GivenSpecifications(_albumfail1);
|
||||
GivenSpecifications(_pass1);
|
||||
|
||||
var result = Subject.GetImportDecisions(_audioFiles, new Artist(), false);
|
||||
var result = Subject.GetImportDecisions(_fileInfos, new Artist(), FilterFilesType.None, false);
|
||||
|
||||
result.Single().Approved.Should().BeFalse();
|
||||
}
|
||||
|
@ -211,7 +213,7 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport
|
|||
GivenSpecifications(_albumpass1);
|
||||
GivenSpecifications(_fail1);
|
||||
|
||||
var result = Subject.GetImportDecisions(_audioFiles, new Artist(), false);
|
||||
var result = Subject.GetImportDecisions(_fileInfos, new Artist(), FilterFilesType.None, false);
|
||||
|
||||
result.Single().Approved.Should().BeFalse();
|
||||
}
|
||||
|
@ -222,7 +224,7 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport
|
|||
GivenSpecifications(_albumpass1, _albumfail1, _albumpass2, _albumpass3);
|
||||
GivenSpecifications(_pass1, _pass2, _pass3);
|
||||
|
||||
var result = Subject.GetImportDecisions(_audioFiles, new Artist(), false);
|
||||
var result = Subject.GetImportDecisions(_fileInfos, new Artist(), FilterFilesType.None, false);
|
||||
|
||||
result.Single().Approved.Should().BeFalse();
|
||||
}
|
||||
|
@ -233,7 +235,7 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport
|
|||
GivenSpecifications(_albumpass1, _albumpass2, _albumpass3);
|
||||
GivenSpecifications(_pass1, _fail1, _pass2, _pass3);
|
||||
|
||||
var result = Subject.GetImportDecisions(_audioFiles, new Artist(), false);
|
||||
var result = Subject.GetImportDecisions(_fileInfos, new Artist(), FilterFilesType.None, false);
|
||||
|
||||
result.Single().Approved.Should().BeFalse();
|
||||
}
|
||||
|
@ -245,7 +247,7 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport
|
|||
GivenSpecifications(_albumpass1, _albumpass2, _albumpass3);
|
||||
GivenSpecifications(_pass1, _pass2, _pass3);
|
||||
|
||||
var result = Subject.GetImportDecisions(_audioFiles, new Artist(), false);
|
||||
var result = Subject.GetImportDecisions(_fileInfos, new Artist(), FilterFilesType.None, false);
|
||||
|
||||
result.Single().Approved.Should().BeTrue();
|
||||
}
|
||||
|
@ -256,7 +258,7 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport
|
|||
GivenAugmentationSuccess();
|
||||
GivenSpecifications(_pass1, _pass2, _pass3, _fail1, _fail2, _fail3);
|
||||
|
||||
var result = Subject.GetImportDecisions(_audioFiles, new Artist(), false);
|
||||
var result = Subject.GetImportDecisions(_fileInfos, new Artist(), FilterFilesType.None, false);
|
||||
result.Single().Rejections.Should().HaveCount(3);
|
||||
}
|
||||
|
||||
|
@ -276,10 +278,10 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport
|
|||
@"C:\Test\Unsorted\The.Office.S03E115.DVDRip.XviD-OSiTV".AsOsAgnostic()
|
||||
});
|
||||
|
||||
Subject.GetImportDecisions(_audioFiles, _artist, false);
|
||||
Subject.GetImportDecisions(_fileInfos, _artist, FilterFilesType.None, false);
|
||||
|
||||
Mocker.GetMock<IAugmentingService>()
|
||||
.Verify(c => c.Augment(It.IsAny<LocalTrack>(), It.IsAny<bool>()), Times.Exactly(_audioFiles.Count));
|
||||
.Verify(c => c.Augment(It.IsAny<LocalTrack>(), It.IsAny<bool>()), Times.Exactly(_fileInfos.Count));
|
||||
|
||||
ExceptionVerification.ExpectedErrors(3);
|
||||
}
|
||||
|
@ -302,10 +304,10 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport
|
|||
return new List<LocalAlbumRelease> { new LocalAlbumRelease(tracks) };
|
||||
});
|
||||
|
||||
var decisions = Subject.GetImportDecisions(_audioFiles, _artist, false);
|
||||
var decisions = Subject.GetImportDecisions(_fileInfos, _artist, FilterFilesType.None, false);
|
||||
|
||||
Mocker.GetMock<IAugmentingService>()
|
||||
.Verify(c => c.Augment(It.IsAny<LocalTrack>(), It.IsAny<bool>()), Times.Exactly(_audioFiles.Count));
|
||||
.Verify(c => c.Augment(It.IsAny<LocalTrack>(), It.IsAny<bool>()), Times.Exactly(_fileInfos.Count));
|
||||
|
||||
decisions.Should().HaveCount(3);
|
||||
decisions.First().Rejections.Should().NotBeEmpty();
|
||||
|
@ -323,10 +325,10 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport
|
|||
@"C:\Test\Unsorted\The.Office.S03E115.DVDRip.XviD-OSiTV".AsOsAgnostic()
|
||||
});
|
||||
|
||||
var decisions = Subject.GetImportDecisions(_audioFiles, _artist, false);
|
||||
var decisions = Subject.GetImportDecisions(_fileInfos, _artist, FilterFilesType.None, false);
|
||||
|
||||
Mocker.GetMock<IAugmentingService>()
|
||||
.Verify(c => c.Augment(It.IsAny<LocalTrack>(), It.IsAny<bool>()), Times.Exactly(_audioFiles.Count));
|
||||
.Verify(c => c.Augment(It.IsAny<LocalTrack>(), It.IsAny<bool>()), Times.Exactly(_fileInfos.Count));
|
||||
|
||||
decisions.Should().HaveCount(3);
|
||||
decisions.First().Rejections.Should().NotBeEmpty();
|
||||
|
@ -344,7 +346,7 @@ namespace NzbDrone.Core.Test.MediaFiles.TrackImport
|
|||
@"C:\Test\Unsorted\The.Office.S03E115.DVDRip.XviD-OSiTV".AsOsAgnostic()
|
||||
});
|
||||
|
||||
Subject.GetImportDecisions(_audioFiles, _artist, false).Should().HaveCount(1);
|
||||
Subject.GetImportDecisions(_fileInfos, _artist, FilterFilesType.None, false).Should().HaveCount(1);
|
||||
|
||||
ExceptionVerification.ExpectedErrors(1);
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
{
|
||||
private TrackFile _trackFile;
|
||||
private LocalTrack _localTrack;
|
||||
private string rootPath = @"C:\Test\Music\Artist".AsOsAgnostic();
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
|
@ -25,7 +26,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
_localTrack = new LocalTrack();
|
||||
_localTrack.Artist = new Artist
|
||||
{
|
||||
Path = @"C:\Test\Music\Artist".AsOsAgnostic()
|
||||
Path = rootPath
|
||||
};
|
||||
|
||||
_trackFile = Builder<TrackFile>
|
||||
|
@ -55,7 +56,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
new TrackFile
|
||||
{
|
||||
Id = 1,
|
||||
RelativePath = @"Season 01\30.rock.s01e01.avi",
|
||||
Path = Path.Combine(rootPath, @"Season 01\30.rock.s01e01.avi"),
|
||||
}))
|
||||
.Build()
|
||||
.ToList();
|
||||
|
@ -70,7 +71,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
new TrackFile
|
||||
{
|
||||
Id = 1,
|
||||
RelativePath = @"Season 01\30.rock.s01e01.avi",
|
||||
Path = Path.Combine(rootPath, @"Season 01\30.rock.s01e01.avi"),
|
||||
}))
|
||||
.Build()
|
||||
.ToList();
|
||||
|
@ -84,14 +85,14 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
new TrackFile
|
||||
{
|
||||
Id = 1,
|
||||
RelativePath = @"Season 01\30.rock.s01e01.avi",
|
||||
Path = Path.Combine(rootPath, @"Season 01\30.rock.s01e01.avi"),
|
||||
}))
|
||||
.TheNext(1)
|
||||
.With(e => e.TrackFile = new LazyLoaded<TrackFile>(
|
||||
new TrackFile
|
||||
{
|
||||
Id = 2,
|
||||
RelativePath = @"Season 01\30.rock.s01e02.avi",
|
||||
Path = Path.Combine(rootPath, @"Season 01\30.rock.s01e02.avi"),
|
||||
}))
|
||||
.Build()
|
||||
.ToList();
|
||||
|
|
|
@ -7,6 +7,7 @@ using NzbDrone.Core.Notifications.Synology;
|
|||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Music;
|
||||
using NzbDrone.Test.Common;
|
||||
using System.IO;
|
||||
|
||||
namespace NzbDrone.Core.Test.NotificationTests
|
||||
{
|
||||
|
@ -15,13 +16,14 @@ namespace NzbDrone.Core.Test.NotificationTests
|
|||
{
|
||||
private Artist _artist;
|
||||
private AlbumDownloadMessage _upgrade;
|
||||
private string rootPath = @"C:\Test\".AsOsAgnostic();
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
_artist = new Artist()
|
||||
{
|
||||
Path = @"C:\Test\".AsOsAgnostic()
|
||||
Path = rootPath,
|
||||
};
|
||||
|
||||
_upgrade = new AlbumDownloadMessage()
|
||||
|
@ -32,7 +34,7 @@ namespace NzbDrone.Core.Test.NotificationTests
|
|||
{
|
||||
new TrackFile
|
||||
{
|
||||
RelativePath = "file1.S01E01E02.mkv"
|
||||
Path = Path.Combine(rootPath, "file1.S01E01E02.mkv")
|
||||
}
|
||||
|
||||
},
|
||||
|
@ -41,11 +43,11 @@ namespace NzbDrone.Core.Test.NotificationTests
|
|||
{
|
||||
new TrackFile
|
||||
{
|
||||
RelativePath = "file1.S01E01.mkv"
|
||||
Path = Path.Combine(rootPath, "file1.S01E01.mkv")
|
||||
},
|
||||
new TrackFile
|
||||
{
|
||||
RelativePath = "file1.S01E02.mkv"
|
||||
Path = Path.Combine(rootPath, "file1.S01E02.mkv")
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -91,6 +91,12 @@
|
|||
<HintPath>..\packages\TagLibSharp-Lidarr.2.2.0.19\lib\netstandard2.0\TagLibSharp.dll</HintPath>
|
||||
<Private>True</Private>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.Abstractions, Version=4.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IO.Abstractions.4.0.11\lib\net40\System.IO.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.Abstractions.TestingHelpers, Version=4.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IO.Abstractions.TestingHelpers.4.0.11\lib\net40\System.IO.Abstractions.TestingHelpers.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Drawing" />
|
||||
|
@ -127,6 +133,7 @@
|
|||
<Compile Include="Datastore\MarrDataLazyLoadingFixture.cs" />
|
||||
<Compile Include="Datastore\Migration\004_add_various_qualities_in_profileFixture.cs" />
|
||||
<Compile Include="Datastore\Migration\023_add_release_groups_etcFixture.cs" />
|
||||
<Compile Include="Datastore\Migration\030_add_mediafilerepository_mtimeFixture.cs" />
|
||||
<Compile Include="Datastore\ObjectDatabaseFixture.cs" />
|
||||
<Compile Include="Datastore\PagingSpecExtensionsTests\PagingOffsetFixture.cs" />
|
||||
<Compile Include="Datastore\PagingSpecExtensionsTests\ToSortDirectionFixture.cs" />
|
||||
|
@ -206,6 +213,7 @@
|
|||
<Compile Include="Extras\Metadata\Consumers\Xbmc\FindMetadataFileFixture.cs" />
|
||||
<Compile Include="FluentTest.cs" />
|
||||
<Compile Include="Framework\CoreTest.cs" />
|
||||
<Compile Include="Framework\FileSystemTest.cs" />
|
||||
<Compile Include="Framework\DbTest.cs" />
|
||||
<Compile Include="Framework\DirectDataMapper.cs" />
|
||||
<Compile Include="Framework\MigrationTest.cs" />
|
||||
|
@ -432,6 +440,14 @@
|
|||
<Project>{CADDFCE0-7509-4430-8364-2074E1EEFCA2}</Project>
|
||||
<Name>NzbDrone.Test.Common</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\NzbDrone.Mono\NzbDrone.Mono.csproj">
|
||||
<Project>{15AD7579-A314-4626-B556-663F51D97CD1}</Project>
|
||||
<Name>NzbDrone.Mono</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\NzbDrone.Windows\NzbDrone.Windows.csproj">
|
||||
<Project>{911284D3-F130-459E-836C-2430B6FBF21D}</Project>
|
||||
<Name>NzbDrone.Windows</Name>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="..\..\Logo\1024.png">
|
||||
|
|
|
@ -391,28 +391,27 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
|
|||
public void use_file_name_when_sceneName_is_null()
|
||||
{
|
||||
_namingConfig.RenameTracks = false;
|
||||
_trackFile.RelativePath = "Linkin Park - 06 - Test";
|
||||
_trackFile.Path = "Linkin Park - 06 - Test";
|
||||
|
||||
Subject.BuildTrackFileName(new List<Track> { _track1 }, _artist, _album, _trackFile)
|
||||
.Should().Be(Path.GetFileNameWithoutExtension(_trackFile.RelativePath));
|
||||
.Should().Be(Path.GetFileNameWithoutExtension(_trackFile.Path));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void use_file_name_when_sceneName_is_not_null()
|
||||
{
|
||||
_namingConfig.RenameTracks = false;
|
||||
_trackFile.RelativePath = "Linkin Park - 06 - Test";
|
||||
_trackFile.Path = "Linkin Park - 06 - Test";
|
||||
_trackFile.SceneName = "SceneName";
|
||||
|
||||
Subject.BuildTrackFileName(new List<Track> { _track1 }, _artist, _album, _trackFile)
|
||||
.Should().Be(Path.GetFileNameWithoutExtension(_trackFile.RelativePath));
|
||||
.Should().Be(Path.GetFileNameWithoutExtension(_trackFile.Path));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void use_path_when_sceneName_and_relative_path_are_null()
|
||||
{
|
||||
_namingConfig.RenameTracks = false;
|
||||
_trackFile.RelativePath = null;
|
||||
_trackFile.Path = @"C:\Test\Unsorted\Artist - 01 - Test";
|
||||
|
||||
Subject.BuildTrackFileName(new List<Track> { _track1 }, _artist, _album, _trackFile)
|
||||
|
@ -447,7 +446,7 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
|
|||
_namingConfig.StandardTrackFormat = "{Artist Name} - {Original Title} - {Track Title}";
|
||||
|
||||
_trackFile.SceneName = "Linkin.Park.Meteora.320-LOL";
|
||||
_trackFile.RelativePath = "30 Rock - 01 - Test";
|
||||
_trackFile.Path = "30 Rock - 01 - Test";
|
||||
|
||||
Subject.BuildTrackFileName(new List<Track> { _track1 }, _artist, _album, _trackFile)
|
||||
.Should().Be("Linkin Park - Linkin.Park.Meteora.320-LOL - City Sushi");
|
||||
|
@ -520,10 +519,10 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
|
|||
_namingConfig.StandardTrackFormat = "{Original Title}";
|
||||
|
||||
_trackFile.SceneName = null;
|
||||
_trackFile.RelativePath = "existing.file.mkv";
|
||||
_trackFile.Path = "existing.file.mkv";
|
||||
|
||||
Subject.BuildTrackFileName(new List<Track> { _track1 }, _artist, _album, _trackFile)
|
||||
.Should().Be(Path.GetFileNameWithoutExtension(_trackFile.RelativePath));
|
||||
.Should().Be(Path.GetFileNameWithoutExtension(_trackFile.Path));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -533,7 +532,7 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
|
|||
_namingConfig.StandardTrackFormat = "{Original Title}";
|
||||
|
||||
_trackFile.SceneName = "30.Rock.S01E01.xvid-LOL";
|
||||
_trackFile.RelativePath = "30 Rock - S01E01 - Test";
|
||||
_trackFile.Path = "30 Rock - S01E01 - Test";
|
||||
|
||||
Subject.BuildTrackFileName(new List<Track> { _track1 }, _artist, _album, _trackFile)
|
||||
.Should().Be("30.Rock.S01E01.xvid-LOL");
|
||||
|
@ -599,7 +598,7 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
|
|||
_namingConfig.StandardTrackFormat = "{Artist Name} - {Original Filename}";
|
||||
|
||||
_trackFile.SceneName = "30.Rock.S01E01.xvid-LOL";
|
||||
_trackFile.RelativePath = "30 Rock - S01E01 - Test";
|
||||
_trackFile.Path = "30 Rock - S01E01 - Test";
|
||||
|
||||
Subject.BuildTrackFileName(new List<Track> { _track1 }, _artist, _album, _trackFile)
|
||||
.Should().Be("30 Rock - 30 Rock - S01E01 - Test");
|
||||
|
@ -612,7 +611,7 @@ namespace NzbDrone.Core.Test.OrganizerTests.FileNameBuilderTests
|
|||
_namingConfig.StandardTrackFormat = "{Original Filename}";
|
||||
|
||||
_trackFile.SceneName = "30.Rock.S01E01.xvid-LOL";
|
||||
_trackFile.RelativePath = "30 Rock - S01E01 - Test";
|
||||
_trackFile.Path = "30 Rock - S01E01 - Test";
|
||||
|
||||
Subject.BuildTrackFileName(new List<Track> { _track1 }, _artist, _album, _trackFile)
|
||||
.Should().Be("30 Rock - S01E01 - Test");
|
||||
|
|
|
@ -8,6 +8,7 @@ using NzbDrone.Common.Disk;
|
|||
using NzbDrone.Test.Common;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using System.IO.Abstractions;
|
||||
|
||||
namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests
|
||||
{
|
||||
|
@ -29,6 +30,10 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests
|
|||
@"movie.exe",
|
||||
@"movie"
|
||||
};
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.GetFileInfos(It.IsAny<string>(), It.IsAny<SearchOption>()))
|
||||
.Returns(new List<IFileInfo>());
|
||||
}
|
||||
|
||||
private IEnumerable<string> GetFiles(string folder, string subFolder = "")
|
||||
|
@ -38,9 +43,15 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests
|
|||
|
||||
private void GivenFiles(IEnumerable<string> files)
|
||||
{
|
||||
var filesToReturn = files.ToArray();
|
||||
var filesToReturn = files.Select(x => (FileInfoBase)new FileInfo(x)).ToList<IFileInfo>();
|
||||
|
||||
foreach (var file in filesToReturn)
|
||||
{
|
||||
TestLogger.Debug(file.Name);
|
||||
}
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.GetFiles(It.IsAny<string>(), SearchOption.AllDirectories))
|
||||
.Setup(s => s.GetFileInfos(It.IsAny<string>(), SearchOption.AllDirectories))
|
||||
.Returns(filesToReturn);
|
||||
}
|
||||
|
||||
|
@ -49,8 +60,8 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests
|
|||
{
|
||||
Subject.GetAudioFiles(path);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>().Verify(s => s.GetFiles(path, SearchOption.AllDirectories), Times.Once());
|
||||
Mocker.GetMock<IDiskProvider>().Verify(s => s.GetFiles(path, SearchOption.TopDirectoryOnly), Times.Never());
|
||||
Mocker.GetMock<IDiskProvider>().Verify(s => s.GetFileInfos(path, SearchOption.AllDirectories), Times.Once());
|
||||
Mocker.GetMock<IDiskProvider>().Verify(s => s.GetFileInfos(path, SearchOption.TopDirectoryOnly), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -58,8 +69,8 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests
|
|||
{
|
||||
Subject.GetAudioFiles(path, true);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>().Verify(s => s.GetFiles(path, SearchOption.AllDirectories), Times.Once());
|
||||
Mocker.GetMock<IDiskProvider>().Verify(s => s.GetFiles(path, SearchOption.TopDirectoryOnly), Times.Never());
|
||||
Mocker.GetMock<IDiskProvider>().Verify(s => s.GetFileInfos(path, SearchOption.AllDirectories), Times.Once());
|
||||
Mocker.GetMock<IDiskProvider>().Verify(s => s.GetFileInfos(path, SearchOption.TopDirectoryOnly), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -67,8 +78,8 @@ namespace NzbDrone.Core.Test.ProviderTests.DiskScanProviderTests
|
|||
{
|
||||
Subject.GetAudioFiles(path, false);
|
||||
|
||||
Mocker.GetMock<IDiskProvider>().Verify(s => s.GetFiles(path, SearchOption.AllDirectories), Times.Never());
|
||||
Mocker.GetMock<IDiskProvider>().Verify(s => s.GetFiles(path, SearchOption.TopDirectoryOnly), Times.Once());
|
||||
Mocker.GetMock<IDiskProvider>().Verify(s => s.GetFileInfos(path, SearchOption.AllDirectories), Times.Never());
|
||||
Mocker.GetMock<IDiskProvider>().Verify(s => s.GetFileInfos(path, SearchOption.TopDirectoryOnly), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
|
|
@ -15,4 +15,5 @@
|
|||
<package id="Prowlin" version="0.9.4456.26422" targetFramework="net461" />
|
||||
<package id="Unity" version="2.1.505.2" targetFramework="net461" />
|
||||
<package id="TagLibSharp-Lidarr" version="2.2.0.19" targetFramework="net461" />
|
||||
<package id="System.IO.Abstractions.TestingHelpers" version="4.0.11" targetFramework="net461" />
|
||||
</packages>
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
using System;
|
||||
using FluentMigrator;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(30)]
|
||||
public class add_mediafilerepository_mtime : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
Alter.Table("TrackFiles").AddColumn("Modified").AsDateTime().WithDefaultValue(new DateTime(2000, 1, 1));
|
||||
Alter.Table("TrackFiles").AddColumn("Path").AsString().Nullable();
|
||||
|
||||
// Remove anything where RelativePath is null
|
||||
Execute.Sql(@"DELETE FROM TrackFiles WHERE RelativePath IS NULL");
|
||||
|
||||
// Remove anything not linked to a track (these shouldn't be present in version < 30)
|
||||
Execute.Sql(@"DELETE FROM TrackFiles
|
||||
WHERE Id IN (
|
||||
SELECT TrackFiles.Id FROM TrackFiles
|
||||
LEFT JOIN Tracks ON TrackFiles.Id = Tracks.TrackFileId
|
||||
WHERE Tracks.Id IS NULL)");
|
||||
|
||||
// Remove anything where we can't get an artist path (i.e. we don't know where it is)
|
||||
Execute.Sql(@"DELETE FROM TrackFiles
|
||||
WHERE Id IN (
|
||||
SELECT TrackFiles.Id FROM TrackFiles
|
||||
LEFT JOIN Albums ON TrackFiles.AlbumId = Albums.Id
|
||||
LEFT JOIN Artists on Artists.ArtistMetadataId = Albums.ArtistMetadataId
|
||||
WHERE Artists.Path IS NULL)");
|
||||
|
||||
// Remove anything linked to unmonitored or unidentified releases. This should ensure uniqueness of track files.
|
||||
Execute.Sql(@"DELETE FROM TrackFiles
|
||||
WHERE Id IN (
|
||||
SELECT TrackFiles.Id FROM TrackFiles
|
||||
LEFT JOIN Tracks ON TrackFiles.Id = Tracks.TrackFileId
|
||||
LEFT JOIN AlbumReleases ON Tracks.AlbumReleaseId = AlbumReleases.Id
|
||||
WHERE AlbumReleases.Monitored = 0
|
||||
OR AlbumReleases.Monitored IS NULL)");
|
||||
|
||||
// Populate the full paths
|
||||
Execute.Sql(@"UPDATE TrackFiles
|
||||
SET Path = (SELECT Artists.Path || '" + System.IO.Path.DirectorySeparatorChar + @"' || TrackFiles.RelativePath
|
||||
FROM Artists
|
||||
JOIN Albums ON Albums.ArtistMetadataId = Artists.ArtistMetadataId
|
||||
WHERE TrackFiles.AlbumId = Albums.Id)");
|
||||
|
||||
// Belt and braces to ensure uniqueness
|
||||
Execute.Sql(@"DELETE FROM TrackFiles
|
||||
WHERE rowid NOT IN (
|
||||
SELECT min(rowid)
|
||||
FROM TrackFiles
|
||||
GROUP BY Path
|
||||
)");
|
||||
|
||||
// Now enforce the uniqueness constraint
|
||||
Alter.Table("TrackFiles").AlterColumn("Path").AsString().NotNullable().Unique();
|
||||
|
||||
// Finally delete the relative path column
|
||||
Delete.Column("RelativePath").FromTable("TrackFiles");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -147,7 +147,6 @@ namespace NzbDrone.Core.Datastore
|
|||
.SingleOrDefault());
|
||||
|
||||
Mapper.Entity<TrackFile>().RegisterModel("TrackFiles")
|
||||
.Ignore(f => f.Path)
|
||||
.Relationship()
|
||||
.HasOne(f => f.Album, f => f.AlbumId)
|
||||
.For(f => f.Tracks)
|
||||
|
|
|
@ -56,7 +56,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
|||
{
|
||||
foreach (var missingTrackFile in missingTrackFiles)
|
||||
{
|
||||
_logger.Trace("Track file {0} is missing from disk.", missingTrackFile.RelativePath);
|
||||
_logger.Trace("Track file {0} is missing from disk.", missingTrackFile.Path);
|
||||
}
|
||||
|
||||
_logger.Debug("Files for this album exist in the database but not on disk, will be unmonitored on next diskscan. skipping.");
|
||||
|
@ -68,9 +68,7 @@ namespace NzbDrone.Core.DecisionEngine.Specifications.RssSync
|
|||
|
||||
private bool IsTrackFileMissing(Artist artist, TrackFile trackFile)
|
||||
{
|
||||
var fullPath = Path.Combine(artist.Path, trackFile.RelativePath);
|
||||
|
||||
return !_diskProvider.FileExists(fullPath);
|
||||
return !_diskProvider.FileExists(trackFile.Path);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,14 +88,14 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
|
|||
|
||||
foreach (var audioFile in _diskScanService.FilterFiles(watchFolder, _diskScanService.GetAudioFiles(watchFolder, false)))
|
||||
{
|
||||
var title = FileNameBuilder.CleanFileName(Path.GetFileName(audioFile));
|
||||
var title = FileNameBuilder.CleanFileName(audioFile.Name);
|
||||
|
||||
var newWatchItem = new WatchFolderItem
|
||||
{
|
||||
DownloadId = Path.GetFileName(audioFile) + "_" + _diskProvider.FileGetLastWrite(audioFile).Ticks,
|
||||
DownloadId = audioFile.Name + "_" + audioFile.LastWriteTimeUtc.Ticks,
|
||||
Title = title,
|
||||
|
||||
OutputPath = new OsPath(audioFile),
|
||||
OutputPath = new OsPath(audioFile.FullName),
|
||||
|
||||
Status = DownloadItemStatus.Completed,
|
||||
RemainingTime = TimeSpan.Zero
|
||||
|
@ -105,10 +105,10 @@ namespace NzbDrone.Core.Download.Clients.Blackhole
|
|||
|
||||
if (PreCheckWatchItemExpiry(newWatchItem, oldWatchItem))
|
||||
{
|
||||
newWatchItem.TotalSize = _diskProvider.GetFileSize(audioFile);
|
||||
newWatchItem.Hash = GetHash(audioFile);
|
||||
newWatchItem.TotalSize = audioFile.Length;
|
||||
newWatchItem.Hash = GetHash(audioFile.FullName);
|
||||
|
||||
if (_diskProvider.IsFileLocked(audioFile))
|
||||
if (_diskProvider.IsFileLocked(audioFile.FullName))
|
||||
{
|
||||
newWatchItem.Status = DownloadItemStatus.Downloading;
|
||||
}
|
||||
|
|
|
@ -50,8 +50,8 @@ namespace NzbDrone.Core.Extras.Files
|
|||
|
||||
protected TExtraFile ImportFile(Artist artist, TrackFile trackFile, string path, bool readOnly, string extension, string fileNameSuffix = null)
|
||||
{
|
||||
var newFolder = Path.GetDirectoryName(Path.Combine(artist.Path, trackFile.RelativePath));
|
||||
var filenameBuilder = new StringBuilder(Path.GetFileNameWithoutExtension(trackFile.RelativePath));
|
||||
var newFolder = Path.GetDirectoryName(trackFile.Path);
|
||||
var filenameBuilder = new StringBuilder(Path.GetFileNameWithoutExtension(trackFile.Path));
|
||||
|
||||
if (fileNameSuffix.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
|
@ -82,8 +82,8 @@ namespace NzbDrone.Core.Extras.Files
|
|||
|
||||
protected TExtraFile MoveFile(Artist artist, TrackFile trackFile, TExtraFile extraFile, string fileNameSuffix = null)
|
||||
{
|
||||
var newFolder = Path.GetDirectoryName(Path.Combine(artist.Path, trackFile.RelativePath));
|
||||
var filenameBuilder = new StringBuilder(Path.GetFileNameWithoutExtension(trackFile.RelativePath));
|
||||
var newFolder = Path.GetDirectoryName(trackFile.Path);
|
||||
var filenameBuilder = new StringBuilder(Path.GetFileNameWithoutExtension(trackFile.Path));
|
||||
|
||||
if (fileNameSuffix.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
|
|
|
@ -65,7 +65,7 @@ namespace NzbDrone.Core.Extras.Lyrics
|
|||
|
||||
if (groupCount > 1)
|
||||
{
|
||||
_logger.Warn("Multiple lyric files found with the same language and extension for {0}", Path.Combine(artist.Path, trackFile.RelativePath));
|
||||
_logger.Warn("Multiple lyric files found with the same language and extension for {0}", trackFile.Path);
|
||||
}
|
||||
|
||||
foreach (var subtitleFile in group)
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Roksbox
|
|||
|
||||
public override string GetFilenameAfterMove(Artist artist, TrackFile trackFile, MetadataFile metadataFile)
|
||||
{
|
||||
var trackFilePath = Path.Combine(artist.Path, trackFile.RelativePath);
|
||||
var trackFilePath = trackFile.Path;
|
||||
|
||||
if (metadataFile.Type == MetadataType.TrackMetadata)
|
||||
{
|
||||
|
@ -122,7 +122,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Roksbox
|
|||
return null;
|
||||
}
|
||||
|
||||
_logger.Debug("Generating Track Metadata for: {0}", trackFile.RelativePath);
|
||||
_logger.Debug("Generating Track Metadata for: {0}", trackFile.Path);
|
||||
|
||||
var xmlResult = string.Empty;
|
||||
foreach (var track in trackFile.Tracks.Value)
|
||||
|
@ -148,7 +148,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Roksbox
|
|||
}
|
||||
}
|
||||
|
||||
return new MetadataFileResult(GetTrackMetadataFilename(trackFile.RelativePath), xmlResult.Trim(Environment.NewLine.ToCharArray()));
|
||||
return new MetadataFileResult(GetTrackMetadataFilename(artist.Path.GetRelativePath(trackFile.Path)), xmlResult.Trim(Environment.NewLine.ToCharArray()));
|
||||
}
|
||||
|
||||
public override List<ImageFileResult> ArtistImages(Artist artist)
|
||||
|
|
|
@ -35,7 +35,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Wdtv
|
|||
|
||||
public override string GetFilenameAfterMove(Artist artist, TrackFile trackFile, MetadataFile metadataFile)
|
||||
{
|
||||
var trackFilePath = Path.Combine(artist.Path, trackFile.RelativePath);
|
||||
var trackFilePath = trackFile.Path;
|
||||
|
||||
if (metadataFile.Type == MetadataType.TrackMetadata)
|
||||
{
|
||||
|
@ -94,7 +94,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Wdtv
|
|||
return null;
|
||||
}
|
||||
|
||||
_logger.Debug("Generating Track Metadata for: {0}", Path.Combine(artist.Path, trackFile.RelativePath));
|
||||
_logger.Debug("Generating Track Metadata for: {0}", trackFile.Path);
|
||||
|
||||
var xmlResult = string.Empty;
|
||||
foreach (var track in trackFile.Tracks.Value)
|
||||
|
@ -124,7 +124,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Wdtv
|
|||
}
|
||||
}
|
||||
|
||||
var filename = GetTrackMetadataFilename(trackFile.RelativePath);
|
||||
var filename = GetTrackMetadataFilename(artist.Path.GetRelativePath(trackFile.Path));
|
||||
|
||||
return new MetadataFileResult(filename, xmlResult.Trim(Environment.NewLine.ToCharArray()));
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace NzbDrone.Core.Extras.Metadata.Consumers.Xbmc
|
|||
|
||||
public override string GetFilenameAfterMove(Artist artist, TrackFile trackFile, MetadataFile metadataFile)
|
||||
{
|
||||
var trackFilePath = Path.Combine(artist.Path, trackFile.RelativePath);
|
||||
var trackFilePath = trackFile.Path;
|
||||
|
||||
if (metadataFile.Type == MetadataType.TrackMetadata)
|
||||
{
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace NzbDrone.Core.Extras.Metadata
|
|||
{
|
||||
var existingFilename = Path.Combine(artist.Path, metadataFile.RelativePath);
|
||||
var extension = Path.GetExtension(existingFilename).TrimStart('.');
|
||||
var newFileName = Path.ChangeExtension(Path.Combine(artist.Path, trackFile.RelativePath), extension);
|
||||
var newFileName = Path.ChangeExtension(trackFile.Path, extension);
|
||||
|
||||
return newFileName;
|
||||
}
|
||||
|
|
|
@ -80,7 +80,7 @@ namespace NzbDrone.Core.Extras.Metadata
|
|||
files.AddIfNotNull(ProcessArtistMetadata(consumer, artist, consumerFiles));
|
||||
files.AddRange(ProcessArtistImages(consumer, artist, consumerFiles));
|
||||
|
||||
var albumGroups = trackFiles.GroupBy(s => Path.GetDirectoryName(s.RelativePath)).ToList();
|
||||
var albumGroups = trackFiles.GroupBy(s => Path.GetDirectoryName(s.Path)).ToList();
|
||||
|
||||
foreach (var group in albumGroups)
|
||||
{
|
||||
|
@ -146,7 +146,7 @@ namespace NzbDrone.Core.Extras.Metadata
|
|||
{
|
||||
var metadataFiles = _metadataFileService.GetFilesByArtist(artist.Id);
|
||||
var movedFiles = new List<MetadataFile>();
|
||||
var distinctTrackFilePaths = trackFiles.DistinctBy(s => Path.GetDirectoryName(s.RelativePath)).ToList();
|
||||
var distinctTrackFilePaths = trackFiles.DistinctBy(s => Path.GetDirectoryName(s.Path)).ToList();
|
||||
|
||||
// TODO: Move EpisodeImage and EpisodeMetadata metadata files, instead of relying on consumers to do it
|
||||
// (Xbmc's EpisodeImage is more than just the extension)
|
||||
|
@ -162,7 +162,7 @@ namespace NzbDrone.Core.Extras.Metadata
|
|||
|
||||
foreach (var metadataFile in metadataFilesForConsumer)
|
||||
{
|
||||
var newFileName = consumer.GetFilenameAfterMove(artist, Path.GetDirectoryName(filePath.RelativePath), metadataFile);
|
||||
var newFileName = consumer.GetFilenameAfterMove(artist, Path.GetDirectoryName(filePath.Path), metadataFile);
|
||||
var existingFileName = Path.Combine(artist.Path, metadataFile.RelativePath);
|
||||
|
||||
if (newFileName.PathNotEquals(existingFileName))
|
||||
|
|
|
@ -234,7 +234,7 @@ namespace NzbDrone.Core.History
|
|||
//Won't have a value since we publish this event before saving to DB.
|
||||
//history.Data.Add("FileId", message.ImportedEpisode.Id.ToString());
|
||||
history.Data.Add("DroppedPath", message.TrackInfo.Path);
|
||||
history.Data.Add("ImportedPath", Path.Combine(message.TrackInfo.Artist.Path, message.ImportedTrack.RelativePath));
|
||||
history.Data.Add("ImportedPath", message.ImportedTrack.Path);
|
||||
history.Data.Add("DownloadClient", message.DownloadClient);
|
||||
|
||||
_historyRepository.Insert(history);
|
||||
|
@ -321,8 +321,7 @@ namespace NzbDrone.Core.History
|
|||
{
|
||||
var sourcePath = message.OriginalPath;
|
||||
var sourceRelativePath = message.Artist.Path.GetRelativePath(message.OriginalPath);
|
||||
var path = Path.Combine(message.Artist.Path, message.TrackFile.RelativePath);
|
||||
var relativePath = message.TrackFile.RelativePath;
|
||||
var path = message.TrackFile.Path;
|
||||
|
||||
foreach (var track in message.TrackFile.Tracks.Value)
|
||||
{
|
||||
|
@ -340,7 +339,6 @@ namespace NzbDrone.Core.History
|
|||
history.Data.Add("SourcePath", sourcePath);
|
||||
history.Data.Add("SourceRelativePath", sourceRelativePath);
|
||||
history.Data.Add("Path", path);
|
||||
history.Data.Add("RelativePath", relativePath);
|
||||
|
||||
_historyRepository.Insert(history);
|
||||
}
|
||||
|
@ -348,8 +346,7 @@ namespace NzbDrone.Core.History
|
|||
|
||||
public void Handle(TrackFileRetaggedEvent message)
|
||||
{
|
||||
var path = Path.Combine(message.Artist.Path, message.TrackFile.RelativePath);
|
||||
var relativePath = message.TrackFile.RelativePath;
|
||||
var path = message.TrackFile.Path;
|
||||
|
||||
foreach (var track in message.TrackFile.Tracks.Value)
|
||||
{
|
||||
|
|
|
@ -15,23 +15,15 @@ namespace NzbDrone.Core.Housekeeping.Housekeepers
|
|||
{
|
||||
var mapper = _database.GetDataMapper();
|
||||
|
||||
// Delete where track no longer exists
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM TrackFiles
|
||||
// Unlink where track no longer exists
|
||||
mapper.ExecuteNonQuery(@"UPDATE TrackFiles
|
||||
SET AlbumId = 0
|
||||
WHERE Id IN (
|
||||
SELECT TrackFiles.Id FROM TrackFiles
|
||||
LEFT OUTER JOIN Tracks
|
||||
ON TrackFiles.Id = Tracks.TrackFileId
|
||||
WHERE Tracks.Id IS NULL)");
|
||||
|
||||
// Delete trackfiles associated with releases that are not currently selected
|
||||
mapper.ExecuteNonQuery(@"DELETE FROM TrackFiles
|
||||
WHERE Id IN (
|
||||
SELECT TrackFiles.Id FROM TrackFiles
|
||||
JOIN Tracks ON TrackFiles.Id = Tracks.TrackFileId
|
||||
JOIN AlbumReleases ON Tracks.AlbumReleaseId = AlbumReleases.Id
|
||||
JOIN Albums ON AlbumReleases.AlbumId = Albums.Id
|
||||
WHERE AlbumReleases.Monitored = 0)");
|
||||
|
||||
// Unlink Tracks where the Trackfiles entry no longer exists
|
||||
mapper.ExecuteNonQuery(@"UPDATE Tracks
|
||||
SET TrackFileId = 0
|
||||
|
|
|
@ -15,6 +15,7 @@ using NLog.Fluent;
|
|||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using TagLib;
|
||||
using NzbDrone.Common.Extensions;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles
|
||||
{
|
||||
|
@ -176,7 +177,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
}
|
||||
|
||||
var newTags = GetTrackMetadata(trackfile);
|
||||
var path = Path.Combine(trackfile.Artist.Value.Path, trackfile.RelativePath);
|
||||
var path = trackfile.Path;
|
||||
|
||||
var diff = ReadAudioTag(path).Diff(newTags);
|
||||
|
||||
|
@ -270,7 +271,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
return;
|
||||
}
|
||||
|
||||
var path = Path.Combine(trackfile.Artist.Value.Path, trackfile.RelativePath);
|
||||
var path = trackfile.Path;
|
||||
_logger.Debug($"Removing MusicBrainz tags for {path}");
|
||||
|
||||
RemoveMusicBrainzTags(path);
|
||||
|
@ -312,7 +313,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
continue;
|
||||
}
|
||||
|
||||
var oldTags = ReadAudioTag(Path.Combine(f.Artist.Value.Path, f.RelativePath));
|
||||
var oldTags = ReadAudioTag(f.Path);
|
||||
var newTags = GetTrackMetadata(f);
|
||||
var diff = oldTags.Diff(newTags);
|
||||
|
||||
|
@ -323,7 +324,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
AlbumId = file.Album.Value.Id,
|
||||
TrackNumbers = file.Tracks.Value.Select(e => e.AbsoluteTrackNumber).ToList(),
|
||||
TrackFileId = file.Id,
|
||||
RelativePath = file.RelativePath,
|
||||
RelativePath = file.Artist.Value.Path.GetRelativePath(file.Path),
|
||||
Changes = diff
|
||||
};
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using NLog;
|
||||
|
@ -15,18 +16,17 @@ using NzbDrone.Core.Messaging.Commands;
|
|||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.RootFolders;
|
||||
using NzbDrone.Core.Music;
|
||||
using NzbDrone.Core.Music.Events;
|
||||
using NzbDrone.Core.MediaFiles.TrackImport;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Common;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles
|
||||
{
|
||||
public interface IDiskScanService
|
||||
{
|
||||
void Scan(Artist artist);
|
||||
string[] GetAudioFiles(string path, bool allDirectories = true);
|
||||
void Scan(Artist artist, FilterFilesType filter = FilterFilesType.Known);
|
||||
IFileInfo[] GetAudioFiles(string path, bool allDirectories = true);
|
||||
string[] GetNonAudioFiles(string path, bool allDirectories = true);
|
||||
List<IFileInfo> FilterFiles(string basePath, IEnumerable<IFileInfo> files);
|
||||
List<string> FilterFiles(string basePath, IEnumerable<string> files);
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
private static readonly Regex ExcludedSubFoldersRegex = new Regex(@"(?:\\|\/|^)(?:extras|@eadir|extrafanart|plex versions|\.[^\\/]+)(?:\\|\/)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
private static readonly Regex ExcludedFilesRegex = new Regex(@"^\._|^Thumbs\.db$|^\.DS_store$|\.partial~$", RegexOptions.Compiled | RegexOptions.IgnoreCase);
|
||||
|
||||
public void Scan(Artist artist)
|
||||
public void Scan(Artist artist, FilterFilesType filter = FilterFilesType.Known)
|
||||
{
|
||||
var rootFolder = _rootFolderService.GetBestRootFolderPath(artist.Path);
|
||||
|
||||
|
@ -113,44 +113,70 @@ namespace NzbDrone.Core.MediaFiles
|
|||
var mediaFileList = FilterFiles(artist.Path, GetAudioFiles(artist.Path)).ToList();
|
||||
musicFilesStopwatch.Stop();
|
||||
_logger.Trace("Finished getting track files for: {0} [{1}]", artist, musicFilesStopwatch.Elapsed);
|
||||
|
||||
CleanMediaFiles(artist, mediaFileList);
|
||||
|
||||
CleanMediaFiles(artist, mediaFileList.Select(x => x.FullName).ToList());
|
||||
|
||||
var decisionsStopwatch = Stopwatch.StartNew();
|
||||
var decisions = _importDecisionMaker.GetImportDecisions(mediaFileList, artist, false);
|
||||
var decisions = _importDecisionMaker.GetImportDecisions(mediaFileList, artist, filter, true);
|
||||
decisionsStopwatch.Stop();
|
||||
_logger.Debug("Import decisions complete for: {0} [{1}]", artist, decisionsStopwatch.Elapsed);
|
||||
|
||||
var importStopwatch = Stopwatch.StartNew();
|
||||
_importApprovedTracks.Import(decisions, false);
|
||||
|
||||
// decisions may have been filtered to just new files. Anything new and approved will have been inserted.
|
||||
// Now we need to make sure anything new but not approved gets inserted
|
||||
// Note that knownFiles will include anything imported just now
|
||||
var knownFiles = _mediaFileService.GetFilesWithBasePath(artist.Path);
|
||||
|
||||
var newFiles = decisions
|
||||
.ExceptBy(x => x.Item.Path, knownFiles, x => x.Path, PathEqualityComparer.Instance)
|
||||
.Select(decision => new TrackFile {
|
||||
Path = decision.Item.Path,
|
||||
Size = decision.Item.Size,
|
||||
Modified = decision.Item.Modified,
|
||||
DateAdded = DateTime.UtcNow,
|
||||
Quality = decision.Item.Quality,
|
||||
MediaInfo = decision.Item.FileTrackInfo.MediaInfo,
|
||||
Language = decision.Item.Language
|
||||
})
|
||||
.ToList();
|
||||
_mediaFileService.AddMany(newFiles);
|
||||
|
||||
_logger.Debug($"Inserted {newFiles.Count} new unmatched trackfiles");
|
||||
|
||||
// finally update info on size/modified for existing files
|
||||
var updatedFiles = knownFiles
|
||||
.Join(decisions,
|
||||
x => x.Path,
|
||||
x => x.Item.Path,
|
||||
(file, decision) => new {
|
||||
File = file,
|
||||
Item = decision.Item
|
||||
},
|
||||
PathEqualityComparer.Instance)
|
||||
.Where(x => x.File.Size != x.Item.Size ||
|
||||
Math.Abs((x.File.Modified - x.Item.Modified).TotalSeconds) > 1 )
|
||||
.Select(x => {
|
||||
x.File.Size = x.Item.Size;
|
||||
x.File.Modified = x.Item.Modified;
|
||||
x.File.MediaInfo = x.Item.FileTrackInfo.MediaInfo;
|
||||
x.File.Quality = x.Item.Quality;
|
||||
return x.File;
|
||||
})
|
||||
.ToList();
|
||||
|
||||
_mediaFileService.Update(updatedFiles);
|
||||
|
||||
_logger.Debug($"Updated info for {updatedFiles.Count} known files");
|
||||
|
||||
RemoveEmptyArtistFolder(artist.Path);
|
||||
UpdateMediaInfo(artist, decisions.Select(x => x.Item).ToList());
|
||||
|
||||
CompletedScanning(artist);
|
||||
importStopwatch.Stop();
|
||||
_logger.Debug("Track import complete for: {0} [{1}]", artist, importStopwatch.Elapsed);
|
||||
}
|
||||
|
||||
private void UpdateMediaInfo(Artist artist, List<LocalTrack> mediaFiles)
|
||||
{
|
||||
var existingFiles = _mediaFileService.GetFilesByArtist(artist.Id);
|
||||
var toUpdate = new List<TrackFile>(existingFiles.Count);
|
||||
|
||||
foreach (var file in existingFiles)
|
||||
{
|
||||
var path = Path.Combine(artist.Path, file.RelativePath);
|
||||
var scannedFile = mediaFiles.FirstOrDefault(x => PathEqualityComparer.Instance.Equals(path, x.Path));
|
||||
|
||||
if (scannedFile != null)
|
||||
{
|
||||
file.MediaInfo = scannedFile.FileTrackInfo.MediaInfo;
|
||||
toUpdate.Add(file);
|
||||
}
|
||||
}
|
||||
|
||||
_logger.Debug($"Updating Media Info for:\n{string.Join("\n", toUpdate)}");
|
||||
_mediaFileService.UpdateMediaInfo(toUpdate);
|
||||
}
|
||||
|
||||
private void CleanMediaFiles(Artist artist, List<string> mediaFileList)
|
||||
{
|
||||
_logger.Debug("{0} Cleaning up media files in DB", artist);
|
||||
|
@ -163,14 +189,14 @@ namespace NzbDrone.Core.MediaFiles
|
|||
_eventAggregator.PublishEvent(new ArtistScannedEvent(artist));
|
||||
}
|
||||
|
||||
public string[] GetAudioFiles(string path, bool allDirectories = true)
|
||||
public IFileInfo[] GetAudioFiles(string path, bool allDirectories = true)
|
||||
{
|
||||
_logger.Debug("Scanning '{0}' for music files", path);
|
||||
|
||||
var searchOption = allDirectories ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
|
||||
var filesOnDisk = _diskProvider.GetFiles(path, searchOption).ToList();
|
||||
var filesOnDisk = _diskProvider.GetFileInfos(path, searchOption);
|
||||
|
||||
var mediaFileList = filesOnDisk.Where(file => MediaFileExtensions.Extensions.Contains(Path.GetExtension(file)))
|
||||
var mediaFileList = filesOnDisk.Where(file => MediaFileExtensions.Extensions.Contains(file.Extension))
|
||||
.ToList();
|
||||
|
||||
_logger.Trace("{0} files were found in {1}", filesOnDisk.Count, path);
|
||||
|
@ -202,6 +228,13 @@ namespace NzbDrone.Core.MediaFiles
|
|||
.ToList();
|
||||
}
|
||||
|
||||
public List<IFileInfo> FilterFiles(string basePath, IEnumerable<IFileInfo> files)
|
||||
{
|
||||
return files.Where(file => !ExcludedSubFoldersRegex.IsMatch(basePath.GetRelativePath(file.FullName)))
|
||||
.Where(file => !ExcludedFilesRegex.IsMatch(file.Name))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private void SetPermissions(string path)
|
||||
{
|
||||
if (!_configService.SetPermissionsLinux)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
|
@ -17,9 +18,9 @@ namespace NzbDrone.Core.MediaFiles
|
|||
{
|
||||
public interface IDownloadedTracksImportService
|
||||
{
|
||||
List<ImportResult> ProcessRootFolder(DirectoryInfo directoryInfo);
|
||||
List<ImportResult> ProcessRootFolder(IDirectoryInfo directoryInfo);
|
||||
List<ImportResult> ProcessPath(string path, ImportMode importMode = ImportMode.Auto, Artist artist = null, DownloadClientItem downloadClientItem = null);
|
||||
bool ShouldDeleteFolder(DirectoryInfo directoryInfo, Artist artist);
|
||||
bool ShouldDeleteFolder(IDirectoryInfo directoryInfo, Artist artist);
|
||||
}
|
||||
|
||||
public class DownloadedTracksImportService : IDownloadedTracksImportService
|
||||
|
@ -52,19 +53,19 @@ namespace NzbDrone.Core.MediaFiles
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
public List<ImportResult> ProcessRootFolder(DirectoryInfo directoryInfo)
|
||||
public List<ImportResult> ProcessRootFolder(IDirectoryInfo directoryInfo)
|
||||
{
|
||||
var results = new List<ImportResult>();
|
||||
|
||||
foreach (var subFolder in _diskProvider.GetDirectories(directoryInfo.FullName))
|
||||
foreach (var subFolder in _diskProvider.GetDirectoryInfos(directoryInfo.FullName))
|
||||
{
|
||||
var folderResults = ProcessFolder(new DirectoryInfo(subFolder), ImportMode.Auto, null);
|
||||
var folderResults = ProcessFolder(subFolder, ImportMode.Auto, null);
|
||||
results.AddRange(folderResults);
|
||||
}
|
||||
|
||||
foreach (var audioFile in _diskScanService.GetAudioFiles(directoryInfo.FullName, false))
|
||||
{
|
||||
var fileResults = ProcessFile(new FileInfo(audioFile), ImportMode.Auto, null);
|
||||
var fileResults = ProcessFile(audioFile, ImportMode.Auto, null);
|
||||
results.AddRange(fileResults);
|
||||
}
|
||||
|
||||
|
@ -75,7 +76,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
{
|
||||
if (_diskProvider.FolderExists(path))
|
||||
{
|
||||
var directoryInfo = new DirectoryInfo(path);
|
||||
var directoryInfo = _diskProvider.GetDirectoryInfo(path);
|
||||
|
||||
if (artist == null)
|
||||
{
|
||||
|
@ -87,7 +88,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
|
||||
if (_diskProvider.FileExists(path))
|
||||
{
|
||||
var fileInfo = new FileInfo(path);
|
||||
var fileInfo = _diskProvider.GetFileInfo(path);
|
||||
|
||||
if (artist == null)
|
||||
{
|
||||
|
@ -103,14 +104,14 @@ namespace NzbDrone.Core.MediaFiles
|
|||
return new List<ImportResult>();
|
||||
}
|
||||
|
||||
public bool ShouldDeleteFolder(DirectoryInfo directoryInfo, Artist artist)
|
||||
public bool ShouldDeleteFolder(IDirectoryInfo directoryInfo, Artist artist)
|
||||
{
|
||||
var audioFiles = _diskScanService.GetAudioFiles(directoryInfo.FullName);
|
||||
var rarFiles = _diskProvider.GetFiles(directoryInfo.FullName, SearchOption.AllDirectories).Where(f => Path.GetExtension(f).Equals(".rar", StringComparison.OrdinalIgnoreCase));
|
||||
|
||||
foreach (var audioFile in audioFiles)
|
||||
{
|
||||
var albumParseResult = Parser.Parser.ParseMusicTitle(Path.GetFileName(audioFile));
|
||||
var albumParseResult = Parser.Parser.ParseMusicTitle(audioFile.Name);
|
||||
|
||||
if (albumParseResult == null)
|
||||
{
|
||||
|
@ -131,7 +132,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
return true;
|
||||
}
|
||||
|
||||
private List<ImportResult> ProcessFolder(DirectoryInfo directoryInfo, ImportMode importMode, DownloadClientItem downloadClientItem)
|
||||
private List<ImportResult> ProcessFolder(IDirectoryInfo directoryInfo, ImportMode importMode, DownloadClientItem downloadClientItem)
|
||||
{
|
||||
var cleanedUpName = GetCleanedUpFolderName(directoryInfo.Name);
|
||||
var artist = _parsingService.GetArtist(cleanedUpName);
|
||||
|
@ -149,7 +150,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
return ProcessFolder(directoryInfo, importMode, artist, downloadClientItem);
|
||||
}
|
||||
|
||||
private List<ImportResult> ProcessFolder(DirectoryInfo directoryInfo, ImportMode importMode, Artist artist, DownloadClientItem downloadClientItem)
|
||||
private List<ImportResult> ProcessFolder(IDirectoryInfo directoryInfo, ImportMode importMode, Artist artist, DownloadClientItem downloadClientItem)
|
||||
{
|
||||
if (_artistService.ArtistPathExists(directoryInfo.FullName))
|
||||
{
|
||||
|
@ -185,17 +186,17 @@ namespace NzbDrone.Core.MediaFiles
|
|||
{
|
||||
foreach (var audioFile in audioFiles)
|
||||
{
|
||||
if (_diskProvider.IsFileLocked(audioFile))
|
||||
if (_diskProvider.IsFileLocked(audioFile.FullName))
|
||||
{
|
||||
return new List<ImportResult>
|
||||
{
|
||||
FileIsLockedResult(audioFile)
|
||||
FileIsLockedResult(audioFile.FullName)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var decisions = _importDecisionMaker.GetImportDecisions(audioFiles.ToList(), artist, trackInfo);
|
||||
var decisions = _importDecisionMaker.GetImportDecisions(audioFiles, artist, trackInfo);
|
||||
var importResults = _importApprovedTracks.Import(decisions, true, downloadClientItem, importMode);
|
||||
|
||||
if (importMode == ImportMode.Auto)
|
||||
|
@ -214,7 +215,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
return importResults;
|
||||
}
|
||||
|
||||
private List<ImportResult> ProcessFile(FileInfo fileInfo, ImportMode importMode, DownloadClientItem downloadClientItem)
|
||||
private List<ImportResult> ProcessFile(IFileInfo fileInfo, ImportMode importMode, DownloadClientItem downloadClientItem)
|
||||
{
|
||||
var artist = _parsingService.GetArtist(Path.GetFileNameWithoutExtension(fileInfo.Name));
|
||||
|
||||
|
@ -231,7 +232,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
return ProcessFile(fileInfo, importMode, artist, downloadClientItem);
|
||||
}
|
||||
|
||||
private List<ImportResult> ProcessFile(FileInfo fileInfo, ImportMode importMode, Artist artist, DownloadClientItem downloadClientItem)
|
||||
private List<ImportResult> ProcessFile(IFileInfo fileInfo, ImportMode importMode, Artist artist, DownloadClientItem downloadClientItem)
|
||||
{
|
||||
if (Path.GetFileNameWithoutExtension(fileInfo.Name).StartsWith("._"))
|
||||
{
|
||||
|
@ -254,7 +255,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
}
|
||||
}
|
||||
|
||||
var decisions = _importDecisionMaker.GetImportDecisions(new List<string>() { fileInfo.FullName }, artist, null);
|
||||
var decisions = _importDecisionMaker.GetImportDecisions(new List<IFileInfo>() { fileInfo }, artist, null);
|
||||
|
||||
return _importApprovedTracks.Import(decisions, true, downloadClientItem, importMode);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
namespace NzbDrone.Core.MediaFiles
|
||||
{
|
||||
public enum FilterFilesType
|
||||
{
|
||||
None,
|
||||
Matched,
|
||||
Known
|
||||
}
|
||||
}
|
|
@ -47,7 +47,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
|
||||
public void DeleteTrackFile(Artist artist, TrackFile trackFile)
|
||||
{
|
||||
var fullPath = Path.Combine(artist.Path, trackFile.RelativePath);
|
||||
var fullPath = trackFile.Path;
|
||||
var rootFolder = _diskProvider.GetParentFolder(artist.Path);
|
||||
|
||||
if (!_diskProvider.FolderExists(rootFolder))
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Marr.Data.QGen;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
|
@ -11,7 +12,8 @@ namespace NzbDrone.Core.MediaFiles
|
|||
List<TrackFile> GetFilesByArtist(int artistId);
|
||||
List<TrackFile> GetFilesByAlbum(int albumId);
|
||||
List<TrackFile> GetFilesByRelease(int releaseId);
|
||||
List<TrackFile> GetFilesWithRelativePath(int artistId, string relativePath);
|
||||
List<TrackFile> GetFilesWithBasePath(string path);
|
||||
TrackFile GetFileWithPath(string path);
|
||||
}
|
||||
|
||||
|
||||
|
@ -55,15 +57,17 @@ namespace NzbDrone.Core.MediaFiles
|
|||
.Where<Track>(x => x.AlbumReleaseId == releaseId)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
|
||||
public List<TrackFile> GetFilesWithRelativePath(int artistId, string relativePath)
|
||||
public List<TrackFile> GetFilesWithBasePath(string path)
|
||||
{
|
||||
return Query
|
||||
.Join<Track, AlbumRelease>(JoinType.Inner, t => t.AlbumRelease, (t, r) => t.AlbumReleaseId == r.Id)
|
||||
.Where<AlbumRelease>(r => r.Monitored == true)
|
||||
.AndWhere(t => t.Artist.Value.Id == artistId && t.RelativePath == relativePath)
|
||||
.Where(x => x.Path.StartsWith(path))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public TrackFile GetFileWithPath(string path)
|
||||
{
|
||||
return Query.Where(x => x.Path == path).SingleOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
|
@ -8,6 +9,7 @@ using NzbDrone.Common;
|
|||
using NzbDrone.Core.Music;
|
||||
using System;
|
||||
using NzbDrone.Core.Music.Events;
|
||||
using NzbDrone.Common.Extensions;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles
|
||||
{
|
||||
|
@ -21,10 +23,11 @@ namespace NzbDrone.Core.MediaFiles
|
|||
List<TrackFile> GetFilesByArtist(int artistId);
|
||||
List<TrackFile> GetFilesByAlbum(int albumId);
|
||||
List<TrackFile> GetFilesByRelease(int releaseId);
|
||||
List<string> FilterExistingFiles(List<string> files, Artist artist);
|
||||
List<IFileInfo> FilterUnchangedFiles(List<IFileInfo> files, Artist artist, FilterFilesType filter);
|
||||
TrackFile Get(int id);
|
||||
List<TrackFile> Get(IEnumerable<int> ids);
|
||||
List<TrackFile> GetFilesWithRelativePath(int artistId, string relativePath);
|
||||
List<TrackFile> GetFilesWithBasePath(string path);
|
||||
TrackFile GetFileWithPath(string path);
|
||||
void UpdateMediaInfo(List<TrackFile> trackFiles);
|
||||
}
|
||||
|
||||
|
@ -70,19 +73,57 @@ namespace NzbDrone.Core.MediaFiles
|
|||
|
||||
public void Delete(TrackFile trackFile, DeleteMediaFileReason reason)
|
||||
{
|
||||
trackFile.Path = Path.Combine(trackFile.Artist.Value.Path, trackFile.RelativePath);
|
||||
|
||||
_mediaFileRepository.Delete(trackFile);
|
||||
_eventAggregator.PublishEvent(new TrackFileDeletedEvent(trackFile, reason));
|
||||
// If the trackfile wasn't mapped to a track, don't publish an event
|
||||
if (trackFile.AlbumId > 0)
|
||||
{
|
||||
_eventAggregator.PublishEvent(new TrackFileDeletedEvent(trackFile, reason));
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> FilterExistingFiles(List<string> files, Artist artist)
|
||||
public List<IFileInfo> FilterUnchangedFiles(List<IFileInfo> files, Artist artist, FilterFilesType filter)
|
||||
{
|
||||
var artistFiles = GetFilesByArtist(artist.Id).Select(f => Path.Combine(artist.Path, f.RelativePath)).ToList();
|
||||
_logger.Debug($"Filtering {files.Count} files for unchanged files");
|
||||
|
||||
if (!artistFiles.Any()) return files;
|
||||
var knownFiles = GetFilesWithBasePath(artist.Path);
|
||||
_logger.Trace($"Got {knownFiles.Count} existing files");
|
||||
|
||||
return files.Except(artistFiles, PathEqualityComparer.Instance).ToList();
|
||||
if (!knownFiles.Any()) return files;
|
||||
|
||||
var combined = files
|
||||
.Join(knownFiles,
|
||||
f => f.FullName,
|
||||
af => af.Path,
|
||||
(f, af) => new { DiskFile = f, DbFile = af},
|
||||
PathEqualityComparer.Instance)
|
||||
.ToList();
|
||||
|
||||
List<IFileInfo> unwanted = null;
|
||||
if (filter == FilterFilesType.Known)
|
||||
{
|
||||
unwanted = combined
|
||||
.Where(x => x.DiskFile.Length == x.DbFile.Size &&
|
||||
Math.Abs((x.DiskFile.LastWriteTimeUtc - x.DbFile.Modified).TotalSeconds) <= 1)
|
||||
.Select(x => x.DiskFile)
|
||||
.ToList();
|
||||
_logger.Trace($"{unwanted.Count} unchanged existing files");
|
||||
}
|
||||
else if (filter == FilterFilesType.Matched)
|
||||
{
|
||||
unwanted = combined
|
||||
.Where(x => x.DiskFile.Length == x.DbFile.Size &&
|
||||
Math.Abs((x.DiskFile.LastWriteTimeUtc - x.DbFile.Modified).TotalSeconds) <= 1 &&
|
||||
(x.DbFile.Tracks == null || (x.DbFile.Tracks.IsLoaded && x.DbFile.Tracks.Value.Any())))
|
||||
.Select(x => x.DiskFile)
|
||||
.ToList();
|
||||
_logger.Trace($"{unwanted.Count} unchanged and matched files");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException("Unrecognised value of FilterFilesType filter");
|
||||
}
|
||||
|
||||
return files.Except(unwanted).ToList();
|
||||
}
|
||||
|
||||
public TrackFile Get(int id)
|
||||
|
@ -95,9 +136,14 @@ namespace NzbDrone.Core.MediaFiles
|
|||
return _mediaFileRepository.Get(ids).ToList();
|
||||
}
|
||||
|
||||
public List<TrackFile> GetFilesWithRelativePath(int artistId, string relativePath)
|
||||
public List<TrackFile> GetFilesWithBasePath(string path)
|
||||
{
|
||||
return _mediaFileRepository.GetFilesWithRelativePath(artistId, relativePath);
|
||||
return _mediaFileRepository.GetFilesWithBasePath(path);
|
||||
}
|
||||
|
||||
public TrackFile GetFileWithPath(string path)
|
||||
{
|
||||
return _mediaFileRepository.GetFileWithPath(path);
|
||||
}
|
||||
|
||||
public void HandleAsync(AlbumDeletedEvent message)
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
foreach (var artistFile in artistFiles)
|
||||
{
|
||||
var trackFile = artistFile;
|
||||
var trackFilePath = Path.Combine(artist.Path, trackFile.RelativePath);
|
||||
var trackFilePath = trackFile.Path;
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -49,15 +49,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
_mediaFileService.Delete(artistFile, DeleteMediaFileReason.MissingFromDisk);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tracks.None(e => e.TrackFileId == trackFile.Id))
|
||||
{
|
||||
_logger.Debug("File [{0}] is not assigned to any artist, removing from db", trackFilePath);
|
||||
_mediaFileService.Delete(trackFile, DeleteMediaFileReason.NoLinkedEpisodes);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.Error(ex, "Unable to cleanup TrackFile in DB: {0}", trackFile.Id);
|
||||
|
|
|
@ -84,7 +84,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
{
|
||||
var file = f;
|
||||
var tracksInFile = tracks.Where(e => e.TrackFileId == file.Id).ToList();
|
||||
var trackFilePath = Path.Combine(artist.Path, file.RelativePath);
|
||||
var trackFilePath = file.Path;
|
||||
|
||||
if (!tracksInFile.Any())
|
||||
{
|
||||
|
@ -105,7 +105,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
AlbumId = album.Id,
|
||||
TrackNumbers = tracksInFile.Select(e => e.AbsoluteTrackNumber).ToList(),
|
||||
TrackFileId = file.Id,
|
||||
ExistingPath = file.RelativePath,
|
||||
ExistingPath = artist.Path.GetRelativePath(file.Path),
|
||||
NewPath = artist.Path.GetRelativePath(newPath)
|
||||
};
|
||||
}
|
||||
|
@ -118,7 +118,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
|
||||
foreach (var trackFile in trackFiles)
|
||||
{
|
||||
var trackFilePath = Path.Combine(artist.Path, trackFile.RelativePath);
|
||||
var trackFilePath = trackFile.Path;
|
||||
|
||||
try
|
||||
{
|
||||
|
|
|
@ -13,9 +13,9 @@ namespace NzbDrone.Core.MediaFiles
|
|||
public class TrackFile : ModelBase
|
||||
{
|
||||
// these are model properties
|
||||
public string RelativePath { get; set; }
|
||||
public string Path { get; set; }
|
||||
public long Size { get; set; }
|
||||
public DateTime Modified { get; set; }
|
||||
public DateTime DateAdded { get; set; }
|
||||
public string SceneName { get; set; }
|
||||
public string ReleaseGroup { get; set; }
|
||||
|
@ -31,7 +31,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("[{0}] {1}", Id, RelativePath);
|
||||
return string.Format("[{0}] {1}", Id, Path);
|
||||
}
|
||||
|
||||
public string GetSceneOrFileName()
|
||||
|
@ -41,11 +41,6 @@ namespace NzbDrone.Core.MediaFiles
|
|||
return SceneName;
|
||||
}
|
||||
|
||||
if (RelativePath.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
return System.IO.Path.GetFileName(RelativePath);
|
||||
}
|
||||
|
||||
if (Path.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
return System.IO.Path.GetFileName(Path);
|
||||
|
|
|
@ -66,7 +66,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
var tracks = _trackService.GetTracksByFileId(trackFile.Id);
|
||||
var album = _albumService.GetAlbum(trackFile.AlbumId);
|
||||
var newFileName = _buildFileNames.BuildTrackFileName(tracks, artist, album, trackFile);
|
||||
var filePath = _buildFileNames.BuildTrackFilePath(artist, album, newFileName, Path.GetExtension(trackFile.RelativePath));
|
||||
var filePath = _buildFileNames.BuildTrackFilePath(artist, album, newFileName, Path.GetExtension(trackFile.Path));
|
||||
|
||||
EnsureTrackFolder(trackFile, artist, album, filePath);
|
||||
|
||||
|
@ -112,7 +112,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
Ensure.That(artist, () => artist).IsNotNull();
|
||||
Ensure.That(destinationFilePath, () => destinationFilePath).IsValidPath();
|
||||
|
||||
var trackFilePath = trackFile.Path ?? Path.Combine(artist.Path, trackFile.RelativePath);
|
||||
var trackFilePath = trackFile.Path;
|
||||
|
||||
if (!_diskProvider.FileExists(trackFilePath))
|
||||
{
|
||||
|
@ -126,7 +126,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
|
||||
_diskTransferService.TransferFile(trackFilePath, destinationFilePath, mode);
|
||||
|
||||
trackFile.RelativePath = artist.Path.GetRelativePath(destinationFilePath);
|
||||
trackFile.Path = destinationFilePath;
|
||||
|
||||
_updateTrackFileService.ChangeFileDateForFile(trackFile, artist, tracks);
|
||||
|
||||
|
|
|
@ -177,9 +177,12 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Identification
|
|||
{
|
||||
var localTracks = trackfiles.Select(x => new LocalTrack {
|
||||
Path = x.Path,
|
||||
Size = x.Size,
|
||||
Modified = x.Modified,
|
||||
FileTrackInfo = _audioTagService.ReadTags(x.Path),
|
||||
ExistingFile = true,
|
||||
AdditionalFile = true
|
||||
AdditionalFile = true,
|
||||
Quality = x.Quality
|
||||
})
|
||||
.ToList();
|
||||
|
||||
|
@ -335,15 +338,6 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Identification
|
|||
.Distinct()
|
||||
.ToDictionary(id => id, id => includeExisting ? _mediaFileService.GetFilesByAlbum(id) : new List<TrackFile>());
|
||||
|
||||
// populate the path. Artist will have been returned by mediaFileService
|
||||
foreach (var trackfiles in albumTracks.Values)
|
||||
{
|
||||
foreach (var trackfile in trackfiles)
|
||||
{
|
||||
trackfile.Path = Path.Combine(trackfile.Artist.Value.Path, trackfile.RelativePath);
|
||||
}
|
||||
}
|
||||
|
||||
return releases.Select(x => new CandidateAlbumRelease {
|
||||
AlbumRelease = x,
|
||||
ExistingTracks = albumTracks[x.AlbumId]
|
||||
|
|
|
@ -92,12 +92,11 @@ namespace NzbDrone.Core.MediaFiles.TrackImport
|
|||
|
||||
foreach (var previousFile in previousFiles)
|
||||
{
|
||||
var trackFilePath = Path.Combine(artist.Path, previousFile.RelativePath);
|
||||
var subfolder = rootFolder.GetRelativePath(_diskProvider.GetParentFolder(trackFilePath));
|
||||
if (_diskProvider.FileExists(trackFilePath))
|
||||
var subfolder = rootFolder.GetRelativePath(_diskProvider.GetParentFolder(previousFile.Path));
|
||||
if (_diskProvider.FileExists(previousFile.Path))
|
||||
{
|
||||
_logger.Debug("Removing existing track file: {0}", previousFile);
|
||||
_recycleBinProvider.DeleteFile(trackFilePath, subfolder);
|
||||
_recycleBinProvider.DeleteFile(previousFile.Path, subfolder);
|
||||
}
|
||||
_mediaFileService.Delete(previousFile, DeleteMediaFileReason.Upgrade);
|
||||
}
|
||||
|
@ -154,7 +153,8 @@ namespace NzbDrone.Core.MediaFiles.TrackImport
|
|||
|
||||
var trackFile = new TrackFile {
|
||||
Path = localTrack.Path.CleanFilePath(),
|
||||
Size = _diskProvider.GetFileSize(localTrack.Path),
|
||||
Size = localTrack.Size,
|
||||
Modified = localTrack.Modified,
|
||||
DateAdded = DateTime.UtcNow,
|
||||
ReleaseGroup = localTrack.ReleaseGroup,
|
||||
Quality = localTrack.Quality,
|
||||
|
@ -190,12 +190,10 @@ namespace NzbDrone.Core.MediaFiles.TrackImport
|
|||
}
|
||||
else
|
||||
{
|
||||
trackFile.RelativePath = localTrack.Artist.Path.GetRelativePath(trackFile.Path);
|
||||
|
||||
// Delete existing files from the DB mapped to this path
|
||||
var previousFiles = _mediaFileService.GetFilesWithRelativePath(localTrack.Artist.Id, trackFile.RelativePath);
|
||||
var previousFile = _mediaFileService.GetFileWithPath(trackFile.Path);
|
||||
|
||||
foreach (var previousFile in previousFiles)
|
||||
if (previousFile != null)
|
||||
{
|
||||
_mediaFileService.Delete(previousFile, DeleteMediaFileReason.ManualOverride);
|
||||
}
|
||||
|
|
|
@ -11,14 +11,15 @@ using NzbDrone.Core.Messaging.Events;
|
|||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.MediaFiles.TrackImport.Aggregation;
|
||||
using NzbDrone.Core.MediaFiles.TrackImport.Identification;
|
||||
using System.IO.Abstractions;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.TrackImport
|
||||
{
|
||||
public interface IMakeImportDecision
|
||||
{
|
||||
List<ImportDecision<LocalTrack>> GetImportDecisions(List<string> musicFiles, Artist artist, bool includeExisting);
|
||||
List<ImportDecision<LocalTrack>> GetImportDecisions(List<string> musicFiles, Artist artist, ParsedTrackInfo folderInfo);
|
||||
List<ImportDecision<LocalTrack>> GetImportDecisions(List<string> musicFiles, Artist artist, Album album, AlbumRelease albumRelease, DownloadClientItem downloadClientItem, ParsedTrackInfo folderInfo, bool filterExistingFiles, bool newDownload, bool singleRelease, bool includeExisting);
|
||||
List<ImportDecision<LocalTrack>> GetImportDecisions(List<IFileInfo> musicFiles, Artist artist, FilterFilesType filter, bool includeExisting);
|
||||
List<ImportDecision<LocalTrack>> GetImportDecisions(List<IFileInfo> musicFiles, Artist artist, ParsedTrackInfo folderInfo);
|
||||
List<ImportDecision<LocalTrack>> GetImportDecisions(List<IFileInfo> musicFiles, Artist artist, Album album, AlbumRelease albumRelease, DownloadClientItem downloadClientItem, ParsedTrackInfo folderInfo, FilterFilesType filter, bool newDownload, bool singleRelease, bool includeExisting);
|
||||
}
|
||||
|
||||
public class ImportDecisionMaker : IMakeImportDecision
|
||||
|
@ -60,25 +61,33 @@ namespace NzbDrone.Core.MediaFiles.TrackImport
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
public List<ImportDecision<LocalTrack>> GetImportDecisions(List<string> musicFiles, Artist artist, bool includeExisting)
|
||||
public List<ImportDecision<LocalTrack>> GetImportDecisions(List<IFileInfo> musicFiles, Artist artist, FilterFilesType filter, bool includeExisting)
|
||||
{
|
||||
return GetImportDecisions(musicFiles, artist, null, null, null, null, false, false, false, true);
|
||||
return GetImportDecisions(musicFiles, artist, null, null, null, null, filter, false, false, true);
|
||||
}
|
||||
|
||||
public List<ImportDecision<LocalTrack>> GetImportDecisions(List<string> musicFiles, Artist artist, ParsedTrackInfo folderInfo)
|
||||
public List<ImportDecision<LocalTrack>> GetImportDecisions(List<IFileInfo> musicFiles, Artist artist, ParsedTrackInfo folderInfo)
|
||||
{
|
||||
return GetImportDecisions(musicFiles, artist, null, null, null, folderInfo, false, true, false, false);
|
||||
return GetImportDecisions(musicFiles, artist, null, null, null, folderInfo, FilterFilesType.None, true, false, false);
|
||||
}
|
||||
|
||||
public List<ImportDecision<LocalTrack>> GetImportDecisions(List<string> musicFiles, Artist artist, Album album, AlbumRelease albumRelease, DownloadClientItem downloadClientItem, ParsedTrackInfo folderInfo, bool filterExistingFiles, bool newDownload, bool singleRelease, bool includeExisting)
|
||||
public List<ImportDecision<LocalTrack>> GetImportDecisions(List<IFileInfo> musicFiles, Artist artist, Album album, AlbumRelease albumRelease, DownloadClientItem downloadClientItem, ParsedTrackInfo folderInfo, FilterFilesType filter, bool newDownload, bool singleRelease, bool includeExisting)
|
||||
{
|
||||
var watch = new System.Diagnostics.Stopwatch();
|
||||
watch.Start();
|
||||
|
||||
var files = filterExistingFiles && (artist != null) ? _mediaFileService.FilterExistingFiles(musicFiles, artist) : musicFiles;
|
||||
var files = filter != FilterFilesType.None && (artist != null) ? _mediaFileService.FilterUnchangedFiles(musicFiles, artist, filter) : musicFiles;
|
||||
|
||||
var localTracks = new List<LocalTrack>();
|
||||
var decisions = new List<ImportDecision<LocalTrack>>();
|
||||
|
||||
_logger.Debug("Analyzing {0}/{1} files.", files.Count, musicFiles.Count);
|
||||
|
||||
if (!files.Any())
|
||||
{
|
||||
return decisions;
|
||||
}
|
||||
|
||||
ParsedAlbumInfo downloadClientItemInfo = null;
|
||||
|
||||
if (downloadClientItem != null)
|
||||
|
@ -86,9 +95,6 @@ namespace NzbDrone.Core.MediaFiles.TrackImport
|
|||
downloadClientItemInfo = Parser.Parser.ParseAlbumTitle(downloadClientItem.Title);
|
||||
}
|
||||
|
||||
var localTracks = new List<LocalTrack>();
|
||||
var decisions = new List<ImportDecision<LocalTrack>>();
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
var localTrack = new LocalTrack
|
||||
|
@ -97,8 +103,10 @@ namespace NzbDrone.Core.MediaFiles.TrackImport
|
|||
Album = album,
|
||||
DownloadClientAlbumInfo = downloadClientItemInfo,
|
||||
FolderTrackInfo = folderInfo,
|
||||
Path = file,
|
||||
FileTrackInfo = _audioTagService.ReadTags(file),
|
||||
Path = file.FullName,
|
||||
Size = file.Length,
|
||||
Modified = file.LastWriteTimeUtc,
|
||||
FileTrackInfo = _audioTagService.ReadTags(file.FullName),
|
||||
ExistingFile = !newDownload,
|
||||
AdditionalFile = false
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
|
@ -20,7 +21,7 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Manual
|
|||
{
|
||||
public interface IManualImportService
|
||||
{
|
||||
List<ManualImportItem> GetMediaFiles(string path, string downloadId, bool filterExistingFiles, bool replaceExistingFiles);
|
||||
List<ManualImportItem> GetMediaFiles(string path, string downloadId, FilterFilesType filter, bool replaceExistingFiles);
|
||||
List<ManualImportItem> UpdateItems(List<ManualImportItem> item);
|
||||
}
|
||||
|
||||
|
@ -72,7 +73,7 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Manual
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
public List<ManualImportItem> GetMediaFiles(string path, string downloadId, bool filterExistingFiles, bool replaceExistingFiles)
|
||||
public List<ManualImportItem> GetMediaFiles(string path, string downloadId, FilterFilesType filter, bool replaceExistingFiles)
|
||||
{
|
||||
if (downloadId.IsNotNullOrWhiteSpace())
|
||||
{
|
||||
|
@ -93,16 +94,16 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Manual
|
|||
return new List<ManualImportItem>();
|
||||
}
|
||||
|
||||
var decision = _importDecisionMaker.GetImportDecisions(new List<string> { path }, null, null, null, null, null, false, true, false, !replaceExistingFiles);
|
||||
var decision = _importDecisionMaker.GetImportDecisions(new List<IFileInfo> { _diskProvider.GetFileInfo(path) }, null, null, null, null, null, FilterFilesType.None, true, false, !replaceExistingFiles);
|
||||
var result = MapItem(decision.First(), Path.GetDirectoryName(path), downloadId, replaceExistingFiles, false);
|
||||
|
||||
return new List<ManualImportItem> { result };
|
||||
}
|
||||
|
||||
return ProcessFolder(path, downloadId, filterExistingFiles, replaceExistingFiles);
|
||||
return ProcessFolder(path, downloadId, filter, replaceExistingFiles);
|
||||
}
|
||||
|
||||
private List<ManualImportItem> ProcessFolder(string folder, string downloadId, bool filterExistingFiles, bool replaceExistingFiles)
|
||||
private List<ManualImportItem> ProcessFolder(string folder, string downloadId, FilterFilesType filter, bool replaceExistingFiles)
|
||||
{
|
||||
var directoryInfo = new DirectoryInfo(folder);
|
||||
var artist = _parsingService.GetArtist(directoryInfo.Name);
|
||||
|
@ -115,11 +116,11 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Manual
|
|||
|
||||
var folderInfo = Parser.Parser.ParseMusicTitle(directoryInfo.Name);
|
||||
var artistFiles = _diskScanService.GetAudioFiles(folder).ToList();
|
||||
var decisions = _importDecisionMaker.GetImportDecisions(artistFiles, artist, null, null, null, folderInfo, filterExistingFiles, true, false, !replaceExistingFiles);
|
||||
var decisions = _importDecisionMaker.GetImportDecisions(artistFiles, artist, null, null, null, folderInfo, filter, true, false, !replaceExistingFiles);
|
||||
|
||||
// paths will be different for new and old files which is why we need to map separately
|
||||
var newFiles = artistFiles.Join(decisions,
|
||||
f => f,
|
||||
f => f.FullName,
|
||||
d => d.Item.Path,
|
||||
(f, d) => new { File = f, Decision = d },
|
||||
PathEqualityComparer.Instance);
|
||||
|
@ -145,7 +146,7 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Manual
|
|||
|
||||
var disableReleaseSwitching = group.First().DisableReleaseSwitching;
|
||||
|
||||
var decisions = _importDecisionMaker.GetImportDecisions(group.Select(x => x.Path).ToList(), group.First().Artist, group.First().Album, group.First().Release, null, null, false, true, true, !replaceExistingFiles);
|
||||
var decisions = _importDecisionMaker.GetImportDecisions(group.Select(x => _diskProvider.GetFileInfo(x.Path)).ToList(), group.First().Artist, group.First().Album, group.First().Release, null, null, FilterFilesType.None, true, true, !replaceExistingFiles);
|
||||
|
||||
var existingItems = group.Join(decisions,
|
||||
i => i.Path,
|
||||
|
@ -260,7 +261,6 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Manual
|
|||
ExistingFile = artist.Path.IsParentPath(file.Path),
|
||||
Tracks = tracks,
|
||||
FileTrackInfo = fileTrackInfo,
|
||||
MediaInfo = fileTrackInfo.MediaInfo,
|
||||
Path = file.Path,
|
||||
Quality = file.Quality,
|
||||
Language = file.Language,
|
||||
|
@ -305,7 +305,7 @@ namespace NzbDrone.Core.MediaFiles.TrackImport.Manual
|
|||
if (_diskProvider.FolderExists(trackedDownload.DownloadItem.OutputPath.FullPath))
|
||||
{
|
||||
if (_downloadedTracksImportService.ShouldDeleteFolder(
|
||||
new DirectoryInfo(trackedDownload.DownloadItem.OutputPath.FullPath),
|
||||
_diskProvider.GetDirectoryInfo(trackedDownload.DownloadItem.OutputPath.FullPath),
|
||||
trackedDownload.RemoteAlbum.Artist) && trackedDownload.DownloadItem.CanMoveFiles)
|
||||
{
|
||||
_diskProvider.DeleteFolder(trackedDownload.DownloadItem.OutputPath.FullPath, true);
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
|
||||
private bool ChangeFileDate(TrackFile trackFile, Artist artist, List<Track> tracks)
|
||||
{
|
||||
var trackFilePath = Path.Combine(artist.Path, trackFile.RelativePath);
|
||||
var trackFilePath = trackFile.Path;
|
||||
|
||||
switch (_configService.FileDate)
|
||||
{
|
||||
|
|
|
@ -57,7 +57,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
foreach (var existingFile in existingFiles)
|
||||
{
|
||||
var file = existingFile.First();
|
||||
var trackFilePath = Path.Combine(localTrack.Artist.Path, file.RelativePath);
|
||||
var trackFilePath = file.Path;
|
||||
var subfolder = rootFolder.GetRelativePath(_diskProvider.GetParentFolder(trackFilePath));
|
||||
|
||||
if (_diskProvider.FileExists(trackFilePath))
|
||||
|
|
|
@ -17,8 +17,8 @@ namespace NzbDrone.Core.Music
|
|||
{
|
||||
public interface IRefreshAlbumService
|
||||
{
|
||||
void RefreshAlbumInfo(Album album, bool forceUpdateFileTags);
|
||||
void RefreshAlbumInfo(List<Album> albums, bool forceAlbumRefresh, bool forceUpdateFileTags);
|
||||
bool RefreshAlbumInfo(Album album, bool forceUpdateFileTags);
|
||||
bool RefreshAlbumInfo(List<Album> albums, bool forceAlbumRefresh, bool forceUpdateFileTags);
|
||||
}
|
||||
|
||||
public class RefreshAlbumService : IRefreshAlbumService, IExecute<RefreshAlbumCommand>
|
||||
|
@ -57,20 +57,23 @@ namespace NzbDrone.Core.Music
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
public void RefreshAlbumInfo(List<Album> albums, bool forceAlbumRefresh, bool forceUpdateFileTags)
|
||||
public bool RefreshAlbumInfo(List<Album> albums, bool forceAlbumRefresh, bool forceUpdateFileTags)
|
||||
{
|
||||
bool updated = false;
|
||||
foreach (var album in albums)
|
||||
{
|
||||
if (forceAlbumRefresh || _checkIfAlbumShouldBeRefreshed.ShouldRefresh(album))
|
||||
{
|
||||
RefreshAlbumInfo(album, forceUpdateFileTags);
|
||||
updated |= RefreshAlbumInfo(album, forceUpdateFileTags);
|
||||
}
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
public void RefreshAlbumInfo(Album album, bool forceUpdateFileTags)
|
||||
public bool RefreshAlbumInfo(Album album, bool forceUpdateFileTags)
|
||||
{
|
||||
_logger.ProgressInfo("Updating Info for {0}", album.Title);
|
||||
bool updated = false;
|
||||
|
||||
Tuple<string, Album, List<ArtistMetadata>> tuple;
|
||||
|
||||
|
@ -81,14 +84,14 @@ namespace NzbDrone.Core.Music
|
|||
catch (AlbumNotFoundException)
|
||||
{
|
||||
_logger.Error($"{album} was not found, it may have been removed from Metadata sources.");
|
||||
return;
|
||||
return updated;
|
||||
}
|
||||
|
||||
if (tuple.Item2.AlbumReleases.Value.Count == 0)
|
||||
{
|
||||
_logger.Debug($"{album} has no valid releases, removing.");
|
||||
_albumService.DeleteMany(new List<Album> { album });
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
var remoteMetadata = tuple.Item3.DistinctBy(x => x.ForeignArtistId).ToList();
|
||||
|
@ -124,6 +127,7 @@ namespace NzbDrone.Core.Music
|
|||
_artistMetadataRepository.InsertMany(addMetadataList);
|
||||
|
||||
forceUpdateFileTags |= updateMetadataList.Any();
|
||||
updated |= updateMetadataList.Any() || addMetadataList.Any();
|
||||
|
||||
var albumInfo = tuple.Item2;
|
||||
|
||||
|
@ -137,6 +141,7 @@ namespace NzbDrone.Core.Music
|
|||
|
||||
// the only thing written to tags from the album object is the title
|
||||
forceUpdateFileTags |= album.Title != (albumInfo.Title ?? "Unknown");
|
||||
updated |= forceUpdateFileTags;
|
||||
|
||||
album.LastInfoSync = DateTime.UtcNow;
|
||||
album.CleanTitle = albumInfo.CleanTitle;
|
||||
|
@ -229,11 +234,14 @@ namespace NzbDrone.Core.Music
|
|||
|
||||
// if we have updated a monitored release, refresh all file tags
|
||||
forceUpdateFileTags |= updateReleaseList.Any(x => x.Monitored);
|
||||
updated |= existingReleases.Any() || updateReleaseList.Any() || newReleaseList.Any();
|
||||
|
||||
_refreshTrackService.RefreshTrackInfo(album, forceUpdateFileTags);
|
||||
updated |= _refreshTrackService.RefreshTrackInfo(album, forceUpdateFileTags);
|
||||
_albumService.UpdateMany(new List<Album>{album});
|
||||
|
||||
_logger.Debug("Finished album refresh for {0}", album.Title);
|
||||
|
||||
return updated;
|
||||
}
|
||||
|
||||
public void Execute(RefreshAlbumCommand message)
|
||||
|
@ -242,10 +250,12 @@ namespace NzbDrone.Core.Music
|
|||
{
|
||||
var album = _albumService.GetAlbum(message.AlbumId.Value);
|
||||
var artist = _artistService.GetArtistByMetadataId(album.ArtistMetadataId);
|
||||
RefreshAlbumInfo(album, false);
|
||||
_eventAggregator.PublishEvent(new ArtistUpdatedEvent(artist));
|
||||
var updated = RefreshAlbumInfo(album, false);
|
||||
if (updated)
|
||||
{
|
||||
_eventAggregator.PublishEvent(new ArtistUpdatedEvent(artist));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,9 +63,10 @@ namespace NzbDrone.Core.Music
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
private void RefreshArtistInfo(Artist artist, bool forceAlbumRefresh)
|
||||
private bool RefreshArtistInfo(Artist artist, bool forceAlbumRefresh)
|
||||
{
|
||||
_logger.ProgressInfo("Updating Info for {0}", artist.Name);
|
||||
bool updated = false;
|
||||
|
||||
Artist artistInfo;
|
||||
|
||||
|
@ -76,10 +77,11 @@ namespace NzbDrone.Core.Music
|
|||
catch (ArtistNotFoundException)
|
||||
{
|
||||
_logger.Error($"Artist {artist} was not found, it may have been removed from Metadata sources.");
|
||||
return;
|
||||
return updated;
|
||||
}
|
||||
|
||||
var forceUpdateFileTags = artist.Name != artistInfo.Name;
|
||||
updated |= forceUpdateFileTags;
|
||||
|
||||
if (artist.Metadata.Value.ForeignArtistId != artistInfo.Metadata.Value.ForeignArtistId)
|
||||
{
|
||||
|
@ -96,6 +98,7 @@ namespace NzbDrone.Core.Music
|
|||
|
||||
artist.Metadata.Value.ForeignArtistId = artistInfo.Metadata.Value.ForeignArtistId;
|
||||
forceUpdateFileTags = true;
|
||||
updated = true;
|
||||
}
|
||||
|
||||
artist.Metadata.Value.ApplyChanges(artistInfo.Metadata.Value);
|
||||
|
@ -153,14 +156,23 @@ namespace NzbDrone.Core.Music
|
|||
newAlbumsList = UpdateAlbums(artist, newAlbumsList);
|
||||
_addAlbumService.AddAlbums(newAlbumsList);
|
||||
|
||||
_refreshAlbumService.RefreshAlbumInfo(updateAlbumsList, forceAlbumRefresh, forceUpdateFileTags);
|
||||
updated |= existingAlbums.Any() || newAlbumsList.Any();
|
||||
|
||||
updated |= _refreshAlbumService.RefreshAlbumInfo(updateAlbumsList, forceAlbumRefresh, forceUpdateFileTags);
|
||||
|
||||
// Do this last so artist only marked as refreshed if refresh of tracks / albums completed successfully
|
||||
_artistService.UpdateArtist(artist);
|
||||
|
||||
_eventAggregator.PublishEvent(new AlbumInfoRefreshedEvent(artist, newAlbumsList, updateAlbumsList));
|
||||
_eventAggregator.PublishEvent(new ArtistUpdatedEvent(artist));
|
||||
|
||||
if (updated)
|
||||
{
|
||||
_eventAggregator.PublishEvent(new ArtistUpdatedEvent(artist));
|
||||
}
|
||||
|
||||
_logger.Debug("Finished artist refresh for {0}", artist.Name);
|
||||
|
||||
return updated;
|
||||
}
|
||||
|
||||
private List<Album> UpdateAlbums(Artist artist, List<Album> albumsToUpdate)
|
||||
|
@ -174,26 +186,26 @@ namespace NzbDrone.Core.Music
|
|||
return albumsToUpdate;
|
||||
}
|
||||
|
||||
private void RescanArtist(Artist artist, bool isNew, CommandTrigger trigger)
|
||||
private void RescanArtist(Artist artist, bool isNew, CommandTrigger trigger, bool infoUpdated)
|
||||
{
|
||||
var rescanAfterRefresh = _configService.RescanAfterRefresh;
|
||||
var shouldRescan = true;
|
||||
|
||||
if (isNew)
|
||||
{
|
||||
_logger.Trace("Forcing refresh of {0}. Reason: New artist", artist);
|
||||
_logger.Trace("Forcing rescan of {0}. Reason: New artist", artist);
|
||||
shouldRescan = true;
|
||||
}
|
||||
|
||||
else if (rescanAfterRefresh == RescanAfterRefreshType.Never)
|
||||
{
|
||||
_logger.Trace("Skipping refresh of {0}. Reason: never recan after refresh", artist);
|
||||
_logger.Trace("Skipping rescan of {0}. Reason: never recan after refresh", artist);
|
||||
shouldRescan = false;
|
||||
}
|
||||
|
||||
else if (rescanAfterRefresh == RescanAfterRefreshType.AfterManual && trigger != CommandTrigger.Manual)
|
||||
{
|
||||
_logger.Trace("Skipping refresh of {0}. Reason: not after automatic scans", artist);
|
||||
_logger.Trace("Skipping rescan of {0}. Reason: not after automatic scans", artist);
|
||||
shouldRescan = false;
|
||||
}
|
||||
|
||||
|
@ -204,7 +216,10 @@ namespace NzbDrone.Core.Music
|
|||
|
||||
try
|
||||
{
|
||||
_diskScanService.Scan(artist);
|
||||
// If some metadata has been updated then rescan unmatched files.
|
||||
// Otherwise only scan files that haven't been seen before.
|
||||
var filter = infoUpdated ? FilterFilesType.Matched : FilterFilesType.Known;
|
||||
_diskScanService.Scan(artist, filter);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -221,16 +236,16 @@ namespace NzbDrone.Core.Music
|
|||
if (message.ArtistId.HasValue)
|
||||
{
|
||||
var artist = _artistService.GetArtist(message.ArtistId.Value);
|
||||
|
||||
bool updated = false;
|
||||
try
|
||||
{
|
||||
RefreshArtistInfo(artist, true);
|
||||
RescanArtist(artist, isNew, trigger);
|
||||
updated = RefreshArtistInfo(artist, true);
|
||||
RescanArtist(artist, isNew, trigger, updated);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(e, "Couldn't refresh info for {0}", artist);
|
||||
RescanArtist(artist, isNew, trigger);
|
||||
RescanArtist(artist, isNew, trigger, updated);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
@ -244,22 +259,23 @@ namespace NzbDrone.Core.Music
|
|||
|
||||
if (manualTrigger || _checkIfArtistShouldBeRefreshed.ShouldRefresh(artist))
|
||||
{
|
||||
bool updated = false;
|
||||
try
|
||||
{
|
||||
RefreshArtistInfo(artist, manualTrigger);
|
||||
updated = RefreshArtistInfo(artist, manualTrigger);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(e, "Couldn't refresh info for {0}", artist);
|
||||
}
|
||||
|
||||
RescanArtist(artist, false, trigger);
|
||||
RescanArtist(artist, false, trigger, updated);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
_logger.Info("Skipping refresh of artist: {0}", artist.Name);
|
||||
RescanArtist(artist, false, trigger);
|
||||
RescanArtist(artist, false, trigger, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace NzbDrone.Core.Music
|
|||
{
|
||||
public interface IRefreshTrackService
|
||||
{
|
||||
void RefreshTrackInfo(Album rg, bool forceUpdateFileTags);
|
||||
bool RefreshTrackInfo(Album rg, bool forceUpdateFileTags);
|
||||
}
|
||||
|
||||
public class RefreshTrackService : IRefreshTrackService
|
||||
|
@ -37,11 +37,12 @@ namespace NzbDrone.Core.Music
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
public void RefreshTrackInfo(Album album, bool forceUpdateFileTags)
|
||||
public bool RefreshTrackInfo(Album album, bool forceUpdateFileTags)
|
||||
{
|
||||
_logger.Info("Starting track info refresh for: {0}", album);
|
||||
var successCount = 0;
|
||||
var failCount = 0;
|
||||
bool updated = false;
|
||||
|
||||
foreach (var release in album.AlbumReleases.Value)
|
||||
{
|
||||
|
@ -115,6 +116,8 @@ namespace NzbDrone.Core.Music
|
|||
_trackService.DeleteMany(existingTracks);
|
||||
_trackService.UpdateMany(updateList);
|
||||
_trackService.InsertMany(newList);
|
||||
|
||||
updated |= existingTracks.Any() || updateList.Any() || newList.Any();
|
||||
}
|
||||
|
||||
if (failCount != 0)
|
||||
|
@ -126,6 +129,8 @@ namespace NzbDrone.Core.Music
|
|||
{
|
||||
_logger.Info("Finished track refresh for album: {0}.", album);
|
||||
}
|
||||
|
||||
return updated;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,14 +79,12 @@ namespace NzbDrone.Core.Notifications.CustomScript
|
|||
|
||||
if (message.TrackFiles.Any())
|
||||
{
|
||||
environmentVariables.Add("Lidarr_AddedTrackRelativePaths", string.Join("|", message.TrackFiles.Select(e => e.RelativePath)));
|
||||
environmentVariables.Add("Lidarr_AddedTrackPaths", string.Join("|", message.TrackFiles.Select(e => Path.Combine(artist.Path, e.RelativePath))));
|
||||
environmentVariables.Add("Lidarr_AddedTrackPaths", string.Join("|", message.TrackFiles.Select(e => e.Path)));
|
||||
}
|
||||
|
||||
if (message.OldFiles.Any())
|
||||
{
|
||||
environmentVariables.Add("Lidarr_DeletedRelativePaths", string.Join("|", message.OldFiles.Select(e => e.RelativePath)));
|
||||
environmentVariables.Add("Lidarr_DeletedPaths", string.Join("|", message.OldFiles.Select(e => Path.Combine(artist.Path, e.RelativePath))));
|
||||
environmentVariables.Add("Lidarr_DeletedPaths", string.Join("|", message.OldFiles.Select(e => e.Path)));
|
||||
}
|
||||
|
||||
ExecuteScript(environmentVariables);
|
||||
|
@ -127,8 +125,7 @@ namespace NzbDrone.Core.Notifications.CustomScript
|
|||
environmentVariables.Add("Lidarr_Album_ReleaseDate", album.ReleaseDate.ToString());
|
||||
environmentVariables.Add("Lidarr_TrackFile_Id", trackFile.Id.ToString());
|
||||
environmentVariables.Add("Lidarr_TrackFile_TrackCount", trackFile.Tracks.Value.Count.ToString());
|
||||
environmentVariables.Add("Lidarr_TrackFile_RelativePath", trackFile.RelativePath);
|
||||
environmentVariables.Add("Lidarr_TrackFile_Path", Path.Combine(artist.Path, trackFile.RelativePath));
|
||||
environmentVariables.Add("Lidarr_TrackFile_Path", trackFile.Path);
|
||||
environmentVariables.Add("Lidarr_TrackFile_TrackNumbers", string.Join(",", trackFile.Tracks.Value.Select(e => e.TrackNumber)));
|
||||
environmentVariables.Add("Lidarr_TrackFile_TrackTitles", string.Join("|", trackFile.Tracks.Value.Select(e => e.Title)));
|
||||
environmentVariables.Add("Lidarr_TrackFile_Quality", trackFile.Quality.Quality.Name);
|
||||
|
|
|
@ -74,7 +74,7 @@ namespace NzbDrone.Core.Notifications
|
|||
private string GetTrackRetagMessage(Artist artist, TrackFile trackFile, Dictionary<string, Tuple<string, string>> diff)
|
||||
{
|
||||
return string.Format("{0}:\n{1}",
|
||||
Path.Combine(artist.Path, trackFile.RelativePath),
|
||||
trackFile.Path,
|
||||
string.Join("\n", diff.Select(x => $"{x.Key}: {FormatMissing(x.Value.Item1)} → {FormatMissing(x.Value.Item2)}")));
|
||||
}
|
||||
|
||||
|
|
|
@ -26,14 +26,14 @@ namespace NzbDrone.Core.Notifications.Synology
|
|||
{
|
||||
foreach (var oldFile in message.OldFiles)
|
||||
{
|
||||
var fullPath = Path.Combine(message.Artist.Path, oldFile.RelativePath);
|
||||
var fullPath = oldFile.Path;
|
||||
|
||||
_indexerProxy.DeleteFile(fullPath);
|
||||
}
|
||||
|
||||
foreach (var newFile in message.TrackFiles)
|
||||
{
|
||||
var fullPath = Path.Combine(message.Artist.Path, newFile.RelativePath);
|
||||
var fullPath = newFile.Path;
|
||||
|
||||
_indexerProxy.AddFile(fullPath);
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ namespace NzbDrone.Core.Notifications.Webhook
|
|||
public WebhookTrackFile(TrackFile trackFile)
|
||||
{
|
||||
Id = trackFile.Id;
|
||||
RelativePath = trackFile.RelativePath;
|
||||
Path = trackFile.Path;
|
||||
Quality = trackFile.Quality.Quality.Name;
|
||||
QualityVersion = trackFile.Quality.Revision.Version;
|
||||
|
@ -18,7 +17,6 @@ namespace NzbDrone.Core.Notifications.Webhook
|
|||
}
|
||||
|
||||
public int Id { get; set; }
|
||||
public string RelativePath { get; set; }
|
||||
public string Path { get; set; }
|
||||
public string Quality { get; set; }
|
||||
public int QualityVersion { get; set; }
|
||||
|
|
|
@ -92,6 +92,9 @@
|
|||
<Reference Include="RestSharp, Version=105.2.3.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\RestSharp.105.2.3\lib\net46\RestSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.Abstractions, Version=4.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IO.Abstractions.4.0.11\lib\net40\System.IO.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data" />
|
||||
|
@ -204,6 +207,7 @@
|
|||
<Compile Include="Datastore\Migration\025_rename_release_profiles.cs" />
|
||||
<Compile Include="Datastore\Migration\026_rename_quality_profiles_add_upgrade_allowed.cs" />
|
||||
<Compile Include="Datastore\Migration\028_clean_artistmetadata_table.cs" />
|
||||
<Compile Include="Datastore\Migration\030_add_mediafilerepository_mtime.cs" />
|
||||
<Compile Include="Datastore\Migration\Framework\MigrationContext.cs" />
|
||||
<Compile Include="Datastore\Migration\Framework\MigrationController.cs" />
|
||||
<Compile Include="Datastore\Migration\Framework\MigrationDbFactory.cs" />
|
||||
|
@ -805,6 +809,7 @@
|
|||
<Compile Include="MediaFiles\Events\TrackFileDeletedEvent.cs" />
|
||||
<Compile Include="MediaFiles\Events\TrackImportedEvent.cs" />
|
||||
<Compile Include="MediaFiles\FileDateType.cs" />
|
||||
<Compile Include="MediaFiles\FilterFilesType.cs" />
|
||||
<Compile Include="MediaFiles\MediaFileAttributeService.cs" />
|
||||
<Compile Include="MediaFiles\MediaFileExtensions.cs" />
|
||||
<Compile Include="MediaFiles\MediaFileRepository.cs" />
|
||||
|
|
|
@ -549,12 +549,7 @@ namespace NzbDrone.Core.Organizer
|
|||
|
||||
private string GetOriginalFileName(TrackFile trackFile)
|
||||
{
|
||||
if (trackFile.RelativePath.IsNullOrWhiteSpace())
|
||||
{
|
||||
return Path.GetFileNameWithoutExtension(trackFile.Path);
|
||||
}
|
||||
|
||||
return Path.GetFileNameWithoutExtension(trackFile.RelativePath);
|
||||
return Path.GetFileNameWithoutExtension(trackFile.Path);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ namespace NzbDrone.Core.Organizer
|
|||
_singleTrackFile = new TrackFile
|
||||
{
|
||||
Quality = new QualityModel(Quality.MP3_256, new Revision(2)),
|
||||
RelativePath = "Artist.Name.Album.Name.TrackNum.Track.Title.MP3256.mp3",
|
||||
Path = "/music/Artist.Name.Album.Name.TrackNum.Track.Title.MP3256.mp3",
|
||||
SceneName = "Artist.Name.Album.Name.TrackNum.Track.Title.MP3256",
|
||||
ReleaseGroup = "RlsGrp",
|
||||
MediaInfo = mediaInfo
|
||||
|
|
|
@ -3,6 +3,7 @@ using NzbDrone.Core.Qualities;
|
|||
using System.Collections.Generic;
|
||||
using NzbDrone.Core.Languages;
|
||||
using NzbDrone.Core.MediaFiles.TrackImport.Identification;
|
||||
using System;
|
||||
|
||||
namespace NzbDrone.Core.Parser.Model
|
||||
{
|
||||
|
@ -15,6 +16,7 @@ namespace NzbDrone.Core.Parser.Model
|
|||
|
||||
public string Path { get; set; }
|
||||
public long Size { get; set; }
|
||||
public DateTime Modified { get; set; }
|
||||
public ParsedTrackInfo FileTrackInfo { get; set; }
|
||||
public ParsedTrackInfo FolderTrackInfo { get; set; }
|
||||
public ParsedAlbumInfo DownloadClientAlbumInfo { get; set; }
|
||||
|
@ -26,7 +28,6 @@ namespace NzbDrone.Core.Parser.Model
|
|||
public Distance Distance { get; set; }
|
||||
public QualityModel Quality { get; set; }
|
||||
public Language Language { get; set; }
|
||||
public MediaInfoModel MediaInfo { get; set; }
|
||||
public bool ExistingFile { get; set; }
|
||||
public bool AdditionalFile { get; set; }
|
||||
public bool SceneSource { get; set; }
|
||||
|
|
|
@ -220,16 +220,13 @@ namespace NzbDrone.Core.Parser
|
|||
|
||||
public Album GetLocalAlbum(string filename, Artist artist)
|
||||
{
|
||||
|
||||
if (Path.HasExtension(filename))
|
||||
{
|
||||
filename = Path.GetDirectoryName(filename);
|
||||
}
|
||||
|
||||
filename = artist.Path.GetRelativePath(filename);
|
||||
|
||||
var tracksInAlbum = _mediaFileService.GetFilesByArtist(artist.Id)
|
||||
.FindAll(s => Path.GetDirectoryName(s.RelativePath) == filename)
|
||||
.FindAll(s => Path.GetDirectoryName(s.Path) == filename)
|
||||
.DistinctBy(s => s.AlbumId)
|
||||
.ToList();
|
||||
|
||||
|
|
|
@ -12,4 +12,5 @@
|
|||
<package id="TagLibSharp-Lidarr" version="2.2.0.19" targetFramework="net461" />
|
||||
<package id="TinyTwitter" version="1.1.2" targetFramework="net461" />
|
||||
<package id="xmlrpcnet" version="2.5.0" targetFramework="net461" />
|
||||
<package id="System.IO.Abstractions" version="4.0.11" targetFramework="net461" />
|
||||
</packages>
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
using NUnit.Framework;
|
||||
using System.Collections.Generic;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.Test.DiskTests;
|
||||
using NzbDrone.Mono.Disk;
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using Mono.Unix;
|
||||
using Mono.Unix.Native;
|
||||
|
@ -23,7 +24,16 @@ namespace NzbDrone.Mono.Disk
|
|||
// `unchecked((uint)-1)` and `uint.MaxValue` are the same thing.
|
||||
private const uint UNCHANGED_ID = uint.MaxValue;
|
||||
|
||||
public DiskProvider(IProcMountProvider procMountProvider, ISymbolicLinkResolver symLinkResolver)
|
||||
public DiskProvider(IProcMountProvider procMountProvider,
|
||||
ISymbolicLinkResolver symLinkResolver)
|
||||
: this(new FileSystem(), procMountProvider, symLinkResolver)
|
||||
{
|
||||
}
|
||||
|
||||
public DiskProvider(IFileSystem fileSystem,
|
||||
IProcMountProvider procMountProvider,
|
||||
ISymbolicLinkResolver symLinkResolver)
|
||||
: base(fileSystem)
|
||||
{
|
||||
_procMountProvider = procMountProvider;
|
||||
_symLinkResolver = symLinkResolver;
|
||||
|
@ -40,6 +50,8 @@ namespace NzbDrone.Mono.Disk
|
|||
{
|
||||
Ensure.That(path, () => path).IsValidPath();
|
||||
|
||||
Logger.Debug($"path: {path}");
|
||||
|
||||
var mount = GetMount(path);
|
||||
|
||||
if (mount == null)
|
||||
|
@ -57,9 +69,9 @@ namespace NzbDrone.Mono.Disk
|
|||
|
||||
try
|
||||
{
|
||||
var fs = File.GetAccessControl(filename);
|
||||
var fs = _fileSystem.File.GetAccessControl(filename);
|
||||
fs.SetAccessRuleProtection(false, false);
|
||||
File.SetAccessControl(filename, fs);
|
||||
_fileSystem.File.SetAccessControl(filename, fs);
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
{
|
||||
|
|
|
@ -58,6 +58,9 @@
|
|||
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NLog.4.5.4\lib\net45\NLog.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.Abstractions, Version=4.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IO.Abstractions.4.0.11\lib\net40\System.IO.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data" />
|
||||
|
@ -102,4 +105,4 @@
|
|||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
@ -9,6 +9,7 @@ using System.Runtime.CompilerServices;
|
|||
using Microsoft.Practices.Unity;
|
||||
using Moq;
|
||||
using Moq.Language.Flow;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Test.Common.AutoMoq.Unity;
|
||||
|
||||
|
@ -50,6 +51,15 @@ namespace NzbDrone.Test.Common.AutoMoq
|
|||
return result;
|
||||
}
|
||||
|
||||
public virtual T Resolve<T>(string name, params ResolverOverride[] resolverOverrides)
|
||||
{
|
||||
ResolveType = typeof(T);
|
||||
var result = _container.Resolve<T>(name, resolverOverrides);
|
||||
SetConstant(result);
|
||||
ResolveType = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
public virtual Mock<T> GetMock<T>() where T : class
|
||||
{
|
||||
return GetMock<T>(DefaultBehavior);
|
||||
|
@ -135,9 +145,9 @@ namespace NzbDrone.Test.Common.AutoMoq
|
|||
_container = container;
|
||||
container.RegisterInstance(this);
|
||||
|
||||
RegisterPlatformLibrary(container);
|
||||
|
||||
_registeredMocks = new Dictionary<Type, object>();
|
||||
|
||||
RegisterPlatformLibrary(container);
|
||||
AddTheAutoMockingContainerExtensionToTheContainer(container);
|
||||
}
|
||||
|
||||
|
@ -178,12 +188,15 @@ namespace NzbDrone.Test.Common.AutoMoq
|
|||
assemblyName = "Lidarr.Mono";
|
||||
}
|
||||
|
||||
if (!File.Exists(assemblyName + ".dll"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
var assembly = Assembly.Load(assemblyName);
|
||||
|
||||
Assembly.Load(assemblyName);
|
||||
// This allows us to resolve the platform specific disk provider in FileSystemTest
|
||||
var diskProvider = assembly.GetTypes().Where(x => x.Name == "DiskProvider").SingleOrDefault();
|
||||
container.RegisterType(typeof(IDiskProvider), diskProvider, "ActualDiskProvider");
|
||||
|
||||
// This tells the mocker to resolve IFileSystem using an actual filesystem (and not a mock)
|
||||
// if not specified, giving the old behaviour before we switched to System.IO.Abstractions.
|
||||
SetConstant<IFileSystem>(new FileSystem());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
|
|
@ -73,6 +73,9 @@
|
|||
<Reference Include="RestSharp, Version=105.2.3.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\RestSharp.105.2.3\lib\net46\RestSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.Abstractions, Version=4.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IO.Abstractions.4.0.11\lib\net40\System.IO.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data" />
|
||||
|
@ -80,15 +83,6 @@
|
|||
<Reference Include="System.Xml" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="Microsoft.Practices.Unity">
|
||||
<HintPath>..\packages\Unity.2.1.505.2\lib\NET35\Microsoft.Practices.Unity.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Microsoft.Practices.Unity.Configuration">
|
||||
<HintPath>..\packages\Unity.2.1.505.2\lib\NET35\Microsoft.Practices.Unity.Configuration.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="Moq">
|
||||
<HintPath>..\packages\Moq.4.0.10827\lib\NET40\Moq.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AutoMoq\AutoMoqer.cs" />
|
||||
|
@ -138,4 +132,4 @@
|
|||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace NzbDrone.Test.Common
|
|||
private TSubject _subject;
|
||||
|
||||
[SetUp]
|
||||
public void CoreTestSetup()
|
||||
public virtual void CoreTestSetup()
|
||||
{
|
||||
_subject = null;
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Runtime.InteropServices;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
|
@ -23,6 +24,16 @@ namespace NzbDrone.Windows.Disk
|
|||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
static extern bool CreateHardLink(string lpFileName, string lpExistingFileName, IntPtr lpSecurityAttributes);
|
||||
|
||||
public DiskProvider()
|
||||
: this(new FileSystem())
|
||||
{
|
||||
}
|
||||
|
||||
public DiskProvider(IFileSystem fileSystem)
|
||||
: base(fileSystem)
|
||||
{
|
||||
}
|
||||
|
||||
public override long? GetAvailableSpace(string path)
|
||||
{
|
||||
Ensure.That(path, () => path).IsValidPath();
|
||||
|
|
|
@ -59,6 +59,9 @@
|
|||
<Reference Include="NLog, Version=4.0.0.0, Culture=neutral, PublicKeyToken=5120e14c03d0593c, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\NLog.4.5.4\lib\net45\NLog.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.IO.Abstractions, Version=4.0.0.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.IO.Abstractions.4.0.11\lib\net40\System.IO.Abstractions.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data" />
|
||||
|
@ -91,4 +94,4 @@
|
|||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
Loading…
Reference in New Issue