Merge branch 'develop' of github.com:NzbDrone/NzbDrone into develop
This commit is contained in:
commit
b53476520f
|
@ -93,7 +93,6 @@ namespace NzbDrone.Common
|
||||||
{
|
{
|
||||||
Ensure.That(() => path).IsValidPath();
|
Ensure.That(() => path).IsValidPath();
|
||||||
|
|
||||||
|
|
||||||
if (!FileExists(path))
|
if (!FileExists(path))
|
||||||
throw new FileNotFoundException("File doesn't exist: " + path);
|
throw new FileNotFoundException("File doesn't exist: " + path);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using FizzWare.NBuilder;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Marr.Data;
|
||||||
|
using Moq;
|
||||||
|
using Newtonsoft.Json.Serialization;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using NzbDrone.Common;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
|
using NzbDrone.Core.MediaFiles;
|
||||||
|
using NzbDrone.Core.MediaFiles.EpisodeImport.Specifications;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
using NzbDrone.Core.Test.Framework;
|
||||||
|
using NzbDrone.Core.Tv;
|
||||||
|
using NzbDrone.Test.Common;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.Test.MediaFileTests.EpisodeImportTests
|
||||||
|
{
|
||||||
|
[TestFixture]
|
||||||
|
public class NotUnpackingSpecificationFixture : CoreTest<NotUnpackingSpecification>
|
||||||
|
{
|
||||||
|
private LocalEpisode _localEpisode;
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void Setup()
|
||||||
|
{
|
||||||
|
Mocker.GetMock<IConfigService>()
|
||||||
|
.SetupGet(s => s.DownloadClientWorkingFolders)
|
||||||
|
.Returns("_UNPACK_|_FAILED_");
|
||||||
|
|
||||||
|
_localEpisode = new LocalEpisode
|
||||||
|
{
|
||||||
|
Path = @"C:\Test\Unsorted TV\30.rock\30.rock.s01e01.avi".AsOsAgnostic(),
|
||||||
|
Size = 100,
|
||||||
|
Series = Builder<Series>.CreateNew().Build()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenInWorkingFolder()
|
||||||
|
{
|
||||||
|
_localEpisode.Path = @"C:\Test\Unsorted TV\_UNPACK_30.rock\30.rock.s01e01.avi".AsOsAgnostic();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GivenLastWriteTimeUtc(DateTime time)
|
||||||
|
{
|
||||||
|
Mocker.GetMock<IDiskProvider>()
|
||||||
|
.Setup(s => s.GetLastFileWrite(It.IsAny<string>()))
|
||||||
|
.Returns(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_return_true_if_not_in_working_folder()
|
||||||
|
{
|
||||||
|
Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_return_true_when_in_old_working_folder()
|
||||||
|
{
|
||||||
|
GivenInWorkingFolder();
|
||||||
|
GivenLastWriteTimeUtc(DateTime.UtcNow.AddHours(-1));
|
||||||
|
|
||||||
|
Subject.IsSatisfiedBy(_localEpisode).Should().BeTrue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_return_false_if_in_working_folder_and_last_write_time_was_recent()
|
||||||
|
{
|
||||||
|
GivenInWorkingFolder();
|
||||||
|
GivenLastWriteTimeUtc(DateTime.UtcNow);
|
||||||
|
|
||||||
|
Subject.IsSatisfiedBy(_localEpisode).Should().BeFalse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -132,6 +132,7 @@
|
||||||
<Compile Include="JobTests\TestJobs.cs" />
|
<Compile Include="JobTests\TestJobs.cs" />
|
||||||
<Compile Include="MediaCoverTests\CoverExistsSpecificationFixture.cs" />
|
<Compile Include="MediaCoverTests\CoverExistsSpecificationFixture.cs" />
|
||||||
<Compile Include="MediaCoverTests\MediaCoverServiceFixture.cs" />
|
<Compile Include="MediaCoverTests\MediaCoverServiceFixture.cs" />
|
||||||
|
<Compile Include="MediaFileTests\EpisodeImportTests\NotUnpackingSpecificationFixture.cs" />
|
||||||
<Compile Include="MediaFileTests\EpisodeImportTests\NotInUseSpecificationFixture.cs" />
|
<Compile Include="MediaFileTests\EpisodeImportTests\NotInUseSpecificationFixture.cs" />
|
||||||
<Compile Include="MediaFileTests\EpisodeImportTests\FreeSpaceSpecificationFixture.cs" />
|
<Compile Include="MediaFileTests\EpisodeImportTests\FreeSpaceSpecificationFixture.cs" />
|
||||||
<Compile Include="MediaFileTests\RenameEpisodeFileServiceFixture.cs" />
|
<Compile Include="MediaFileTests\RenameEpisodeFileServiceFixture.cs" />
|
||||||
|
|
|
@ -78,7 +78,8 @@ namespace NzbDrone.Core.Test.ParserTests
|
||||||
new object[] { "POI S02E11 1080i HDTV DD5.1 MPEG2-TrollHD", Quality.RAWHD, false },
|
new object[] { "POI S02E11 1080i HDTV DD5.1 MPEG2-TrollHD", Quality.RAWHD, false },
|
||||||
new object[] { "How I Met Your Mother S01E18 Nothing Good Happens After 2 A.M. 720p HDTV DD5.1 MPEG2-TrollHD", Quality.RAWHD, false },
|
new object[] { "How I Met Your Mother S01E18 Nothing Good Happens After 2 A.M. 720p HDTV DD5.1 MPEG2-TrollHD", Quality.RAWHD, false },
|
||||||
new object[] { "Arrested.Development.S04E01.iNTERNAL.1080p.WEBRip.x264-QRUS", Quality.WEBDL1080p, false },
|
new object[] { "Arrested.Development.S04E01.iNTERNAL.1080p.WEBRip.x264-QRUS", Quality.WEBDL1080p, false },
|
||||||
new object[] { "Arrested.Development.S04E01.720p.WEBRip.AAC2.0.x264-NFRiP", Quality.WEBDL720p, false }
|
new object[] { "Arrested.Development.S04E01.720p.WEBRip.AAC2.0.x264-NFRiP", Quality.WEBDL720p, false },
|
||||||
|
new object[] { "Sons.Of.Anarchy.S02E13.1080p.BluRay.x264-AVCDVD", Quality.Bluray1080p, false }
|
||||||
};
|
};
|
||||||
|
|
||||||
public static object[] SelfQualityParserCases =
|
public static object[] SelfQualityParserCases =
|
||||||
|
|
|
@ -258,6 +258,12 @@ namespace NzbDrone.Core.Configuration
|
||||||
set { SetValue("AutoDownloadPropers", value); }
|
set { SetValue("AutoDownloadPropers", value); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string DownloadClientWorkingFolders
|
||||||
|
{
|
||||||
|
get { return GetValue("DownloadClientWorkingFolders", "_UNPACK_|_FAILED_"); }
|
||||||
|
set { SetValue("DownloadClientWorkingFolders", value); }
|
||||||
|
}
|
||||||
|
|
||||||
private string GetValue(string key)
|
private string GetValue(string key)
|
||||||
{
|
{
|
||||||
return GetValue(key, String.Empty);
|
return GetValue(key, String.Empty);
|
||||||
|
|
|
@ -38,6 +38,7 @@ namespace NzbDrone.Core.Configuration
|
||||||
string ReleaseRestrictions { get; set; }
|
string ReleaseRestrictions { get; set; }
|
||||||
Int32 RssSyncInterval { get; set; }
|
Int32 RssSyncInterval { get; set; }
|
||||||
Boolean AutoDownloadPropers { get; set; }
|
Boolean AutoDownloadPropers { get; set; }
|
||||||
|
String DownloadClientWorkingFolders { get; set; }
|
||||||
void SaveValues(Dictionary<string, object> configValues);
|
void SaveValues(Dictionary<string, object> configValues);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using NLog;
|
||||||
|
using NzbDrone.Common;
|
||||||
|
using NzbDrone.Core.Configuration;
|
||||||
|
using NzbDrone.Core.Parser.Model;
|
||||||
|
|
||||||
|
namespace NzbDrone.Core.MediaFiles.EpisodeImport.Specifications
|
||||||
|
{
|
||||||
|
public class NotUnpackingSpecification : IImportDecisionEngineSpecification
|
||||||
|
{
|
||||||
|
private readonly IDiskProvider _diskProvider;
|
||||||
|
private readonly IConfigService _configService;
|
||||||
|
private readonly Logger _logger;
|
||||||
|
|
||||||
|
public NotUnpackingSpecification(IDiskProvider diskProvider, IConfigService configService, Logger logger)
|
||||||
|
{
|
||||||
|
_diskProvider = diskProvider;
|
||||||
|
_configService = configService;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string RejectionReason { get { return "File is still being unpacked"; } }
|
||||||
|
|
||||||
|
public bool IsSatisfiedBy(LocalEpisode localEpisode)
|
||||||
|
{
|
||||||
|
if (_diskProvider.IsParent(localEpisode.Series.Path, localEpisode.Path))
|
||||||
|
{
|
||||||
|
_logger.Trace("{0} is in series folder, unpacking check", localEpisode.Path);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var workingFolder in _configService.DownloadClientWorkingFolders.Split('|'))
|
||||||
|
{
|
||||||
|
if (Directory.GetParent(localEpisode.Path).Name.StartsWith(workingFolder))
|
||||||
|
{
|
||||||
|
if (_diskProvider.GetLastFileWrite(localEpisode.Path) > DateTime.UtcNow.AddMinutes(-5))
|
||||||
|
{
|
||||||
|
_logger.Trace("{0} appears to be unpacking still", localEpisode.Path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -229,6 +229,7 @@
|
||||||
<Compile Include="MediaFiles\EpisodeImport\IImportDecisionEngineSpecification.cs" />
|
<Compile Include="MediaFiles\EpisodeImport\IImportDecisionEngineSpecification.cs" />
|
||||||
<Compile Include="MediaFiles\EpisodeImport\ImportDecisionMaker.cs" />
|
<Compile Include="MediaFiles\EpisodeImport\ImportDecisionMaker.cs" />
|
||||||
<Compile Include="MediaFiles\EpisodeImport\ImportApprovedEpisodes.cs" />
|
<Compile Include="MediaFiles\EpisodeImport\ImportApprovedEpisodes.cs" />
|
||||||
|
<Compile Include="MediaFiles\EpisodeImport\Specifications\NotUnpackingSpecification.cs" />
|
||||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\NotInUseSpecification.cs" />
|
<Compile Include="MediaFiles\EpisodeImport\Specifications\NotInUseSpecification.cs" />
|
||||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\FreeSpaceSpecification.cs" />
|
<Compile Include="MediaFiles\EpisodeImport\Specifications\FreeSpaceSpecification.cs" />
|
||||||
<Compile Include="MediaFiles\EpisodeImport\Specifications\UpgradeSpecification.cs" />
|
<Compile Include="MediaFiles\EpisodeImport\Specifications\UpgradeSpecification.cs" />
|
||||||
|
|
|
@ -249,7 +249,7 @@ namespace NzbDrone.Core.Parser
|
||||||
var result = new QualityModel { Quality = Quality.Unknown };
|
var result = new QualityModel { Quality = Quality.Unknown };
|
||||||
result.Proper = (normalizedName.Contains("proper") || normalizedName.Contains("repack"));
|
result.Proper = (normalizedName.Contains("proper") || normalizedName.Contains("repack"));
|
||||||
|
|
||||||
if (normalizedName.Contains("dvd") || normalizedName.Contains("bdrip") || normalizedName.Contains("brrip"))
|
if ((normalizedName.Contains("dvd") && !normalizedName.Contains("avcdvd")) || normalizedName.Contains("bdrip") || normalizedName.Contains("brrip"))
|
||||||
{
|
{
|
||||||
result.Quality = Quality.DVD;
|
result.Quality = Quality.DVD;
|
||||||
return result;
|
return result;
|
||||||
|
@ -325,8 +325,8 @@ namespace NzbDrone.Core.Parser
|
||||||
result.Quality = Quality.HDTV720p;
|
result.Quality = Quality.HDTV720p;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
//Based on extension
|
|
||||||
|
|
||||||
|
//Based on extension
|
||||||
if (result.Quality == Quality.Unknown && !name.ContainsInvalidPathChars())
|
if (result.Quality == Quality.Unknown && !name.ContainsInvalidPathChars())
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
|
|
@ -5,8 +5,8 @@ define(
|
||||||
'marionette',
|
'marionette',
|
||||||
'AddSeries/Collection',
|
'AddSeries/Collection',
|
||||||
'AddSeries/SearchResultCollectionView',
|
'AddSeries/SearchResultCollectionView',
|
||||||
'Shared/SpinnerView'
|
'Shared/LoadingView'
|
||||||
], function (App, Marionette, AddSeriesCollection, SearchResultCollectionView, SpinnerView) {
|
], function (App, Marionette, AddSeriesCollection, SearchResultCollectionView, LoadingView) {
|
||||||
return Marionette.Layout.extend({
|
return Marionette.Layout.extend({
|
||||||
template: 'AddSeries/AddSeriesTemplate',
|
template: 'AddSeries/AddSeriesTemplate',
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ define(
|
||||||
this.searchResult.close();
|
this.searchResult.close();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
this.searchResult.show(new SpinnerView());
|
this.searchResult.show(new LoadingView());
|
||||||
this.currentSearchPromise = this.collection.fetch({
|
this.currentSearchPromise = this.collection.fetch({
|
||||||
data: { term: options.term }
|
data: { term: options.term }
|
||||||
}).done(function () {
|
}).done(function () {
|
||||||
|
|
|
@ -6,11 +6,12 @@ define(
|
||||||
'Episode/Search/ButtonsView',
|
'Episode/Search/ButtonsView',
|
||||||
'Episode/Search/ManualLayout',
|
'Episode/Search/ManualLayout',
|
||||||
'Release/Collection',
|
'Release/Collection',
|
||||||
|
'Series/SeriesCollection',
|
||||||
'Shared/LoadingView',
|
'Shared/LoadingView',
|
||||||
'Shared/Messenger',
|
'Shared/Messenger',
|
||||||
'Commands/CommandController',
|
'Commands/CommandController',
|
||||||
'Shared/FormatHelpers'
|
'Shared/FormatHelpers'
|
||||||
], function (App, Marionette, ButtonsView, ManualSearchLayout, ReleaseCollection, LoadingView, Messenger, CommandController, FormatHelpers) {
|
], function (App, Marionette, ButtonsView, ManualSearchLayout, ReleaseCollection, SeriesCollection, LoadingView, Messenger, CommandController, FormatHelpers) {
|
||||||
|
|
||||||
return Marionette.Layout.extend({
|
return Marionette.Layout.extend({
|
||||||
template: 'Episode/Search/LayoutTemplate',
|
template: 'Episode/Search/LayoutTemplate',
|
||||||
|
@ -40,7 +41,8 @@ define(
|
||||||
|
|
||||||
CommandController.Execute('episodeSearch', { episodeId: this.model.get('id') });
|
CommandController.Execute('episodeSearch', { episodeId: this.model.get('id') });
|
||||||
|
|
||||||
var seriesTitle = this.model.get('series').get('title');
|
var series = SeriesCollection.get(this.model.get('seriesId'));
|
||||||
|
var seriesTitle = series.get('title');
|
||||||
var season = this.model.get('seasonNumber');
|
var season = this.model.get('seasonNumber');
|
||||||
var episode = this.model.get('episodeNumber');
|
var episode = this.model.get('episodeNumber');
|
||||||
var message = seriesTitle + ' - ' + season + 'x' + FormatHelpers.pad(episode, 2);
|
var message = seriesTitle + ' - ' + season + 'x' + FormatHelpers.pad(episode, 2);
|
||||||
|
|
|
@ -55,7 +55,7 @@ define(
|
||||||
this.activity.show(new Backgrid.Grid({
|
this.activity.show(new Backgrid.Grid({
|
||||||
collection: new Backbone.Collection(episodeFile),
|
collection: new Backbone.Collection(episodeFile),
|
||||||
columns : this.columns,
|
columns : this.columns,
|
||||||
className : 'table table-bordered'
|
className : 'table table-bordered'spinn
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -156,7 +156,7 @@ define(
|
||||||
},
|
},
|
||||||
element : this.ui.rename,
|
element : this.ui.rename,
|
||||||
context : this,
|
context : this,
|
||||||
onSuccess : this._showSeasons,
|
onSuccess : this._refetchEpisodeFiles,
|
||||||
failMessage: 'Series search failed'
|
failMessage: 'Series search failed'
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -209,6 +209,10 @@ define(
|
||||||
|
|
||||||
_showInfo: function () {
|
_showInfo: function () {
|
||||||
this.info.show(new InfoView({ model: this.model }));
|
this.info.show(new InfoView({ model: this.model }));
|
||||||
|
},
|
||||||
|
|
||||||
|
_refetchEpisodeFiles: function () {
|
||||||
|
this.episodeFileCollection.fetch();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue