Relative episode file paths
This commit is contained in:
parent
10fc875715
commit
6671934c0f
|
@ -1,5 +1,8 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Api.Episodes;
|
||||
using NzbDrone.Api.REST;
|
||||
using NzbDrone.Core.Datastore.Events;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
|
@ -7,6 +10,7 @@ using NzbDrone.Api.Mapping;
|
|||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Api.EpisodeFiles
|
||||
{
|
||||
|
@ -15,16 +19,19 @@ namespace NzbDrone.Api.EpisodeFiles
|
|||
{
|
||||
private readonly IMediaFileService _mediaFileService;
|
||||
private readonly IRecycleBinProvider _recycleBinProvider;
|
||||
private readonly ISeriesService _seriesService;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public EpisodeModule(ICommandExecutor commandExecutor,
|
||||
IMediaFileService mediaFileService,
|
||||
IRecycleBinProvider recycleBinProvider,
|
||||
ISeriesService seriesService,
|
||||
Logger logger)
|
||||
: base(commandExecutor)
|
||||
{
|
||||
_mediaFileService = mediaFileService;
|
||||
_recycleBinProvider = recycleBinProvider;
|
||||
_seriesService = seriesService;
|
||||
_logger = logger;
|
||||
GetResourceById = GetEpisodeFile;
|
||||
GetResourceAll = GetEpisodeFiles;
|
||||
|
@ -34,7 +41,10 @@ namespace NzbDrone.Api.EpisodeFiles
|
|||
|
||||
private EpisodeFileResource GetEpisodeFile(int id)
|
||||
{
|
||||
return _mediaFileService.Get(id).InjectTo<EpisodeFileResource>();
|
||||
var episodeFile = _mediaFileService.Get(id);
|
||||
var series = _seriesService.GetSeries(episodeFile.SeriesId);
|
||||
|
||||
return MapToResource(series, episodeFile);
|
||||
}
|
||||
|
||||
private List<EpisodeFileResource> GetEpisodeFiles()
|
||||
|
@ -46,7 +56,10 @@ namespace NzbDrone.Api.EpisodeFiles
|
|||
throw new BadRequestException("seriesId is missing");
|
||||
}
|
||||
|
||||
return ToListResource(() => _mediaFileService.GetFilesBySeries(seriesId.Value));
|
||||
var series = _seriesService.GetSeries(seriesId.Value);
|
||||
|
||||
return _mediaFileService.GetFilesBySeries(seriesId.Value)
|
||||
.Select(f => MapToResource(series, f)).ToList();
|
||||
}
|
||||
|
||||
private void SetQuality(EpisodeFileResource episodeFileResource)
|
||||
|
@ -59,12 +72,22 @@ namespace NzbDrone.Api.EpisodeFiles
|
|||
private void DeleteEpisodeFile(int id)
|
||||
{
|
||||
var episodeFile = _mediaFileService.Get(id);
|
||||
var series = _seriesService.GetSeries(episodeFile.SeriesId);
|
||||
var fullPath = Path.Combine(series.Path, episodeFile.RelativePath);
|
||||
|
||||
_logger.Info("Deleting episode file: {0}", episodeFile.Path);
|
||||
_recycleBinProvider.DeleteFile(episodeFile.Path);
|
||||
_logger.Info("Deleting episode file: {0}", fullPath);
|
||||
_recycleBinProvider.DeleteFile(fullPath);
|
||||
_mediaFileService.Delete(episodeFile);
|
||||
}
|
||||
|
||||
private static EpisodeFileResource MapToResource(Core.Tv.Series series, EpisodeFile episodeFile)
|
||||
{
|
||||
var resource = episodeFile.InjectTo<EpisodeFileResource>();
|
||||
resource.Path = Path.Combine(series.Path, episodeFile.RelativePath);
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
public void Handle(EpisodeFileAddedEvent message)
|
||||
{
|
||||
BroadcastResourceChange(ModelAction.Updated, message.EpisodeFile.Id);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using NzbDrone.Api.REST;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Api.EpisodeFiles
|
||||
{
|
||||
|
@ -9,6 +8,7 @@ namespace NzbDrone.Api.EpisodeFiles
|
|||
{
|
||||
public Int32 SeriesId { get; set; }
|
||||
public Int32 SeasonNumber { get; set; }
|
||||
public String RelativePath { get; set; }
|
||||
public String Path { get; set; }
|
||||
public Int64 Size { get; set; }
|
||||
public DateTime DateAdded { get; set; }
|
||||
|
|
|
@ -37,7 +37,6 @@ namespace NzbDrone.Api.Series
|
|||
ISceneMappingService sceneMappingService,
|
||||
IMapCoversToLocal coverMapper,
|
||||
RootFolderValidator rootFolderValidator,
|
||||
PathExistsValidator pathExistsValidator,
|
||||
SeriesPathValidator seriesPathValidator,
|
||||
SeriesExistsValidator seriesExistsValidator,
|
||||
DroneFactoryValidator droneFactoryValidator,
|
||||
|
|
|
@ -7,6 +7,7 @@ using NLog;
|
|||
using NzbDrone.Common.EnsureThat;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Common.Instrumentation;
|
||||
using NzbDrone.Common.Instrumentation.Extensions;
|
||||
|
||||
namespace NzbDrone.Common.Disk
|
||||
{
|
||||
|
@ -192,7 +193,7 @@ namespace NzbDrone.Common.Disk
|
|||
Ensure.That(source, () => source).IsValidPath();
|
||||
Ensure.That(target, () => target).IsValidPath();
|
||||
|
||||
Logger.Debug("{0} {1} -> {2}", transferAction, source, target);
|
||||
Logger.ProgressDebug("{0} {1} -> {2}", transferAction, source, target);
|
||||
|
||||
var sourceFolder = new DirectoryInfo(source);
|
||||
var targetFolder = new DirectoryInfo(target);
|
||||
|
@ -211,7 +212,7 @@ namespace NzbDrone.Common.Disk
|
|||
{
|
||||
var destFile = Path.Combine(target, sourceFile.Name);
|
||||
|
||||
Logger.Debug("{0} {1} -> {2}", transferAction, sourceFile, destFile);
|
||||
Logger.ProgressDebug("{0} {1} -> {2}", transferAction, sourceFile, destFile);
|
||||
|
||||
switch (transferAction)
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using NLog;
|
||||
|
||||
namespace NzbDrone.Core.Instrumentation.Extensions
|
||||
namespace NzbDrone.Common.Instrumentation.Extensions
|
||||
{
|
||||
public static class LoggerExtensions
|
||||
{
|
|
@ -118,6 +118,7 @@
|
|||
<Compile Include="IEnumerableExtensions.cs" />
|
||||
<Compile Include="Instrumentation\CleanseLogMessage.cs" />
|
||||
<Compile Include="Instrumentation\ExceptronTarget.cs" />
|
||||
<Compile Include="Instrumentation\Extensions\LoggerProgressExtensions.cs" />
|
||||
<Compile Include="Instrumentation\GlobalExceptionHandlers.cs" />
|
||||
<Compile Include="Instrumentation\LogEventExtensions.cs" />
|
||||
<Compile Include="Instrumentation\LogglyTarget.cs" />
|
||||
|
|
|
@ -86,14 +86,10 @@ namespace NzbDrone.Core.Test.Datastore
|
|||
|
||||
Db.Insert(episode);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
var loadedEpisodeFile = Db.Single<Episode>().EpisodeFile.Value;
|
||||
|
||||
loadedEpisodeFile.Should().NotBeNull();
|
||||
loadedEpisodeFile.ShouldHave().AllProperties().But(c => c.DateAdded).EqualTo(episodeFile);
|
||||
loadedEpisodeFile.ShouldHave().AllProperties().But(c => c.DateAdded).But(c => c.Path).EqualTo(episodeFile);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
|
|
@ -102,9 +102,9 @@ namespace NzbDrone.Core.Test.InstrumentationTests
|
|||
public void null_string_as_arg_should_not_fail()
|
||||
{
|
||||
var epFile = new EpisodeFile();
|
||||
_logger.Debug("File {0} no longer exists on disk. removing from database.", epFile.Path);
|
||||
_logger.Debug("File {0} no longer exists on disk. removing from database.", epFile.RelativePath);
|
||||
|
||||
epFile.Path.Should().BeNull();
|
||||
epFile.RelativePath.Should().BeNull();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -30,7 +30,8 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeFileMovingServiceTests
|
|||
.Build();
|
||||
|
||||
_episodeFile = Builder<EpisodeFile>.CreateNew()
|
||||
.With(f => f.Path = @"C:\Test\File.avi")
|
||||
.With(f => f.Path = null)
|
||||
.With(f => f.RelativePath = @"Season 1\File.avi")
|
||||
.Build();
|
||||
|
||||
_localEpisode = Builder<LocalEpisode>.CreateNew()
|
||||
|
@ -44,7 +45,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeFileMovingServiceTests
|
|||
|
||||
Mocker.GetMock<IBuildFileNames>()
|
||||
.Setup(s => s.BuildFilePath(It.IsAny<Series>(), It.IsAny<Int32>(), It.IsAny<String>(), It.IsAny<String>()))
|
||||
.Returns(@"C:\Test\File Name.avi");
|
||||
.Returns(@"C:\Test\TV\Series\File Name.avi");
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.FileExists(It.IsAny<String>()))
|
||||
|
|
|
@ -83,7 +83,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
|
|||
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Setup(c => c.FilterExistingFiles(_videoFiles, It.IsAny<int>()))
|
||||
.Setup(c => c.FilterExistingFiles(_videoFiles, It.IsAny<Series>()))
|
||||
.Returns(_videoFiles);
|
||||
}
|
||||
|
||||
|
@ -163,7 +163,7 @@ namespace NzbDrone.Core.Test.MediaFiles.EpisodeImport
|
|||
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Setup(c => c.FilterExistingFiles(_videoFiles, It.IsAny<int>()))
|
||||
.Setup(c => c.FilterExistingFiles(_videoFiles, It.IsAny<Series>()))
|
||||
.Returns(_videoFiles);
|
||||
|
||||
Subject.GetImportDecisions(_videoFiles, _series, false);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using FizzWare.NBuilder;
|
||||
using FluentAssertions;
|
||||
|
@ -31,6 +32,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
|
||||
var series = Builder<Series>.CreateNew()
|
||||
.With(e => e.Profile = new Profile { Items = Qualities.QualityFixture.GetDefaultQualities() })
|
||||
.With(s => s.Path = @"C:\Test\TV\30 Rock".AsOsAgnostic())
|
||||
.Build();
|
||||
|
||||
var episodes = Builder<Episode>.CreateListOfSize(5)
|
||||
|
@ -48,7 +50,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
{
|
||||
Series = series,
|
||||
Episodes = new List<Episode> {episode},
|
||||
Path = @"C:\Test\TV\30 Rock\30 Rock - S01E01 - Pilot.avi".AsOsAgnostic(),
|
||||
Path = Path.Combine(series.Path, "30 Rock - S01E01 - Pilot.avi"),
|
||||
Quality = new QualityModel(Quality.Bluray720p),
|
||||
ParsedEpisodeInfo = new ParsedEpisodeInfo
|
||||
{
|
||||
|
|
|
@ -4,7 +4,6 @@ using NUnit.Framework;
|
|||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
namespace NzbDrone.Core.Test.MediaFiles
|
||||
{
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
|
@ -6,20 +7,24 @@ using NUnit.Framework;
|
|||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Organizer;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Test.Common;
|
||||
|
||||
namespace NzbDrone.Core.Test.MediaFiles
|
||||
namespace NzbDrone.Core.Test.MediaFiles.MediaFileServiceTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class MediaFileServiceTest : CoreTest<MediaFileService>
|
||||
public class FilterFixture : CoreTest<MediaFileService>
|
||||
{
|
||||
private Series _series;
|
||||
|
||||
[Test]
|
||||
[TestCase("Law & Order: Criminal Intent - S10E07 - Icarus [HDTV-720p]",
|
||||
"Law & Order- Criminal Intent - S10E07 - Icarus [HDTV-720p]")]
|
||||
public void CleanFileName(string name, string expectedName)
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
FileNameBuilder.CleanFileName(name).Should().Be(expectedName);
|
||||
_series = new Series
|
||||
{
|
||||
Id = 10,
|
||||
Path = @"C:\".AsOsAgnostic()
|
||||
};
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -27,9 +32,9 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
{
|
||||
var files = new List<string>()
|
||||
{
|
||||
"c:\\file1.avi".AsOsAgnostic(),
|
||||
"c:\\file2.avi".AsOsAgnostic(),
|
||||
"c:\\file3.avi".AsOsAgnostic()
|
||||
"C:\\file1.avi".AsOsAgnostic(),
|
||||
"C:\\file2.avi".AsOsAgnostic(),
|
||||
"C:\\file3.avi".AsOsAgnostic()
|
||||
};
|
||||
|
||||
Mocker.GetMock<IMediaFileRepository>()
|
||||
|
@ -37,26 +42,25 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
.Returns(new List<EpisodeFile>());
|
||||
|
||||
|
||||
Subject.FilterExistingFiles(files, 10).Should().BeEquivalentTo(files);
|
||||
Subject.FilterExistingFiles(files, _series).Should().BeEquivalentTo(files);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void filter_should_return_none_if_all_files_exist()
|
||||
{
|
||||
var files = new List<string>()
|
||||
{
|
||||
"c:\\file1.avi".AsOsAgnostic(),
|
||||
"c:\\file2.avi".AsOsAgnostic(),
|
||||
"c:\\file3.avi".AsOsAgnostic()
|
||||
"C:\\file1.avi".AsOsAgnostic(),
|
||||
"C:\\file2.avi".AsOsAgnostic(),
|
||||
"C:\\file3.avi".AsOsAgnostic()
|
||||
};
|
||||
|
||||
Mocker.GetMock<IMediaFileRepository>()
|
||||
.Setup(c => c.GetFilesBySeries(It.IsAny<int>()))
|
||||
.Returns(files.Select(f => new EpisodeFile { Path = f }).ToList());
|
||||
.Returns(files.Select(f => new EpisodeFile { RelativePath = Path.GetFileName(f) }).ToList());
|
||||
|
||||
|
||||
Subject.FilterExistingFiles(files, 10).Should().BeEmpty();
|
||||
Subject.FilterExistingFiles(files, _series).Should().BeEmpty();
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -64,21 +68,21 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
{
|
||||
var files = new List<string>()
|
||||
{
|
||||
"c:\\file1.avi".AsOsAgnostic(),
|
||||
"c:\\file2.avi".AsOsAgnostic(),
|
||||
"c:\\file3.avi".AsOsAgnostic()
|
||||
"C:\\file1.avi".AsOsAgnostic(),
|
||||
"C:\\file2.avi".AsOsAgnostic(),
|
||||
"C:\\file3.avi".AsOsAgnostic()
|
||||
};
|
||||
|
||||
Mocker.GetMock<IMediaFileRepository>()
|
||||
.Setup(c => c.GetFilesBySeries(It.IsAny<int>()))
|
||||
.Returns(new List<EpisodeFile>
|
||||
{
|
||||
new EpisodeFile{Path = "c:\\file2.avi".AsOsAgnostic()}
|
||||
new EpisodeFile{ RelativePath = "file2.avi".AsOsAgnostic()}
|
||||
});
|
||||
|
||||
|
||||
Subject.FilterExistingFiles(files, 10).Should().HaveCount(2);
|
||||
Subject.FilterExistingFiles(files, 10).Should().NotContain("c:\\file2.avi".AsOsAgnostic());
|
||||
Subject.FilterExistingFiles(files, _series).Should().HaveCount(2);
|
||||
Subject.FilterExistingFiles(files, _series).Should().NotContain("C:\\file2.avi".AsOsAgnostic());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -88,21 +92,21 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
|
||||
var files = new List<string>()
|
||||
{
|
||||
"c:\\file1.avi".AsOsAgnostic(),
|
||||
"c:\\FILE2.avi".AsOsAgnostic(),
|
||||
"c:\\file3.avi".AsOsAgnostic()
|
||||
"C:\\file1.avi".AsOsAgnostic(),
|
||||
"C:\\FILE2.avi".AsOsAgnostic(),
|
||||
"C:\\file3.avi".AsOsAgnostic()
|
||||
};
|
||||
|
||||
Mocker.GetMock<IMediaFileRepository>()
|
||||
.Setup(c => c.GetFilesBySeries(It.IsAny<int>()))
|
||||
.Returns(new List<EpisodeFile>
|
||||
{
|
||||
new EpisodeFile{Path = "c:\\file2.avi".AsOsAgnostic()}
|
||||
new EpisodeFile{ RelativePath = "file2.avi".AsOsAgnostic()}
|
||||
});
|
||||
|
||||
|
||||
Subject.FilterExistingFiles(files, 10).Should().HaveCount(2);
|
||||
Subject.FilterExistingFiles(files, 10).Should().NotContain("c:\\file2.avi".AsOsAgnostic());
|
||||
Subject.FilterExistingFiles(files, _series).Should().HaveCount(2);
|
||||
Subject.FilterExistingFiles(files, _series).Should().NotContain("C:\\file2.avi".AsOsAgnostic());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -112,19 +116,19 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
|
||||
var files = new List<string>()
|
||||
{
|
||||
"c:\\file1.avi".AsOsAgnostic(),
|
||||
"c:\\FILE2.avi".AsOsAgnostic(),
|
||||
"c:\\file3.avi".AsOsAgnostic()
|
||||
"C:\\file1.avi".AsOsAgnostic(),
|
||||
"C:\\FILE2.avi".AsOsAgnostic(),
|
||||
"C:\\file3.avi".AsOsAgnostic()
|
||||
};
|
||||
|
||||
Mocker.GetMock<IMediaFileRepository>()
|
||||
.Setup(c => c.GetFilesBySeries(It.IsAny<int>()))
|
||||
.Returns(new List<EpisodeFile>
|
||||
{
|
||||
new EpisodeFile{Path = "c:\\file2.avi".AsOsAgnostic()}
|
||||
new EpisodeFile{ RelativePath = "file2.avi".AsOsAgnostic()}
|
||||
});
|
||||
|
||||
Subject.FilterExistingFiles(files, 10).Should().HaveCount(3);
|
||||
Subject.FilterExistingFiles(files, _series).Should().HaveCount(3);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -132,16 +136,16 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
{
|
||||
var files = new List<string>()
|
||||
{
|
||||
"c:\\FILE1.avi".AsOsAgnostic()
|
||||
"C:\\FILE1.avi".AsOsAgnostic()
|
||||
};
|
||||
|
||||
Mocker.GetMock<IMediaFileRepository>()
|
||||
.Setup(c => c.GetFilesBySeries(It.IsAny<int>()))
|
||||
.Returns(new List<EpisodeFile>());
|
||||
|
||||
Subject.FilterExistingFiles(files, 10).Should().HaveCount(1);
|
||||
Subject.FilterExistingFiles(files, 10).Should().NotContain(files.First().ToLower());
|
||||
Subject.FilterExistingFiles(files, 10).Should().Contain(files.First());
|
||||
Subject.FilterExistingFiles(files, _series).Should().HaveCount(1);
|
||||
Subject.FilterExistingFiles(files, _series).Should().NotContain(files.First().ToLower());
|
||||
Subject.FilterExistingFiles(files, _series).Should().Contain(files.First());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,7 +30,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
.Returns(Builder<Series>.CreateNew().Build());
|
||||
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(e => e.FileExists(It.Is<String>(c => c != DELETED_PATH)))
|
||||
.Setup(e => e.FileExists(It.Is<String>(c => !c.Contains(DELETED_PATH))))
|
||||
.Returns(true);
|
||||
|
||||
Mocker.GetMock<IEpisodeService>()
|
||||
|
@ -68,18 +68,18 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void should_delete_none_existing_files()
|
||||
public void should_delete_non_existent_files()
|
||||
{
|
||||
var episodeFiles = Builder<EpisodeFile>.CreateListOfSize(10)
|
||||
.Random(2)
|
||||
.With(c => c.Path = DELETED_PATH)
|
||||
.With(c => c.RelativePath = DELETED_PATH)
|
||||
.Build();
|
||||
|
||||
GivenEpisodeFiles(episodeFiles);
|
||||
|
||||
Subject.Execute(new CleanMediaFileDb(0));
|
||||
|
||||
Mocker.GetMock<IMediaFileService>().Verify(c => c.Delete(It.Is<EpisodeFile>(e => e.Path == DELETED_PATH), false), Times.Exactly(2));
|
||||
Mocker.GetMock<IMediaFileService>().Verify(c => c.Delete(It.Is<EpisodeFile>(e => e.RelativePath == DELETED_PATH), false), Times.Exactly(2));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -87,7 +87,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
{
|
||||
var episodeFiles = Builder<EpisodeFile>.CreateListOfSize(10)
|
||||
.Random(10)
|
||||
.With(c => c.Path = "ExistingPath")
|
||||
.With(c => c.RelativePath = "ExistingPath")
|
||||
.Build();
|
||||
|
||||
GivenEpisodeFiles(episodeFiles);
|
||||
|
@ -98,21 +98,6 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
Mocker.GetMock<IMediaFileService>().Verify(c => c.Delete(It.IsAny<EpisodeFile>(), false), Times.Exactly(10));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_delete_files_that_do_not_belong_to_the_series_path()
|
||||
{
|
||||
var episodeFiles = Builder<EpisodeFile>.CreateListOfSize(10)
|
||||
.Random(10)
|
||||
.With(c => c.Path = "ExistingPath")
|
||||
.Build();
|
||||
|
||||
GivenEpisodeFiles(episodeFiles);
|
||||
|
||||
Subject.Execute(new CleanMediaFileDb(0));
|
||||
|
||||
Mocker.GetMock<IMediaFileService>().Verify(c => c.Delete(It.IsAny<EpisodeFile>(), false), Times.Exactly(10));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_unlink_episode_when_episodeFile_does_not_exist()
|
||||
{
|
||||
|
@ -128,7 +113,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
{
|
||||
var episodeFiles = Builder<EpisodeFile>.CreateListOfSize(10)
|
||||
.Random(10)
|
||||
.With(c => c.Path = "ExistingPath")
|
||||
.With(c => c.RelativePath = "ExistingPath")
|
||||
.Build();
|
||||
|
||||
GivenEpisodeFiles(episodeFiles);
|
||||
|
|
|
@ -1,23 +1,33 @@
|
|||
using FizzWare.NBuilder;
|
||||
using System.IO;
|
||||
using FizzWare.NBuilder;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Core.Lifecycle;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.MediaFiles.MediaInfo;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Test.Common;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Core.Test.MediaFiles.MediaInfo
|
||||
{
|
||||
[TestFixture]
|
||||
public class UpdateMediaInfoServiceFixture : CoreTest<UpdateMediaInfoService>
|
||||
{
|
||||
private Series _series;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_series = new Series
|
||||
{
|
||||
Id = 1,
|
||||
Path = @"C:\series".AsOsAgnostic()
|
||||
};
|
||||
}
|
||||
|
||||
private void GivenFileExists()
|
||||
{
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
|
@ -44,7 +54,7 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo
|
|||
{
|
||||
var episodeFiles = Builder<EpisodeFile>.CreateListOfSize(3)
|
||||
.All()
|
||||
.With(v => v.Path = @"C:\series\media.mkv".AsOsAgnostic())
|
||||
.With(v => v.RelativePath = "media.mkv")
|
||||
.TheFirst(1)
|
||||
.With(v => v.MediaInfo = new MediaInfoModel())
|
||||
.BuildList();
|
||||
|
@ -56,10 +66,10 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo
|
|||
GivenFileExists();
|
||||
GivenSuccessfulScan();
|
||||
|
||||
Subject.Handle(new SeriesScannedEvent(new Tv.Series { Id = 1 }));
|
||||
Subject.Handle(new SeriesScannedEvent(_series));
|
||||
|
||||
Mocker.GetMock<IVideoFileInfoReader>()
|
||||
.Verify(v => v.GetMediaInfo(@"C:\series\media.mkv".AsOsAgnostic()), Times.Exactly(2));
|
||||
.Verify(v => v.GetMediaInfo(Path.Combine(_series.Path, "media.mkv")), Times.Exactly(2));
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Verify(v => v.Update(It.IsAny<EpisodeFile>()), Times.Exactly(2));
|
||||
|
@ -70,7 +80,7 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo
|
|||
{
|
||||
var episodeFiles = Builder<EpisodeFile>.CreateListOfSize(2)
|
||||
.All()
|
||||
.With(v => v.Path = @"C:\series\media.mkv".AsOsAgnostic())
|
||||
.With(v => v.RelativePath = "media.mkv")
|
||||
.BuildList();
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
|
@ -79,10 +89,10 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo
|
|||
|
||||
GivenSuccessfulScan();
|
||||
|
||||
Subject.Handle(new SeriesScannedEvent(new Tv.Series { Id = 1 }));
|
||||
Subject.Handle(new SeriesScannedEvent(_series));
|
||||
|
||||
Mocker.GetMock<IVideoFileInfoReader>()
|
||||
.Verify(v => v.GetMediaInfo(@"C:\series\media.mkv".AsOsAgnostic()), Times.Never());
|
||||
.Verify(v => v.GetMediaInfo("media.mkv"), Times.Never());
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Verify(v => v.Update(It.IsAny<EpisodeFile>()), Times.Never());
|
||||
|
@ -93,9 +103,9 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo
|
|||
{
|
||||
var episodeFiles = Builder<EpisodeFile>.CreateListOfSize(2)
|
||||
.All()
|
||||
.With(v => v.Path = @"C:\series\media.mkv".AsOsAgnostic())
|
||||
.With(v => v.RelativePath = "media.mkv")
|
||||
.TheFirst(1)
|
||||
.With(v => v.Path = @"C:\series\media2.mkv".AsOsAgnostic())
|
||||
.With(v => v.RelativePath = "media2.mkv")
|
||||
.BuildList();
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
|
@ -104,12 +114,12 @@ namespace NzbDrone.Core.Test.MediaFiles.MediaInfo
|
|||
|
||||
GivenFileExists();
|
||||
GivenSuccessfulScan();
|
||||
GivenFailedScan(@"C:\series\media2.mkv".AsOsAgnostic());
|
||||
GivenFailedScan(Path.Combine(_series.Path, "media2.mkv"));
|
||||
|
||||
Subject.Handle(new SeriesScannedEvent(new Tv.Series { Id = 1 }));
|
||||
Subject.Handle(new SeriesScannedEvent(_series));
|
||||
|
||||
Mocker.GetMock<IVideoFileInfoReader>()
|
||||
.Verify(v => v.GetMediaInfo(@"C:\series\media.mkv".AsOsAgnostic()), Times.Exactly(1));
|
||||
.Verify(v => v.GetMediaInfo(Path.Combine(_series.Path, "media.mkv")), Times.Exactly(1));
|
||||
|
||||
Mocker.GetMock<IMediaFileService>()
|
||||
.Verify(v => v.Update(It.IsAny<EpisodeFile>()), Times.Exactly(1));
|
||||
|
|
|
@ -10,6 +10,7 @@ using NzbDrone.Core.MediaFiles;
|
|||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Test.Common;
|
||||
|
||||
namespace NzbDrone.Core.Test.MediaFiles
|
||||
{
|
||||
|
@ -22,6 +23,10 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
public void Setup()
|
||||
{
|
||||
_localEpisode = new LocalEpisode();
|
||||
_localEpisode.Series = new Series
|
||||
{
|
||||
Path = @"C:\Test\TV\Series".AsOsAgnostic()
|
||||
};
|
||||
|
||||
_episodeFile = Builder<EpisodeFile>
|
||||
.CreateNew()
|
||||
|
@ -42,7 +47,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
new EpisodeFile
|
||||
{
|
||||
Id = 1,
|
||||
Path = @"C:\Test\30 Rock\Season 01\30.rock.s01e01.avi",
|
||||
RelativePath = @"Season 01\30.rock.s01e01.avi",
|
||||
}))
|
||||
.Build()
|
||||
.ToList();
|
||||
|
@ -57,7 +62,7 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
new EpisodeFile
|
||||
{
|
||||
Id = 1,
|
||||
Path = @"C:\Test\30 Rock\Season 01\30.rock.s01e01.avi",
|
||||
RelativePath = @"Season 01\30.rock.s01e01.avi",
|
||||
}))
|
||||
.Build()
|
||||
.ToList();
|
||||
|
@ -71,14 +76,14 @@ namespace NzbDrone.Core.Test.MediaFiles
|
|||
new EpisodeFile
|
||||
{
|
||||
Id = 1,
|
||||
Path = @"C:\Test\30 Rock\Season 01\30.rock.s01e01.avi",
|
||||
RelativePath = @"Season 01\30.rock.s01e01.avi",
|
||||
}))
|
||||
.TheNext(1)
|
||||
.With(e => e.EpisodeFile = new LazyLoaded<EpisodeFile>(
|
||||
new EpisodeFile
|
||||
{
|
||||
Id = 2,
|
||||
Path = @"C:\Test\30 Rock\Season 01\30.rock.s01e02.avi",
|
||||
RelativePath = @"Season 01\30.rock.s01e02.avi",
|
||||
}))
|
||||
.Build()
|
||||
.ToList();
|
||||
|
|
|
@ -188,7 +188,8 @@
|
|||
<Compile Include="MediaFiles\EpisodeImport\Specifications\UpgradeSpecificationFixture.cs" />
|
||||
<Compile Include="MediaFiles\ImportApprovedEpisodesFixture.cs" />
|
||||
<Compile Include="MediaFiles\MediaFileRepositoryFixture.cs" />
|
||||
<Compile Include="MediaFiles\MediaFileServiceTest.cs" />
|
||||
<Compile Include="OrganizerTests\CleanFixture.cs" />
|
||||
<Compile Include="MediaFiles\MediaFileServiceTests\FilterFixture.cs" />
|
||||
<Compile Include="MediaFiles\MediaFileTableCleanupServiceFixture.cs" />
|
||||
<Compile Include="MediaFiles\MediaInfo\UpdateMediaInfoServiceFixture.cs" />
|
||||
<Compile Include="MediaFiles\MediaInfo\VideoFileInfoReaderFixture.cs" />
|
||||
|
@ -262,6 +263,7 @@
|
|||
<Compile Include="TvTests\EpisodeRepositoryTests\EpisodesWithFilesFixture.cs" />
|
||||
<Compile Include="TvTests\EpisodeRepositoryTests\EpisodesWithoutFilesFixture.cs" />
|
||||
<Compile Include="TvTests\EpisodeRepositoryTests\FindEpisodeFixture.cs" />
|
||||
<Compile Include="TvTests\MoveSeriesServiceFixture.cs" />
|
||||
<Compile Include="TvTests\RefreshEpisodeServiceFixture.cs" />
|
||||
<Compile Include="TvTests\RefreshSeriesServiceFixture.cs" />
|
||||
<Compile Include="TvTests\SeriesRepositoryTests\SeriesRepositoryFixture.cs" />
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using FluentAssertions;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Organizer;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Test.Common;
|
||||
|
||||
namespace NzbDrone.Core.Test.OrganizerTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class CleanFixture : CoreTest
|
||||
{
|
||||
[TestCase("Law & Order: Criminal Intent - S10E07 - Icarus [HDTV-720p]",
|
||||
"Law & Order- Criminal Intent - S10E07 - Icarus [HDTV-720p]")]
|
||||
public void CleanFileName(string name, string expectedName)
|
||||
{
|
||||
FileNameBuilder.CleanFileName(name).Should().Be(expectedName);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -64,6 +64,8 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
_episodeFile.Quality.Proper = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
[Test]
|
||||
public void should_replace_Series_space_Title()
|
||||
{
|
||||
|
@ -227,10 +229,10 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
public void use_file_name_when_sceneName_is_null()
|
||||
{
|
||||
_namingConfig.RenameEpisodes = false;
|
||||
_episodeFile.Path = @"C:\Test\TV\30 Rock - S01E01 - Test";
|
||||
_episodeFile.RelativePath = "30 Rock - S01E01 - Test";
|
||||
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be(Path.GetFileNameWithoutExtension(_episodeFile.Path));
|
||||
.Should().Be(Path.GetFileNameWithoutExtension(_episodeFile.RelativePath));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -238,7 +240,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
{
|
||||
_namingConfig.RenameEpisodes = false;
|
||||
_episodeFile.SceneName = "30.Rock.S01E01.xvid-LOL";
|
||||
_episodeFile.Path = @"C:\Test\TV\30 Rock - S01E01 - Test";
|
||||
_episodeFile.RelativePath = "30 Rock - S01E01 - Test";
|
||||
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be("30.Rock.S01E01.xvid-LOL");
|
||||
|
@ -378,7 +380,7 @@ namespace NzbDrone.Core.Test.OrganizerTests
|
|||
_namingConfig.StandardEpisodeFormat = "{Series Title} - {Original Title}";
|
||||
|
||||
_episodeFile.SceneName = "30.Rock.S01E01.xvid-LOL";
|
||||
_episodeFile.Path = @"C:\Test\TV\30 Rock - S01E01 - Test";
|
||||
_episodeFile.RelativePath = "30 Rock - S01E01 - Test";
|
||||
|
||||
Subject.BuildFileName(new List<Episode> { _episode1 }, _series, _episodeFile)
|
||||
.Should().Be("30 Rock - 30.Rock.S01E01.xvid-LOL");
|
||||
|
|
|
@ -67,9 +67,9 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeRepositoryTests
|
|||
new QualitiesBelowCutoff(profile.Id, new[] {Quality.SDTV.Id})
|
||||
};
|
||||
|
||||
var qualityMet = new EpisodeFile { Path = "a", Quality = new QualityModel { Quality = Quality.WEBDL480p } };
|
||||
var qualityUnmet = new EpisodeFile { Path = "b", Quality = new QualityModel { Quality = Quality.SDTV } };
|
||||
var qualityRawHD = new EpisodeFile { Path = "c", Quality = new QualityModel { Quality = Quality.RAWHD } };
|
||||
var qualityMet = new EpisodeFile { RelativePath = "a", Quality = new QualityModel { Quality = Quality.WEBDL480p } };
|
||||
var qualityUnmet = new EpisodeFile { RelativePath = "b", Quality = new QualityModel { Quality = Quality.SDTV } };
|
||||
var qualityRawHD = new EpisodeFile { RelativePath = "c", Quality = new QualityModel { Quality = Quality.RAWHD } };
|
||||
|
||||
MediaFileRepository fileRepository = Mocker.Resolve<MediaFileRepository>();
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ namespace NzbDrone.Core.Test.TvTests.EpisodeRepositoryTests
|
|||
public void should_only_contain_episodes_for_the_given_series()
|
||||
{
|
||||
var episodeFile = Builder<EpisodeFile>.CreateNew()
|
||||
.With(f => f.Path = "another path")
|
||||
.With(f => f.RelativePath = "another path")
|
||||
.With(c => c.Quality = new QualityModel())
|
||||
.BuildNew();
|
||||
|
||||
|
|
|
@ -0,0 +1,100 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using FizzWare.NBuilder;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Core.Organizer;
|
||||
using NzbDrone.Core.Test.Framework;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Tv.Commands;
|
||||
using NzbDrone.Test.Common;
|
||||
|
||||
namespace NzbDrone.Core.Test.TvTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class MoveSeriesServiceFixture : CoreTest<MoveSeriesService>
|
||||
{
|
||||
private Series _series;
|
||||
private MoveSeriesCommand _command;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_series = Builder<Series>
|
||||
.CreateNew()
|
||||
.Build();
|
||||
|
||||
_command = new MoveSeriesCommand
|
||||
{
|
||||
SeriesId = 1,
|
||||
SourcePath = @"C:\Test\TV\Series".AsOsAgnostic(),
|
||||
DestinationPath = @"C:\Test\TV2\Series".AsOsAgnostic()
|
||||
};
|
||||
|
||||
Mocker.GetMock<ISeriesService>()
|
||||
.Setup(s => s.GetSeries(It.IsAny<Int32>()))
|
||||
.Returns(_series);
|
||||
}
|
||||
|
||||
private void GivenFailedMove()
|
||||
{
|
||||
Mocker.GetMock<IDiskProvider>()
|
||||
.Setup(s => s.MoveFolder(It.IsAny<String>(), It.IsAny<String>()))
|
||||
.Throws<IOException>();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_log_error_when_move_throws_an_exception()
|
||||
{
|
||||
GivenFailedMove();
|
||||
|
||||
Assert.Throws<IOException>(() => Subject.Execute(_command));
|
||||
|
||||
ExceptionVerification.ExpectedErrors(1);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_no_update_series_path_on_error()
|
||||
{
|
||||
GivenFailedMove();
|
||||
|
||||
Assert.Throws<IOException>(() => Subject.Execute(_command));
|
||||
|
||||
ExceptionVerification.ExpectedErrors(1);
|
||||
|
||||
Mocker.GetMock<ISeriesService>()
|
||||
.Verify(v => v.UpdateSeries(It.IsAny<Series>()), Times.Never());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_build_new_path_when_root_folder_is_provided()
|
||||
{
|
||||
_command.DestinationPath = null;
|
||||
_command.DestinationRootFolder = @"C:\Test\TV3".AsOsAgnostic();
|
||||
|
||||
var expectedPath = @"C:\Test\TV3\Series".AsOsAgnostic();
|
||||
|
||||
Mocker.GetMock<IBuildFileNames>()
|
||||
.Setup(s => s.GetSeriesFolder(It.IsAny<Series>(), null))
|
||||
.Returns("Series");
|
||||
|
||||
Subject.Execute(_command);
|
||||
|
||||
Mocker.GetMock<ISeriesService>()
|
||||
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.Path == expectedPath)), Times.Once());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void should_use_destination_path_if_destination_root_folder_is_blank()
|
||||
{
|
||||
Subject.Execute(_command);
|
||||
|
||||
Mocker.GetMock<ISeriesService>()
|
||||
.Verify(v => v.UpdateSeries(It.Is<Series>(s => s.Path == _command.DestinationPath)), Times.Once());
|
||||
|
||||
Mocker.GetMock<IBuildFileNames>()
|
||||
.Verify(v => v.GetSeriesFolder(It.IsAny<Series>(), null), Times.Never());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,8 +8,8 @@ using NLog;
|
|||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Common.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
|
||||
namespace NzbDrone.Core.Backup
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
using System.Data;
|
||||
using System.IO;
|
||||
using FluentMigrator;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(57)]
|
||||
public class convert_episode_file_path_to_relative : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
Create.Column("RelativePath").OnTable("EpisodeFiles").AsString().Nullable();
|
||||
|
||||
//TODO: Add unique contraint for series ID and Relative Path
|
||||
//TODO: Warn if multiple series share the same path
|
||||
|
||||
Execute.WithConnection(UpdateRelativePaths);
|
||||
}
|
||||
|
||||
private void UpdateRelativePaths(IDbConnection conn, IDbTransaction tran)
|
||||
{
|
||||
using (IDbCommand getSeriesCmd = conn.CreateCommand())
|
||||
{
|
||||
getSeriesCmd.Transaction = tran;
|
||||
getSeriesCmd.CommandText = @"SELECT Id, Path FROM Series";
|
||||
using (IDataReader seriesReader = getSeriesCmd.ExecuteReader())
|
||||
{
|
||||
while (seriesReader.Read())
|
||||
{
|
||||
var seriesId = seriesReader.GetInt32(0);
|
||||
var seriesPath = seriesReader.GetString(1) + Path.DirectorySeparatorChar;
|
||||
|
||||
using (IDbCommand updateCmd = conn.CreateCommand())
|
||||
{
|
||||
updateCmd.Transaction = tran;
|
||||
updateCmd.CommandText = "UPDATE EpisodeFiles SET RelativePath = REPLACE(Path, ?, '') WHERE SeriesId = ?";
|
||||
updateCmd.AddParameter(seriesPath);
|
||||
updateCmd.AddParameter(seriesId);
|
||||
|
||||
updateCmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
using FluentMigrator;
|
||||
using NzbDrone.Core.Datastore.Migration.Framework;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration
|
||||
{
|
||||
[Migration(58)]
|
||||
public class drop_episode_file_path : NzbDroneMigrationBase
|
||||
{
|
||||
protected override void MainDbUpgrade()
|
||||
{
|
||||
SqLiteAlter.DropColumns("EpisodeFiles", new [] { "Path" });
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,241 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.SQLite;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using NLog;
|
||||
|
||||
namespace NzbDrone.Core.Datastore.Migration.Framework
|
||||
{
|
||||
public interface ISQLiteMigrationHelper
|
||||
{
|
||||
Dictionary<String, SQLiteMigrationHelper.SQLiteColumn> GetColumns(string tableName);
|
||||
void CreateTable(string tableName, IEnumerable<SQLiteMigrationHelper.SQLiteColumn> values, IEnumerable<SQLiteMigrationHelper.SQLiteIndex> indexes);
|
||||
void CopyData(string sourceTable, string destinationTable, IEnumerable<SQLiteMigrationHelper.SQLiteColumn> columns);
|
||||
void DropTable(string tableName);
|
||||
void RenameTable(string tableName, string newName);
|
||||
List<T> GetDuplicates<T>(string tableName, string columnName);
|
||||
SQLiteTransaction BeginTransaction();
|
||||
List<SQLiteMigrationHelper.SQLiteIndex> GetIndexes(string tableName);
|
||||
}
|
||||
|
||||
public class SQLiteMigrationHelper : ISQLiteMigrationHelper
|
||||
{
|
||||
private readonly SQLiteConnection _connection;
|
||||
|
||||
private static readonly Regex SchemaRegex = new Regex(@"['\""\[](?<name>\w+)['\""\]]\s(?<schema>[\w-\s]+)",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline);
|
||||
|
||||
private static readonly Regex IndexRegex = new Regex(@"\(""(?<col>.*)""\s(?<direction>ASC|DESC)\)$",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Multiline);
|
||||
|
||||
public SQLiteMigrationHelper(IConnectionStringFactory connectionStringFactory, Logger logger)
|
||||
{
|
||||
try
|
||||
{
|
||||
_connection = new SQLiteConnection(connectionStringFactory.MainDbConnectionString);
|
||||
_connection.Open();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
logger.ErrorException("Couldn't open database " + connectionStringFactory.MainDbConnectionString, e);
|
||||
throw;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private string GetOriginalSql(string tableName)
|
||||
{
|
||||
var command =
|
||||
new SQLiteCommand(string.Format("SELECT sql FROM sqlite_master WHERE type='table' AND name ='{0}'",
|
||||
tableName));
|
||||
|
||||
command.Connection = _connection;
|
||||
|
||||
return (string)command.ExecuteScalar();
|
||||
}
|
||||
|
||||
public Dictionary<String, SQLiteColumn> GetColumns(string tableName)
|
||||
{
|
||||
var originalSql = GetOriginalSql(tableName);
|
||||
|
||||
var matches = SchemaRegex.Matches(originalSql);
|
||||
|
||||
return matches.Cast<Match>().ToDictionary(
|
||||
match => match.Groups["name"].Value.Trim(),
|
||||
match => new SQLiteColumn
|
||||
{
|
||||
Name = match.Groups["name"].Value.Trim(),
|
||||
Schema = match.Groups["schema"].Value.Trim()
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private static IEnumerable<T> ReadArray<T>(SQLiteDataReader reader)
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
yield return (T)Convert.ChangeType(reader[0], typeof(T));
|
||||
}
|
||||
}
|
||||
|
||||
public List<SQLiteIndex> GetIndexes(string tableName)
|
||||
{
|
||||
var command = new SQLiteCommand(string.Format("SELECT sql FROM sqlite_master WHERE type='index' AND tbl_name ='{0}'", tableName));
|
||||
command.Connection = _connection;
|
||||
|
||||
var reader = command.ExecuteReader();
|
||||
var sqls = ReadArray<string>(reader).ToList();
|
||||
|
||||
|
||||
var indexes = new List<SQLiteIndex>();
|
||||
|
||||
foreach (var indexSql in sqls)
|
||||
{
|
||||
var newIndex = new SQLiteIndex();
|
||||
var matches = IndexRegex.Match(indexSql);
|
||||
|
||||
newIndex.Column = matches.Groups["col"].Value;
|
||||
newIndex.Unique = indexSql.Contains("UNIQUE");
|
||||
newIndex.Table = tableName;
|
||||
|
||||
indexes.Add(newIndex);
|
||||
}
|
||||
|
||||
return indexes;
|
||||
}
|
||||
|
||||
public void CreateTable(string tableName, IEnumerable<SQLiteColumn> values, IEnumerable<SQLiteIndex> indexes)
|
||||
{
|
||||
var columns = String.Join(",", values.Select(c => c.ToString()));
|
||||
|
||||
ExecuteNonQuery("CREATE TABLE [{0}] ({1})", tableName, columns);
|
||||
|
||||
foreach (var index in indexes)
|
||||
{
|
||||
ExecuteNonQuery("DROP INDEX {0}", index.IndexName);
|
||||
ExecuteNonQuery(index.CreateSql(tableName));
|
||||
}
|
||||
}
|
||||
|
||||
public void CopyData(string sourceTable, string destinationTable, IEnumerable<SQLiteColumn> columns)
|
||||
{
|
||||
var originalCount = GetRowCount(sourceTable);
|
||||
|
||||
var columnsToTransfer = String.Join(",", columns.Select(c => c.Name));
|
||||
|
||||
var transferCommand = BuildCommand("INSERT INTO {0} SELECT {1} FROM {2};", destinationTable, columnsToTransfer, sourceTable);
|
||||
|
||||
transferCommand.ExecuteNonQuery();
|
||||
|
||||
var transferredRows = GetRowCount(destinationTable);
|
||||
|
||||
|
||||
if (transferredRows != originalCount)
|
||||
{
|
||||
throw new ApplicationException(string.Format("Expected {0} rows to be copied from [{1}] to [{2}]. But only copied {3}", originalCount, sourceTable, destinationTable, transferredRows));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void DropTable(string tableName)
|
||||
{
|
||||
var dropCommand = BuildCommand("DROP TABLE {0};", tableName);
|
||||
dropCommand.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
|
||||
public void RenameTable(string tableName, string newName)
|
||||
{
|
||||
var renameCommand = BuildCommand("ALTER TABLE {0} RENAME TO {1};", tableName, newName);
|
||||
renameCommand.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
public Dictionary<int,T> GetDuplicates<T>(string tableName, string columnName)
|
||||
{
|
||||
var dupCommand = BuildCommand("select id, {0} from {1}", columnName, tableName);
|
||||
|
||||
var result = new Dictionary<int, T>();
|
||||
using (var reader = dupCommand.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return ReadArray<T>().ToList();
|
||||
}
|
||||
|
||||
public int GetRowCount(string tableName)
|
||||
{
|
||||
var countCommand = BuildCommand("SELECT COUNT(*) FROM {0};", tableName);
|
||||
return Convert.ToInt32(countCommand.ExecuteScalar());
|
||||
}
|
||||
|
||||
|
||||
public SQLiteTransaction BeginTransaction()
|
||||
{
|
||||
return _connection.BeginTransaction();
|
||||
}
|
||||
|
||||
private SQLiteCommand BuildCommand(string format, params string[] args)
|
||||
{
|
||||
var command = new SQLiteCommand(string.Format(format, args));
|
||||
command.Connection = _connection;
|
||||
return command;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void ExecuteNonQuery(string command, params string[] args)
|
||||
{
|
||||
var sqLiteCommand = new SQLiteCommand(string.Format(command, args))
|
||||
{
|
||||
Connection = _connection
|
||||
};
|
||||
|
||||
sqLiteCommand.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
|
||||
public class SQLiteColumn
|
||||
{
|
||||
public string Name { get; set; }
|
||||
public string Schema { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("[{0}] {1}", Name, Schema);
|
||||
}
|
||||
}
|
||||
|
||||
public class SQLiteIndex
|
||||
{
|
||||
public string Column { get; set; }
|
||||
public string Table { get; set; }
|
||||
public bool Unique { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Format("[{0}] Unique: {1}", Column, Unique);
|
||||
}
|
||||
|
||||
public string IndexName
|
||||
{
|
||||
get
|
||||
{
|
||||
return string.Format("IX_{0}_{1}", Table, Column);
|
||||
}
|
||||
}
|
||||
|
||||
public string CreateSql(string tableName)
|
||||
{
|
||||
return string.Format(@"CREATE UNIQUE INDEX ""{2}"" ON ""{0}"" (""{1}"" ASC)", tableName, Column, IndexName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -56,16 +56,17 @@ namespace NzbDrone.Core.Datastore
|
|||
.Relationship()
|
||||
.HasOne(s => s.Profile, s => s.ProfileId);
|
||||
|
||||
Mapper.Entity<EpisodeFile>().RegisterModel("EpisodeFiles")
|
||||
.Ignore(f => f.Path)
|
||||
.Relationships.AutoMapICollectionOrComplexProperties();
|
||||
|
||||
Mapper.Entity<Episode>().RegisterModel("Episodes")
|
||||
.Ignore(e => e.SeriesTitle)
|
||||
.Ignore(e => e.Series)
|
||||
.Ignore(e => e.HasFile)
|
||||
.Relationship()
|
||||
.HasOne(episode => episode.EpisodeFile, episode => episode.EpisodeFileId);
|
||||
|
||||
Mapper.Entity<EpisodeFile>().RegisterModel("EpisodeFiles")
|
||||
.Relationships.AutoMapICollectionOrComplexProperties();
|
||||
|
||||
|
||||
Mapper.Entity<Profile>().RegisterModel("Profiles");
|
||||
Mapper.Entity<QualityDefinition>().RegisterModel("QualityDefinitions");
|
||||
Mapper.Entity<Log>().RegisterModel("Logs");
|
||||
|
|
|
@ -3,12 +3,11 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.Instrumentation.Extensions;
|
||||
using NzbDrone.Common.Serializer;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.Parser;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Qualities;
|
||||
|
||||
namespace NzbDrone.Core.DecisionEngine
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using System;
|
||||
using NLog;
|
||||
using NzbDrone.Common.EnsureThat;
|
||||
using NzbDrone.Core.Instrumentation.Extensions;
|
||||
using NzbDrone.Common.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common;
|
||||
|
@ -169,7 +170,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.EpisodeInfo.Path);
|
||||
history.Data.Add("ImportedPath", message.ImportedEpisode.Path);
|
||||
history.Data.Add("ImportedPath", Path.Combine(message.EpisodeInfo.Series.Path, message.ImportedEpisode.RelativePath));
|
||||
history.Data.Add("DownloadClient", message.DownloadClient);
|
||||
history.Data.Add("DownloadClientId", message.DownloadClientId);
|
||||
|
||||
|
|
|
@ -3,9 +3,9 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.Datastore;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Queue;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
|
|
@ -3,11 +3,11 @@ using System.Collections.Generic;
|
|||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.DataAugmentation.Scene;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.IndexerSearch.Definitions;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.Parser.Model;
|
||||
using NzbDrone.Core.Tv;
|
||||
using System.Linq;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using NLog;
|
||||
using NzbDrone.Common.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
|
||||
namespace NzbDrone.Core.IndexerSearch
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using NLog;
|
||||
using NzbDrone.Common.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.DecisionEngine;
|
||||
using NzbDrone.Core.Download;
|
||||
using NzbDrone.Core.Download.Pending;
|
||||
using NzbDrone.Core.IndexerSearch;
|
||||
using NzbDrone.Core.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.MediaFiles.Commands;
|
||||
using NzbDrone.Core.MediaFiles.EpisodeImport;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
|
|
|
@ -8,20 +8,26 @@ namespace NzbDrone.Core.MediaFiles
|
|||
{
|
||||
public class EpisodeFile : ModelBase
|
||||
{
|
||||
public int SeriesId { get; set; }
|
||||
public int SeasonNumber { get; set; }
|
||||
public string Path { get; set; }
|
||||
public long Size { get; set; }
|
||||
public Int32 SeriesId { get; set; }
|
||||
public Int32 SeasonNumber { get; set; }
|
||||
public String RelativePath { get; set; }
|
||||
public String Path { get; set; }
|
||||
public Int64 Size { get; set; }
|
||||
public DateTime DateAdded { get; set; }
|
||||
public string SceneName { get; set; }
|
||||
public string ReleaseGroup { get; set; }
|
||||
public String SceneName { get; set; }
|
||||
public String ReleaseGroup { get; set; }
|
||||
public QualityModel Quality { get; set; }
|
||||
public MediaInfoModel MediaInfo { get; set; }
|
||||
public LazyList<Episode> Episodes { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
public override String ToString()
|
||||
{
|
||||
return String.Format("[{0}] {1}", Id, Path);
|
||||
return String.Format("[{0}] {1}", Id, RelativePath);
|
||||
}
|
||||
//
|
||||
// public String Path(Series series)
|
||||
// {
|
||||
// return System.IO.Path.Combine(series.Path, RelativePath);
|
||||
// }
|
||||
}
|
||||
}
|
|
@ -50,7 +50,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
{
|
||||
var episodes = _episodeService.GetEpisodesByFileId(episodeFile.Id);
|
||||
var newFileName = _buildFileNames.BuildFileName(episodes, series, episodeFile);
|
||||
var filePath = _buildFileNames.BuildFilePath(series, episodes.First().SeasonNumber, newFileName, Path.GetExtension(episodeFile.Path));
|
||||
var filePath = _buildFileNames.BuildFilePath(series, episodes.First().SeasonNumber, newFileName, Path.GetExtension(episodeFile.RelativePath));
|
||||
|
||||
_logger.Debug("Renaming episode file: {0} to {1}", episodeFile, filePath);
|
||||
|
||||
|
@ -60,7 +60,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
public EpisodeFile MoveEpisodeFile(EpisodeFile episodeFile, LocalEpisode localEpisode)
|
||||
{
|
||||
var newFileName = _buildFileNames.BuildFileName(localEpisode.Episodes, localEpisode.Series, episodeFile);
|
||||
var filePath = _buildFileNames.BuildFilePath(localEpisode.Series, localEpisode.SeasonNumber, newFileName, Path.GetExtension(episodeFile.Path));
|
||||
var filePath = _buildFileNames.BuildFilePath(localEpisode.Series, localEpisode.SeasonNumber, newFileName, Path.GetExtension(localEpisode.Path));
|
||||
|
||||
_logger.Debug("Moving episode file: {0} to {1}", episodeFile, filePath);
|
||||
|
||||
|
@ -70,27 +70,29 @@ namespace NzbDrone.Core.MediaFiles
|
|||
public EpisodeFile CopyEpisodeFile(EpisodeFile episodeFile, LocalEpisode localEpisode)
|
||||
{
|
||||
var newFileName = _buildFileNames.BuildFileName(localEpisode.Episodes, localEpisode.Series, episodeFile);
|
||||
var filePath = _buildFileNames.BuildFilePath(localEpisode.Series, localEpisode.SeasonNumber, newFileName, Path.GetExtension(episodeFile.Path));
|
||||
var filePath = _buildFileNames.BuildFilePath(localEpisode.Series, localEpisode.SeasonNumber, newFileName, Path.GetExtension(localEpisode.Path));
|
||||
|
||||
_logger.Debug("Copying episode file: {0} to {1}", episodeFile, filePath);
|
||||
|
||||
return TransferFile(episodeFile, localEpisode.Series, localEpisode.Episodes, filePath, true);
|
||||
}
|
||||
|
||||
private EpisodeFile TransferFile(EpisodeFile episodeFile, Series series, List<Episode> episodes, string destinationFilename, bool copyOnly)
|
||||
private EpisodeFile TransferFile(EpisodeFile episodeFile, Series series, List<Episode> episodes, String destinationFilename, Boolean copyOnly)
|
||||
{
|
||||
Ensure.That(episodeFile, () => episodeFile).IsNotNull();
|
||||
Ensure.That(series,() => series).IsNotNull();
|
||||
Ensure.That(destinationFilename, () => destinationFilename).IsValidPath();
|
||||
|
||||
if (!_diskProvider.FileExists(episodeFile.Path))
|
||||
var episodeFilePath = episodeFile.Path ?? Path.Combine(series.Path, episodeFile.RelativePath);
|
||||
|
||||
if (!_diskProvider.FileExists(episodeFilePath))
|
||||
{
|
||||
throw new FileNotFoundException("Episode file path does not exist", episodeFile.Path);
|
||||
throw new FileNotFoundException("Episode file path does not exist", episodeFilePath);
|
||||
}
|
||||
|
||||
if (episodeFile.Path.PathEquals(destinationFilename))
|
||||
if (episodeFilePath.PathEquals(destinationFilename))
|
||||
{
|
||||
throw new SameFilenameException("File not moved, source and destination are the same", episodeFile.Path);
|
||||
throw new SameFilenameException("File not moved, source and destination are the same", episodeFilePath);
|
||||
}
|
||||
|
||||
var directoryName = new FileInfo(destinationFilename).DirectoryName;
|
||||
|
@ -116,15 +118,16 @@ namespace NzbDrone.Core.MediaFiles
|
|||
|
||||
if (copyOnly)
|
||||
{
|
||||
_logger.Debug("Copying [{0}] > [{1}]", episodeFile.Path, destinationFilename);
|
||||
_diskProvider.CopyFile(episodeFile.Path, destinationFilename);
|
||||
_logger.Debug("Copying [{0}] > [{1}]", episodeFilePath, destinationFilename);
|
||||
_diskProvider.CopyFile(episodeFilePath, destinationFilename);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Debug("Moving [{0}] > [{1}]", episodeFile.Path, destinationFilename);
|
||||
_diskProvider.MoveFile(episodeFile.Path, destinationFilename);
|
||||
_logger.Debug("Moving [{0}] > [{1}]", episodeFilePath, destinationFilename);
|
||||
_diskProvider.MoveFile(episodeFilePath, destinationFilename);
|
||||
}
|
||||
episodeFile.Path = destinationFilename;
|
||||
|
||||
episodeFile.RelativePath = series.Path.GetRelativePath(destinationFilename);
|
||||
|
||||
_updateEpisodeFileService.ChangeFileDateForFile(episodeFile, series, episodes);
|
||||
|
||||
|
|
|
@ -86,6 +86,11 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
|||
oldFiles = moveResult.OldFiles;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
episodeFile.RelativePath = localEpisode.Series.Path.GetRelativePath(episodeFile.Path);
|
||||
}
|
||||
|
||||
_mediaFileService.Add(episodeFile);
|
||||
imported.Add(importDecision);
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ namespace NzbDrone.Core.MediaFiles.EpisodeImport
|
|||
|
||||
public List<ImportDecision> GetImportDecisions(List<string> videoFiles, Series series, bool sceneSource, QualityModel quality = null)
|
||||
{
|
||||
var newFiles = _mediaFileService.FilterExistingFiles(videoFiles.ToList(), series.Id);
|
||||
var newFiles = _mediaFileService.FilterExistingFiles(videoFiles.ToList(), series);
|
||||
|
||||
_logger.Debug("Analyzing {0}/{1} files.", newFiles.Count, videoFiles.Count());
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Tv;
|
||||
using NzbDrone.Core.Tv.Events;
|
||||
using NzbDrone.Common;
|
||||
|
||||
|
@ -16,7 +18,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
List<EpisodeFile> GetFilesBySeries(int seriesId);
|
||||
List<EpisodeFile> GetFilesBySeason(int seriesId, int seasonNumber);
|
||||
List<EpisodeFile> GetFilesWithoutMediaInfo();
|
||||
List<string> FilterExistingFiles(List<string> files, int seriesId);
|
||||
List<string> FilterExistingFiles(List<string> files, Series series);
|
||||
EpisodeFile Get(int id);
|
||||
List<EpisodeFile> Get(IEnumerable<int> ids);
|
||||
}
|
||||
|
@ -68,9 +70,9 @@ namespace NzbDrone.Core.MediaFiles
|
|||
return _mediaFileRepository.GetFilesWithoutMediaInfo();
|
||||
}
|
||||
|
||||
public List<string> FilterExistingFiles(List<string> files, int seriesId)
|
||||
public List<string> FilterExistingFiles(List<string> files, Series series)
|
||||
{
|
||||
var seriesFiles = GetFilesBySeries(seriesId).Select(f => f.Path).ToList();
|
||||
var seriesFiles = GetFilesBySeries(series.Id).Select(f => Path.Combine(series.Path, f.RelativePath)).ToList();
|
||||
|
||||
if (!seriesFiles.Any()) return files;
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common;
|
||||
|
@ -39,25 +40,20 @@ namespace NzbDrone.Core.MediaFiles
|
|||
|
||||
foreach (var episodeFile in seriesFile)
|
||||
{
|
||||
var episodeFilePath = Path.Combine(series.Path, episodeFile.RelativePath);
|
||||
|
||||
try
|
||||
{
|
||||
if (!_diskProvider.FileExists(episodeFile.Path))
|
||||
if (!_diskProvider.FileExists(episodeFilePath))
|
||||
{
|
||||
_logger.Debug("File [{0}] no longer exists on disk, removing from db", episodeFile.Path);
|
||||
_logger.Debug("File [{0}] no longer exists on disk, removing from db", episodeFilePath);
|
||||
_mediaFileService.Delete(episodeFile);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!series.Path.IsParentPath(episodeFile.Path))
|
||||
{
|
||||
_logger.Debug("File [{0}] does not belong to this series, removing from db", episodeFile.Path);
|
||||
_mediaFileService.Delete(episodeFile);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!episodes.Any(e => e.EpisodeFileId == episodeFile.Id))
|
||||
{
|
||||
_logger.Debug("File [{0}] is not assigned to any episodes, removing from db", episodeFile.Path);
|
||||
_logger.Debug("File [{0}] is not assigned to any episodes, removing from db", episodeFilePath);
|
||||
_mediaFileService.Delete(episodeFile);
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -1,13 +1,11 @@
|
|||
using NLog;
|
||||
using System.IO;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Core.Lifecycle;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Tv;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace NzbDrone.Core.MediaFiles.MediaInfo
|
||||
{
|
||||
|
@ -29,11 +27,11 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
|
|||
_logger = logger;
|
||||
}
|
||||
|
||||
private void UpdateMediaInfo(List<EpisodeFile> mediaFiles)
|
||||
private void UpdateMediaInfo(Series series, List<EpisodeFile> mediaFiles)
|
||||
{
|
||||
foreach (var mediaFile in mediaFiles)
|
||||
{
|
||||
var path = mediaFile.Path;
|
||||
var path = Path.Combine(series.Path, mediaFile.RelativePath);
|
||||
|
||||
if (!_diskProvider.FileExists(path))
|
||||
{
|
||||
|
@ -57,7 +55,7 @@ namespace NzbDrone.Core.MediaFiles.MediaInfo
|
|||
.Where(c => c.MediaInfo == null)
|
||||
.ToList();
|
||||
|
||||
UpdateMediaInfo(mediaFiles);
|
||||
UpdateMediaInfo(message.Series, mediaFiles);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Core.Instrumentation.Extensions;
|
||||
using NzbDrone.Common.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.MediaFiles.Commands;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
|
@ -77,18 +77,19 @@ namespace NzbDrone.Core.MediaFiles
|
|||
{
|
||||
var file = f;
|
||||
var episodesInFile = episodes.Where(e => e.EpisodeFileId == file.Id).ToList();
|
||||
var episodeFilePath = Path.Combine(series.Path, file.RelativePath);
|
||||
|
||||
if (!episodesInFile.Any())
|
||||
{
|
||||
_logger.Warn("File ({0}) is not linked to any episodes", file.Path);
|
||||
_logger.Warn("File ({0}) is not linked to any episodes", episodeFilePath);
|
||||
continue;
|
||||
}
|
||||
|
||||
var seasonNumber = episodesInFile.First().SeasonNumber;
|
||||
var newName = _filenameBuilder.BuildFileName(episodesInFile, series, file);
|
||||
var newPath = _filenameBuilder.BuildFilePath(series, seasonNumber, newName, Path.GetExtension(file.Path));
|
||||
var newPath = _filenameBuilder.BuildFilePath(series, seasonNumber, newName, Path.GetExtension(episodeFilePath));
|
||||
|
||||
if (!file.Path.PathEquals(newPath))
|
||||
if (!episodeFilePath.PathEquals(newPath))
|
||||
{
|
||||
yield return new RenameEpisodeFilePreview
|
||||
{
|
||||
|
@ -96,7 +97,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
SeasonNumber = seasonNumber,
|
||||
EpisodeNumbers = episodesInFile.Select(e => e.EpisodeNumber).ToList(),
|
||||
EpisodeFileId = file.Id,
|
||||
ExistingPath = series.Path.GetRelativePath(file.Path),
|
||||
ExistingPath = file.RelativePath,
|
||||
NewPath = series.Path.GetRelativePath(newPath)
|
||||
};
|
||||
}
|
||||
|
@ -109,6 +110,8 @@ namespace NzbDrone.Core.MediaFiles
|
|||
|
||||
foreach (var episodeFile in episodeFiles)
|
||||
{
|
||||
var episodeFilePath = Path.Combine(series.Path, episodeFile.RelativePath);
|
||||
|
||||
try
|
||||
{
|
||||
_logger.Debug("Renaming episode file: {0}", episodeFile);
|
||||
|
@ -125,7 +128,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.ErrorException("Failed to rename file: " + episodeFile.Path, ex);
|
||||
_logger.ErrorException("Failed to rename file: " + episodeFilePath, ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.MediaFiles.Events;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
@ -43,6 +44,8 @@ namespace NzbDrone.Core.MediaFiles
|
|||
|
||||
private bool ChangeFileDate(EpisodeFile episodeFile, Series series, List<Episode> episodes)
|
||||
{
|
||||
var episodeFilePath = Path.Combine(series.Path, episodeFile.RelativePath);
|
||||
|
||||
switch (_configService.FileDate)
|
||||
{
|
||||
case FileDateType.LocalAirDate:
|
||||
|
@ -55,7 +58,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
return false;
|
||||
}
|
||||
|
||||
return ChangeFileDateToLocalAirDate(episodeFile.Path, airDate, airTime);
|
||||
return ChangeFileDateToLocalAirDate(episodeFilePath, airDate, airTime);
|
||||
}
|
||||
|
||||
case FileDateType.UtcAirDate:
|
||||
|
@ -67,7 +70,7 @@ namespace NzbDrone.Core.MediaFiles
|
|||
return false;
|
||||
}
|
||||
|
||||
return ChangeFileDateToUtcAirDate(episodeFile.Path, airDateUtc.Value);
|
||||
return ChangeFileDateToUtcAirDate(episodeFilePath, airDateUtc.Value);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Linq;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.Disk;
|
||||
|
@ -43,11 +44,12 @@ namespace NzbDrone.Core.MediaFiles
|
|||
foreach (var existingFile in existingFiles)
|
||||
{
|
||||
var file = existingFile.First();
|
||||
var episodeFilePath = Path.Combine(localEpisode.Series.Path, file.RelativePath);
|
||||
|
||||
if (_diskProvider.FileExists(file.Path))
|
||||
if (_diskProvider.FileExists(episodeFilePath))
|
||||
{
|
||||
_logger.Debug("Removing existing episode file: {0}", file);
|
||||
_recycleBinProvider.DeleteFile(file.Path);
|
||||
_recycleBinProvider.DeleteFile(episodeFilePath);
|
||||
}
|
||||
|
||||
moveFileResult.OldFiles.Add(file);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
using System.Threading;
|
||||
using NLog;
|
||||
using NzbDrone.Core.Instrumentation.Extensions;
|
||||
using NzbDrone.Common.Instrumentation.Extensions;
|
||||
|
||||
namespace NzbDrone.Core.Messaging.Commands
|
||||
{
|
||||
|
|
|
@ -49,12 +49,12 @@ namespace NzbDrone.Core.Metadata.Consumers.Roksbox
|
|||
|
||||
if (metadataFile.Type == MetadataType.EpisodeImage)
|
||||
{
|
||||
newFilename = GetEpisodeImageFilename(episodeFile.Path);
|
||||
newFilename = GetEpisodeImageFilename(episodeFile.RelativePath);
|
||||
}
|
||||
|
||||
else if (metadataFile.Type == MetadataType.EpisodeMetadata)
|
||||
{
|
||||
newFilename = GetEpisodeMetadataFilename(episodeFile.Path);
|
||||
newFilename = GetEpisodeMetadataFilename(episodeFile.RelativePath);
|
||||
}
|
||||
|
||||
else
|
||||
|
@ -64,6 +64,7 @@ namespace NzbDrone.Core.Metadata.Consumers.Roksbox
|
|||
}
|
||||
|
||||
var existingFilename = Path.Combine(series.Path, metadataFile.RelativePath);
|
||||
newFilename = Path.Combine(series.Path, newFilename);
|
||||
|
||||
if (!newFilename.PathEquals(existingFilename))
|
||||
{
|
||||
|
@ -159,8 +160,8 @@ namespace NzbDrone.Core.Metadata.Consumers.Roksbox
|
|||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
_logger.Debug("Generating Episode Metadata for: {0}", episodeFile.Path);
|
||||
|
||||
_logger.Debug("Generating Episode Metadata for: {0}", episodeFile.RelativePath);
|
||||
|
||||
var xmlResult = String.Empty;
|
||||
foreach (var episode in episodeFile.Episodes.Value)
|
||||
|
@ -191,7 +192,7 @@ namespace NzbDrone.Core.Metadata.Consumers.Roksbox
|
|||
}
|
||||
}
|
||||
|
||||
return new MetadataFileResult(GetEpisodeMetadataFilename(episodeFile.Path), xmlResult.Trim(Environment.NewLine.ToCharArray()));
|
||||
return new MetadataFileResult(GetEpisodeMetadataFilename(episodeFile.RelativePath), xmlResult.Trim(Environment.NewLine.ToCharArray()));
|
||||
}
|
||||
|
||||
public override List<ImageFileResult> SeriesImages(Series series)
|
||||
|
@ -244,7 +245,7 @@ namespace NzbDrone.Core.Metadata.Consumers.Roksbox
|
|||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
return new List<ImageFileResult> {new ImageFileResult(GetEpisodeImageFilename(episodeFile.Path), screenshot.Url)};
|
||||
return new List<ImageFileResult> {new ImageFileResult(GetEpisodeImageFilename(episodeFile.RelativePath), screenshot.Url)};
|
||||
}
|
||||
|
||||
private string GetEpisodeMetadataFilename(string episodeFilePath)
|
||||
|
|
|
@ -48,12 +48,12 @@ namespace NzbDrone.Core.Metadata.Consumers.Wdtv
|
|||
|
||||
if (metadataFile.Type == MetadataType.EpisodeImage)
|
||||
{
|
||||
newFilename = GetEpisodeImageFilename(episodeFile.Path);
|
||||
newFilename = GetEpisodeImageFilename(episodeFile.RelativePath);
|
||||
}
|
||||
|
||||
else if (metadataFile.Type == MetadataType.EpisodeMetadata)
|
||||
{
|
||||
newFilename = GetEpisodeMetadataFilename(episodeFile.Path);
|
||||
newFilename = GetEpisodeMetadataFilename(episodeFile.RelativePath);
|
||||
}
|
||||
|
||||
else
|
||||
|
@ -63,6 +63,7 @@ namespace NzbDrone.Core.Metadata.Consumers.Wdtv
|
|||
}
|
||||
|
||||
var existingFilename = Path.Combine(series.Path, metadataFile.RelativePath);
|
||||
newFilename = Path.Combine(series.Path, newFilename);
|
||||
|
||||
if (!newFilename.PathEquals(existingFilename))
|
||||
{
|
||||
|
@ -151,7 +152,7 @@ namespace NzbDrone.Core.Metadata.Consumers.Wdtv
|
|||
return null;
|
||||
}
|
||||
|
||||
_logger.Debug("Generating Episode Metadata for: {0}", episodeFile.Path);
|
||||
_logger.Debug("Generating Episode Metadata for: {0}", Path.Combine(series.Path, episodeFile.RelativePath));
|
||||
|
||||
var xmlResult = String.Empty;
|
||||
foreach (var episode in episodeFile.Episodes.Value)
|
||||
|
@ -190,7 +191,7 @@ namespace NzbDrone.Core.Metadata.Consumers.Wdtv
|
|||
}
|
||||
}
|
||||
|
||||
var filename = GetEpisodeMetadataFilename(episodeFile.Path);
|
||||
var filename = GetEpisodeMetadataFilename(episodeFile.RelativePath);
|
||||
|
||||
return new MetadataFileResult(filename, xmlResult.Trim(Environment.NewLine.ToCharArray()));
|
||||
}
|
||||
|
@ -264,7 +265,7 @@ namespace NzbDrone.Core.Metadata.Consumers.Wdtv
|
|||
return new List<ImageFileResult>();
|
||||
}
|
||||
|
||||
return new List<ImageFileResult>{ new ImageFileResult(GetEpisodeImageFilename(episodeFile.Path), screenshot.Url) };
|
||||
return new List<ImageFileResult>{ new ImageFileResult(GetEpisodeImageFilename(episodeFile.RelativePath), screenshot.Url) };
|
||||
}
|
||||
|
||||
private string GetEpisodeMetadataFilename(string episodeFilePath)
|
||||
|
|
|
@ -50,12 +50,12 @@ namespace NzbDrone.Core.Metadata.Consumers.Xbmc
|
|||
|
||||
if (metadataFile.Type == MetadataType.EpisodeImage)
|
||||
{
|
||||
newFilename = GetEpisodeImageFilename(episodeFile.Path);
|
||||
newFilename = GetEpisodeImageFilename(episodeFile.RelativePath);
|
||||
}
|
||||
|
||||
else if (metadataFile.Type == MetadataType.EpisodeMetadata)
|
||||
{
|
||||
newFilename = GetEpisodeNfoFilename(episodeFile.Path);
|
||||
newFilename = GetEpisodeNfoFilename(episodeFile.RelativePath);
|
||||
}
|
||||
|
||||
else
|
||||
|
@ -65,6 +65,7 @@ namespace NzbDrone.Core.Metadata.Consumers.Xbmc
|
|||
}
|
||||
|
||||
var existingFilename = Path.Combine(series.Path, metadataFile.RelativePath);
|
||||
newFilename = Path.Combine(series.Path, newFilename);
|
||||
|
||||
if (!newFilename.PathEquals(existingFilename))
|
||||
{
|
||||
|
@ -214,7 +215,7 @@ namespace NzbDrone.Core.Metadata.Consumers.Xbmc
|
|||
return null;
|
||||
}
|
||||
|
||||
_logger.Debug("Generating Episode Metadata for: {0}", episodeFile.Path);
|
||||
_logger.Debug("Generating Episode Metadata for: {0}", Path.Combine(series.Path, episodeFile.RelativePath));
|
||||
|
||||
var xmlResult = String.Empty;
|
||||
foreach (var episode in episodeFile.Episodes.Value)
|
||||
|
@ -265,7 +266,7 @@ namespace NzbDrone.Core.Metadata.Consumers.Xbmc
|
|||
}
|
||||
}
|
||||
|
||||
return new MetadataFileResult(GetEpisodeNfoFilename(episodeFile.Path), xmlResult.Trim(Environment.NewLine.ToCharArray()));
|
||||
return new MetadataFileResult(GetEpisodeNfoFilename(episodeFile.RelativePath), xmlResult.Trim(Environment.NewLine.ToCharArray()));
|
||||
}
|
||||
|
||||
public override List<ImageFileResult> SeriesImages(Series series)
|
||||
|
@ -305,7 +306,7 @@ namespace NzbDrone.Core.Metadata.Consumers.Xbmc
|
|||
|
||||
return new List<ImageFileResult>
|
||||
{
|
||||
new ImageFileResult(GetEpisodeImageFilename(episodeFile.Path), screenshot.Url)
|
||||
new ImageFileResult(GetEpisodeImageFilename(episodeFile.RelativePath), screenshot.Url)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -174,18 +174,18 @@ namespace NzbDrone.Core.Metadata
|
|||
return null;
|
||||
}
|
||||
|
||||
var relativePath = series.Path.GetRelativePath(episodeMetadata.Path);
|
||||
var fullPath = Path.Combine(series.Path, episodeMetadata.Path);
|
||||
|
||||
var existingMetadata = existingMetadataFiles.SingleOrDefault(c => c.Type == MetadataType.EpisodeMetadata &&
|
||||
c.EpisodeFileId == episodeFile.Id);
|
||||
|
||||
if (existingMetadata != null)
|
||||
{
|
||||
var fullPath = Path.Combine(series.Path, existingMetadata.RelativePath);
|
||||
if (!episodeMetadata.Path.PathEquals(fullPath))
|
||||
var existingFullPath = Path.Combine(series.Path, existingMetadata.RelativePath);
|
||||
if (!episodeMetadata.Path.PathEquals(existingFullPath))
|
||||
{
|
||||
_diskProvider.MoveFile(fullPath, episodeMetadata.Path);
|
||||
existingMetadata.RelativePath = relativePath;
|
||||
_diskProvider.MoveFile(existingFullPath, fullPath);
|
||||
existingMetadata.RelativePath = episodeMetadata.Path;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,7 +198,7 @@ namespace NzbDrone.Core.Metadata
|
|||
EpisodeFileId = episodeFile.Id,
|
||||
Consumer = consumer.GetType().Name,
|
||||
Type = MetadataType.EpisodeMetadata,
|
||||
RelativePath = relativePath
|
||||
RelativePath = episodeMetadata.Path
|
||||
};
|
||||
|
||||
if (hash == metadata.Hash)
|
||||
|
@ -206,8 +206,8 @@ namespace NzbDrone.Core.Metadata
|
|||
return null;
|
||||
}
|
||||
|
||||
_logger.Debug("Writing Episode Metadata to: {0}", episodeMetadata.Path);
|
||||
_diskProvider.WriteAllText(episodeMetadata.Path, episodeMetadata.Contents);
|
||||
_logger.Debug("Writing Episode Metadata to: {0}", fullPath);
|
||||
_diskProvider.WriteAllText(fullPath, episodeMetadata.Contents);
|
||||
|
||||
metadata.Hash = hash;
|
||||
|
||||
|
@ -289,24 +289,24 @@ namespace NzbDrone.Core.Metadata
|
|||
|
||||
foreach (var image in consumer.EpisodeImages(series, episodeFile))
|
||||
{
|
||||
var fullPath = Path.Combine(series.Path, image.Path);
|
||||
|
||||
if (_diskProvider.FileExists(image.Path))
|
||||
{
|
||||
_logger.Debug("Episode image already exists: {0}", image.Path);
|
||||
continue;
|
||||
}
|
||||
|
||||
var relativePath = series.Path.GetRelativePath(image.Path);
|
||||
|
||||
var existingMetadata = existingMetadataFiles.FirstOrDefault(c => c.Type == MetadataType.EpisodeImage &&
|
||||
c.EpisodeFileId == episodeFile.Id);
|
||||
|
||||
if (existingMetadata != null)
|
||||
{
|
||||
var fullPath = Path.Combine(series.Path, existingMetadata.RelativePath);
|
||||
if (!image.Path.PathEquals(fullPath))
|
||||
var existingFullPath = Path.Combine(series.Path, existingMetadata.RelativePath);
|
||||
if (!fullPath.PathEquals(existingFullPath))
|
||||
{
|
||||
_diskProvider.MoveFile(fullPath, image.Path);
|
||||
existingMetadata.RelativePath = relativePath;
|
||||
_diskProvider.MoveFile(fullPath, fullPath);
|
||||
existingMetadata.RelativePath = image.Path;
|
||||
|
||||
return new List<MetadataFile>{ existingMetadata };
|
||||
}
|
||||
|
|
|
@ -215,6 +215,8 @@
|
|||
<Compile Include="Datastore\Migration\054_rename_profiles.cs" />
|
||||
<Compile Include="Datastore\Migration\055_drop_old_profile_columns.cs" />
|
||||
<Compile Include="Datastore\Migration\056_add_mediainfo_to_episodefile.cs" />
|
||||
<Compile Include="Datastore\Migration\057_convert_episode_file_path_to_relative.cs" />
|
||||
<Compile Include="Datastore\Migration\058_drop_epsiode_file_path.cs" />
|
||||
<Compile Include="Datastore\Migration\Framework\MigrationContext.cs" />
|
||||
<Compile Include="Datastore\Migration\Framework\MigrationController.cs" />
|
||||
<Compile Include="Datastore\Migration\Framework\MigrationExtension.cs" />
|
||||
|
@ -427,7 +429,6 @@
|
|||
<Compile Include="Instrumentation\Commands\TrimLogCommand.cs" />
|
||||
<Compile Include="Instrumentation\DatabaseTarget.cs" />
|
||||
<Compile Include="Instrumentation\DeleteLogFilesService.cs" />
|
||||
<Compile Include="Instrumentation\Extensions\LoggerProgressExtensions.cs" />
|
||||
<Compile Include="Instrumentation\Log.cs" />
|
||||
<Compile Include="Instrumentation\LogRepository.cs" />
|
||||
<Compile Include="Instrumentation\LogService.cs" />
|
||||
|
@ -701,6 +702,7 @@
|
|||
<Compile Include="ThingiProvider\ProviderFactory.cs" />
|
||||
<Compile Include="ThingiProvider\ProviderRepository.cs" />
|
||||
<Compile Include="Tv\Actor.cs" />
|
||||
<Compile Include="Tv\Commands\MoveSeriesCommand.cs" />
|
||||
<Compile Include="Tv\Commands\RefreshSeriesCommand.cs" />
|
||||
<Compile Include="Tv\Episode.cs" />
|
||||
<Compile Include="Tv\EpisodeCutoffService.cs" />
|
||||
|
@ -714,8 +716,10 @@
|
|||
<Compile Include="Tv\Events\SeriesAddedEvent.cs" />
|
||||
<Compile Include="Tv\Events\SeriesDeletedEvent.cs" />
|
||||
<Compile Include="Tv\Events\SeriesEditedEvent.cs" />
|
||||
<Compile Include="Tv\Events\SeriesMovedEvent.cs" />
|
||||
<Compile Include="Tv\Events\SeriesRefreshStartingEvent.cs" />
|
||||
<Compile Include="Tv\Events\SeriesUpdatedEvent.cs" />
|
||||
<Compile Include="Tv\MoveSeriesService.cs" />
|
||||
<Compile Include="Tv\Ratings.cs" />
|
||||
<Compile Include="Tv\RefreshEpisodeService.cs" />
|
||||
<Compile Include="Tv\RefreshSeriesService.cs" />
|
||||
|
|
|
@ -6,6 +6,7 @@ using System.Text.RegularExpressions;
|
|||
using NLog;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.Cache;
|
||||
using NzbDrone.Common.EnsureThat;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Qualities;
|
||||
using NzbDrone.Core.Tv;
|
||||
|
@ -77,7 +78,7 @@ namespace NzbDrone.Core.Organizer
|
|||
{
|
||||
if (episodeFile.SceneName.IsNullOrWhiteSpace())
|
||||
{
|
||||
return Path.GetFileNameWithoutExtension(episodeFile.Path);
|
||||
return Path.GetFileNameWithoutExtension(episodeFile.RelativePath);
|
||||
}
|
||||
|
||||
return episodeFile.SceneName;
|
||||
|
@ -204,6 +205,8 @@ namespace NzbDrone.Core.Organizer
|
|||
|
||||
public string BuildFilePath(Series series, int seasonNumber, string fileName, string extension)
|
||||
{
|
||||
Ensure.That(extension, () => extension).IsNotNullOrWhiteSpace();
|
||||
|
||||
string path = series.Path;
|
||||
|
||||
if (series.SeasonFolder)
|
||||
|
|
|
@ -93,7 +93,7 @@ namespace NzbDrone.Core.Organizer
|
|||
_singleEpisodeFile = new EpisodeFile
|
||||
{
|
||||
Quality = new QualityModel(Quality.HDTV720p),
|
||||
Path = @"C:\Test\Series.Title.S01E01.720p.HDTV.x264-EVOLVE.mkv",
|
||||
RelativePath = "Series.Title.S01E01.720p.HDTV.x264-EVOLVE.mkv",
|
||||
ReleaseGroup = "RlsGrp",
|
||||
MediaInfo = mediaInfo
|
||||
};
|
||||
|
@ -101,7 +101,7 @@ namespace NzbDrone.Core.Organizer
|
|||
_multiEpisodeFile = new EpisodeFile
|
||||
{
|
||||
Quality = new QualityModel(Quality.HDTV720p),
|
||||
Path = @"C:\Test\Series.Title.S01E01-E02.720p.HDTV.x264-EVOLVE.mkv",
|
||||
RelativePath = "Series.Title.S01E01-E02.720p.HDTV.x264-EVOLVE.mkv",
|
||||
ReleaseGroup = "RlsGrp",
|
||||
MediaInfo = mediaInfo
|
||||
};
|
||||
|
@ -109,7 +109,7 @@ namespace NzbDrone.Core.Organizer
|
|||
_dailyEpisodeFile = new EpisodeFile
|
||||
{
|
||||
Quality = new QualityModel(Quality.HDTV720p),
|
||||
Path = @"C:\Test\Series.Title.2013.10.30.HDTV.x264-EVOLVE.mkv",
|
||||
RelativePath = "Series.Title.2013.10.30.HDTV.x264-EVOLVE.mkv",
|
||||
ReleaseGroup = "RlsGrp",
|
||||
MediaInfo = mediaInfo
|
||||
};
|
||||
|
@ -117,7 +117,7 @@ namespace NzbDrone.Core.Organizer
|
|||
_animeEpisodeFile = new EpisodeFile
|
||||
{
|
||||
Quality = new QualityModel(Quality.HDTV720p),
|
||||
Path = @"C:\Test\Series.Title.001.HDTV.x264-EVOLVE.mkv",
|
||||
RelativePath = "Series.Title.001.HDTV.x264-EVOLVE.mkv",
|
||||
ReleaseGroup = "RlsGrp",
|
||||
MediaInfo = mediaInfoAnime
|
||||
};
|
||||
|
|
|
@ -8,7 +8,6 @@ using NzbDrone.Core.Messaging.Events;
|
|||
|
||||
namespace NzbDrone.Core.ProgressMessaging
|
||||
{
|
||||
|
||||
public class ProgressMessageTarget : Target, IHandle<ApplicationStartedEvent>
|
||||
{
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
|
||||
namespace NzbDrone.Core.Tv.Commands
|
||||
{
|
||||
public class MoveSeriesCommand : Command
|
||||
{
|
||||
public Int32 SeriesId { get; set; }
|
||||
public String SourcePath { get; set; }
|
||||
public String DestinationPath { get; set; }
|
||||
public String DestinationRootFolder { get; set; }
|
||||
}
|
||||
}
|
|
@ -199,7 +199,7 @@ namespace NzbDrone.Core.Tv
|
|||
foreach (var episode in message.EpisodeFile.Episodes.Value)
|
||||
{
|
||||
_episodeRepository.SetFileId(episode.Id, message.EpisodeFile.Id);
|
||||
_logger.Debug("Linking [{0}] > [{1}]", message.EpisodeFile.Path, episode);
|
||||
_logger.Debug("Linking [{0}] > [{1}]", message.EpisodeFile.RelativePath, episode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
using System;
|
||||
using NzbDrone.Common.Messaging;
|
||||
|
||||
namespace NzbDrone.Core.Tv.Events
|
||||
{
|
||||
public class SeriesMovedEvent : IEvent
|
||||
{
|
||||
public Series Series { get; set; }
|
||||
public String SourcePath { get; set; }
|
||||
public String DestinationPath { get; set; }
|
||||
|
||||
public SeriesMovedEvent(Series series, string sourcePath, string destinationPath)
|
||||
{
|
||||
Series = series;
|
||||
SourcePath = sourcePath;
|
||||
DestinationPath = destinationPath;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using NLog;
|
||||
using NzbDrone.Common;
|
||||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
using NzbDrone.Core.Organizer;
|
||||
using NzbDrone.Core.Tv.Commands;
|
||||
using NzbDrone.Core.Tv.Events;
|
||||
|
||||
namespace NzbDrone.Core.Tv
|
||||
{
|
||||
public class MoveSeriesService : IExecute<MoveSeriesCommand>
|
||||
{
|
||||
private readonly ISeriesService _seriesService;
|
||||
private readonly IBuildFileNames _filenameBuilder;
|
||||
private readonly IDiskProvider _diskProvider;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly Logger _logger;
|
||||
|
||||
public MoveSeriesService(ISeriesService seriesService,
|
||||
IBuildFileNames filenameBuilder,
|
||||
IDiskProvider diskProvider,
|
||||
IEventAggregator eventAggregator,
|
||||
Logger logger)
|
||||
{
|
||||
_seriesService = seriesService;
|
||||
_filenameBuilder = filenameBuilder;
|
||||
_diskProvider = diskProvider;
|
||||
_eventAggregator = eventAggregator;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void Execute(MoveSeriesCommand message)
|
||||
{
|
||||
var series = _seriesService.GetSeries(message.SeriesId);
|
||||
var source = message.SourcePath;
|
||||
var destination = message.DestinationPath;
|
||||
|
||||
if (!message.DestinationRootFolder.IsNullOrWhiteSpace())
|
||||
{
|
||||
_logger.Debug("Buiding destination path using root folder: {0} and the series title", message.DestinationRootFolder);
|
||||
destination = Path.Combine(message.DestinationRootFolder, _filenameBuilder.GetSeriesFolder(series));
|
||||
}
|
||||
|
||||
_logger.ProgressInfo("Moving {0} from '{1}' to '{2}'", series.Title, source, destination);
|
||||
|
||||
//TODO: Move to transactional disk operations
|
||||
try
|
||||
{
|
||||
_diskProvider.MoveFolder(source, destination);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
var errorMessage = String.Format("Unable to move series from '{0}' to '{1}'", source, destination);
|
||||
|
||||
_logger.ErrorException(errorMessage, ex);
|
||||
throw;
|
||||
}
|
||||
|
||||
_logger.ProgressInfo("{0} moved successfully to {1}", series.Title, series.Path);
|
||||
|
||||
//Update the series path to the new path
|
||||
series.Path = destination;
|
||||
series = _seriesService.UpdateSeries(series);
|
||||
|
||||
_eventAggregator.PublishEvent(new SeriesMovedEvent(series, source, destination));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,8 +3,8 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using NLog;
|
||||
using NzbDrone.Common.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.DataAugmentation.DailySeries;
|
||||
using NzbDrone.Core.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.MediaFiles;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Messaging.Events;
|
||||
|
|
|
@ -16,8 +16,6 @@ namespace NzbDrone.Core.Tv
|
|||
|
||||
public void Handle(SeriesEditedEvent message)
|
||||
{
|
||||
//TODO: Refresh if path has changed (also move files)
|
||||
|
||||
if (message.Series.SeriesType != message.OldSeries.SeriesType)
|
||||
{
|
||||
_commandExecutor.PublishCommandAsync(new RefreshSeriesCommand(message.Series.Id));
|
||||
|
|
|
@ -5,10 +5,10 @@ using NzbDrone.Common;
|
|||
using NzbDrone.Common.Disk;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Common.Http;
|
||||
using NzbDrone.Common.Instrumentation.Extensions;
|
||||
using NzbDrone.Common.Processes;
|
||||
using NzbDrone.Core.Backup;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
using NzbDrone.Core.Update.Commands;
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using NLog;
|
||||
using NzbDrone.Common.EnvironmentInfo;
|
||||
using NzbDrone.Common.Instrumentation.Extensions;
|
||||
using NzbDrone.Core.Configuration;
|
||||
using NzbDrone.Core.Instrumentation.Extensions;
|
||||
|
||||
namespace NzbDrone.Core.Update
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue